[#287] Support proxy for frostfsid and policy contracts

Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
Denis Kirillov 2023-12-21 17:57:12 +03:00
parent 3b6d2bc522
commit 899213b3f3
7 changed files with 71 additions and 8 deletions

View file

@ -21,6 +21,7 @@ This document outlines major changes between releases.
- Add `namespace` label to billing metrics (#271) - Add `namespace` label to billing metrics (#271)
- Support policy-engine (#257) - Support policy-engine (#257)
- Support `policy` contract (#259) - Support `policy` contract (#259)
- Support `proxy` contract (#287)
### Changed ### Changed
- Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221) - Generalise config param `use_default_xmlns_for_complete_multipart` to `use_default_xmlns` so that use default xmlns for all requests (#221)

View file

@ -438,9 +438,10 @@ func (a *App) initMetrics() {
func (a *App) initFrostfsID(ctx context.Context) { func (a *App) initFrostfsID(ctx context.Context) {
var err error var err error
a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{ a.frostfsid, err = frostfsid.New(ctx, frostfsid.Config{
RPCAddress: a.cfg.GetString(cfgRPCEndpoint), RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
Contract: a.cfg.GetString(cfgFrostfsIDContract), Contract: a.cfg.GetString(cfgFrostfsIDContract),
Key: a.key, ProxyContract: a.cfg.GetString(cfgProxyContract),
Key: a.key,
}) })
if err != nil { if err != nil {
a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err)) a.log.Fatal(logs.InitFrostfsIDContractFailed, zap.Error(err))
@ -455,9 +456,10 @@ func (a *App) initPolicyStorage(ctx context.Context) {
if a.cfg.GetBool(cfgPolicyEnabled) { if a.cfg.GetBool(cfgPolicyEnabled) {
policyContract, err = contract.New(ctx, contract.Config{ policyContract, err = contract.New(ctx, contract.Config{
RPCAddress: a.cfg.GetString(cfgRPCEndpoint), RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
Contract: a.cfg.GetString(cfgPolicyContract), Contract: a.cfg.GetString(cfgPolicyContract),
Key: a.key, ProxyContract: a.cfg.GetString(cfgProxyContract),
Key: a.key,
}) })
if err != nil { if err != nil {
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err)) a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err))

View file

@ -213,6 +213,9 @@ const ( // Settings.
cfgPolicyEnabled = "policy.enabled" cfgPolicyEnabled = "policy.enabled"
cfgPolicyContract = "policy.contract" cfgPolicyContract = "policy.contract"
// Proxy.
cfgProxyContract = "proxy.contract"
// envPrefix is an environment variables prefix used for configuration. // envPrefix is an environment variables prefix used for configuration.
envPrefix = "S3_GW" envPrefix = "S3_GW"
) )
@ -702,6 +705,9 @@ func newSettings() *viper.Viper {
v.SetDefault(cfgPolicyContract, "policy.frostfs") v.SetDefault(cfgPolicyContract, "policy.frostfs")
v.SetDefault(cfgPolicyEnabled, true) v.SetDefault(cfgPolicyEnabled, true)
// proxy
v.SetDefault(cfgProxyContract, "proxy.frostfs")
// resolve // resolve
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader) v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)

View file

@ -204,6 +204,10 @@ S3_GW_POLICY_ENABLED=true
# Policy contract hash (LE) or name in NNS. # Policy contract hash (LE) or name in NNS.
S3_GW_POLICY_CONTRACT=policy.frostfs S3_GW_POLICY_CONTRACT=policy.frostfs
# Proxy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
# Proxy contract hash (LE) or name in NNS.
S3_GW_PROXY_CONTRACT=proxy.frostfs
# Namespaces configuration # Namespaces configuration
S3_GW_NAMESPACES_CONFIG=namespaces.json S3_GW_NAMESPACES_CONFIG=namespaces.json

View file

@ -241,5 +241,10 @@ policy:
# Policy contract hash (LE) or name in NNS. # Policy contract hash (LE) or name in NNS.
contract: policy.frostfs contract: policy.frostfs
# Proxy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
proxy:
# Proxy contract hash (LE) or name in NNS.
contract: proxy.frostfs
namespaces: namespaces:
config: namespaces.json config: namespaces.json

View file

@ -191,6 +191,7 @@ There are some custom types used for brevity:
| `web` | [Web server configuration](#web-section) | | `web` | [Web server configuration](#web-section) |
| `frostfsid` | [FrostfsID configuration](#frostfsid-section) | | `frostfsid` | [FrostfsID configuration](#frostfsid-section) |
| `policy` | [Policy contract configuration](#policy-section) | | `policy` | [Policy contract configuration](#policy-section) |
| `proxy` | [Proxy contract configuration](#proxy-section) |
| `namespaces` | [Namespaces configuration](#namespaces-section) | | `namespaces` | [Namespaces configuration](#namespaces-section) |
### General section ### General section
@ -662,6 +663,19 @@ policy:
| `enabled` | `bool` | no | true | Enables using policies from Policy contract to check permissions. | | `enabled` | `bool` | no | true | Enables using policies from Policy contract to check permissions. |
| `contract` | `string` | no | policy.frostfs | Policy contract hash (LE) or name in NNS. | | `contract` | `string` | no | policy.frostfs | Policy contract hash (LE) or name in NNS. |
# `proxy` section
Proxy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
```yaml
proxy:
contract: proxy.frostfs
```
| Parameter | Type | SIGHUP reload | Default value | Description |
|------------|----------|---------------|-----------------|------------------------------------------|
| `contract` | `string` | no | `proxy.frostfs` | Proxy contract hash (LE) or name in NNS. |
# `namespaces` section # `namespaces` section
Namespaces configuration. Namespaces configuration.

View file

@ -9,9 +9,11 @@ import (
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy" policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy" "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util" frostfsutil "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
"github.com/nspcc-dev/neo-go/pkg/core/transaction"
"github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/crypto/keys"
"github.com/nspcc-dev/neo-go/pkg/rpcclient" "github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor" "github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/notary"
"github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet" "github.com/nspcc-dev/neo-go/pkg/wallet"
) )
@ -28,6 +30,9 @@ type Config struct {
// Contract is hash of contract or its name in NNS. // Contract is hash of contract or its name in NNS.
Contract string Contract string
// ProxyContract is hash of proxy contract or its name in NNS to interact with policy.
ProxyContract string
// Key is used to interact with policy contract. // Key is used to interact with policy contract.
// If this is nil than random key will be generated. // If this is nil than random key will be generated.
Key *keys.PrivateKey Key *keys.PrivateKey
@ -54,8 +59,12 @@ func New(ctx context.Context, cfg Config) (*Client, error) {
return nil, fmt.Errorf("create policy rpc client: %w", err) return nil, fmt.Errorf("create policy rpc client: %w", err)
} }
acc := wallet.NewAccountFromPrivateKey(key) proxyContractHash, err := frostfsutil.ResolveContractHash(cfg.ProxyContract, cfg.RPCAddress)
act, err := actor.NewSimple(rpcCli, acc) if err != nil {
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
}
act, err := actor.New(rpcCli, getSigners(key, proxyContractHash, contractHash))
if err != nil { if err != nil {
return nil, fmt.Errorf("create new actor: %w", err) return nil, fmt.Errorf("create new actor: %w", err)
} }
@ -66,6 +75,28 @@ func New(ctx context.Context, cfg Config) (*Client, error) {
}, nil }, nil
} }
func getSigners(key *keys.PrivateKey, proxyHash, contractHash util.Uint160) []actor.SignerAccount {
acc := wallet.NewAccountFromPrivateKey(key)
return []actor.SignerAccount{
{
Signer: transaction.Signer{
Account: proxyHash,
Scopes: transaction.CustomContracts,
AllowedContracts: []util.Uint160{contractHash},
},
Account: notary.FakeContractAccount(proxyHash),
},
{
Signer: transaction.Signer{
Account: acc.Contract.ScriptHash(),
Scopes: transaction.CalledByEntry,
},
Account: acc,
},
}
}
func (c *Client) AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error) { func (c *Client) AddChain(kind policycontract.Kind, entity string, name []byte, chain []byte) (util.Uint256, uint32, error) {
return c.policyContract.AddChain(big.NewInt(int64(kind)), entity, name, chain) return c.policyContract.AddChain(big.NewInt(int64(kind)), entity, name, chain)
} }