forked from TrueCloudLab/frostfs-s3-gw
[#259] Support contract based policies
Signed-off-by: Denis Kirillov <d.kirillov@yadro.com>
This commit is contained in:
parent
be6a37ada5
commit
9272f4e108
18 changed files with 428 additions and 43 deletions
|
@ -20,6 +20,7 @@ This document outlines major changes between releases.
|
||||||
- Support control api to manage policies. See `control` config section (#258)
|
- Support control api to manage policies. See `control` config section (#258)
|
||||||
- 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)
|
||||||
|
|
||||||
### 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)
|
||||||
|
|
72
api/cache/policy.go
vendored
Normal file
72
api/cache/policy.go
vendored
Normal file
|
@ -0,0 +1,72 @@
|
||||||
|
package cache
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"github.com/bluele/gcache"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MorphPolicyCache provides lru cache for listing policies stored in policy contract.
|
||||||
|
type MorphPolicyCache struct {
|
||||||
|
cache gcache.Cache
|
||||||
|
logger *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type MorphPolicyCacheKey struct {
|
||||||
|
Target engine.Target
|
||||||
|
Name chain.Name
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
// DefaultMorphPolicyCacheSize is a default maximum number of entries in cache.
|
||||||
|
DefaultMorphPolicyCacheSize = 1e4
|
||||||
|
// DefaultMorphPolicyCacheLifetime is a default lifetime of entries in cache.
|
||||||
|
DefaultMorphPolicyCacheLifetime = time.Minute
|
||||||
|
)
|
||||||
|
|
||||||
|
// DefaultMorphPolicyConfig returns new default cache expiration values.
|
||||||
|
func DefaultMorphPolicyConfig(logger *zap.Logger) *Config {
|
||||||
|
return &Config{
|
||||||
|
Size: DefaultMorphPolicyCacheSize,
|
||||||
|
Lifetime: DefaultMorphPolicyCacheLifetime,
|
||||||
|
Logger: logger,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewMorphPolicyCache creates an object of MorphPolicyCache.
|
||||||
|
func NewMorphPolicyCache(config *Config) *MorphPolicyCache {
|
||||||
|
gc := gcache.New(config.Size).LRU().Expiration(config.Lifetime).Build()
|
||||||
|
return &MorphPolicyCache{cache: gc, logger: config.Logger}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get returns a cached object. Returns nil if value is missing.
|
||||||
|
func (o *MorphPolicyCache) Get(key MorphPolicyCacheKey) []*chain.Chain {
|
||||||
|
entry, err := o.cache.Get(key)
|
||||||
|
if err != nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
result, ok := entry.([]*chain.Chain)
|
||||||
|
if !ok {
|
||||||
|
o.logger.Warn(logs.InvalidCacheEntryType, zap.String("actual", fmt.Sprintf("%T", entry)),
|
||||||
|
zap.String("expected", fmt.Sprintf("%T", result)))
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
// Put puts an object to cache.
|
||||||
|
func (o *MorphPolicyCache) Put(key MorphPolicyCacheKey, list []*chain.Chain) error {
|
||||||
|
return o.cache.Set(key, list)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete deletes an object from cache.
|
||||||
|
func (o *MorphPolicyCache) Delete(key MorphPolicyCacheKey) bool {
|
||||||
|
return o.cache.Remove(key)
|
||||||
|
}
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apiErr "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
@ -51,7 +52,7 @@ func policyCheck(storage engine.ChainRouter, settings PolicySettings, domains []
|
||||||
|
|
||||||
reqInfo := GetReqInfo(r.Context())
|
reqInfo := GetReqInfo(r.Context())
|
||||||
target := engine.NewRequestTargetWithNamespace(settings.ResolveNamespaceAlias(reqInfo.Namespace))
|
target := engine.NewRequestTargetWithNamespace(settings.ResolveNamespaceAlias(reqInfo.Namespace))
|
||||||
st, found, err := storage.IsAllowed(chain.Ingress, target, req)
|
st, found, err := storage.IsAllowed(policy.S3ChainName, target, req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ import (
|
||||||
|
|
||||||
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
apiErrors "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/errors"
|
||||||
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
s3middleware "git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/metrics"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
@ -164,7 +165,7 @@ func TestPolicyChecker(t *testing.T) {
|
||||||
}},
|
}},
|
||||||
}
|
}
|
||||||
|
|
||||||
err := chiRouter.cfg.PolicyStorage.MorphRuleChainStorage().AddMorphRuleChain(chain.Ingress, engine.NamespaceTarget(namespace), ruleChain)
|
err := chiRouter.cfg.PolicyStorage.MorphRuleChainStorage().AddMorphRuleChain(policy.S3ChainName, engine.NamespaceTarget(namespace), ruleChain)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// check we can access 'bucket' in default namespace
|
// check we can access 'bucket' in default namespace
|
||||||
|
|
|
@ -30,6 +30,8 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/resolver"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/resolver"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/frostfsid"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy/contract"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/services"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/version"
|
||||||
|
@ -144,6 +146,7 @@ func newApp(ctx context.Context, log *Logger, v *viper.Viper) *App {
|
||||||
func (a *App) init(ctx context.Context) {
|
func (a *App) init(ctx context.Context) {
|
||||||
a.setRuntimeParameters()
|
a.setRuntimeParameters()
|
||||||
a.initAPI(ctx)
|
a.initAPI(ctx)
|
||||||
|
a.initPolicyStorage(ctx)
|
||||||
a.initControlAPI()
|
a.initControlAPI()
|
||||||
a.initMetrics()
|
a.initMetrics()
|
||||||
a.initFrostfsID(ctx)
|
a.initFrostfsID(ctx)
|
||||||
|
@ -271,10 +274,10 @@ func (s *appSettings) DefaultPlacementPolicy(namespace string) netmap.PlacementP
|
||||||
|
|
||||||
func (s *appSettings) PlacementPolicy(namespace, constraint string) (netmap.PlacementPolicy, bool) {
|
func (s *appSettings) PlacementPolicy(namespace, constraint string) (netmap.PlacementPolicy, bool) {
|
||||||
s.mu.RLock()
|
s.mu.RLock()
|
||||||
policy, ok := s.namespaces[namespace].LocationConstraints[constraint]
|
placementPolicy, ok := s.namespaces[namespace].LocationConstraints[constraint]
|
||||||
s.mu.RUnlock()
|
s.mu.RUnlock()
|
||||||
|
|
||||||
return policy, ok
|
return placementPolicy, ok
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *appSettings) CopiesNumbers(namespace, constraint string) ([]uint32, bool) {
|
func (s *appSettings) CopiesNumbers(namespace, constraint string) ([]uint32, bool) {
|
||||||
|
@ -417,12 +420,10 @@ func (a *App) initAPI(ctx context.Context) {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) initControlAPI() {
|
func (a *App) initControlAPI() {
|
||||||
a.policyStorage = inmemory.NewInMemoryLocalOverrides()
|
|
||||||
|
|
||||||
svc := controlSvc.New(
|
svc := controlSvc.New(
|
||||||
controlSvc.WithSettings(a.settings),
|
controlSvc.WithSettings(a.settings),
|
||||||
controlSvc.WithLogger(a.log),
|
controlSvc.WithLogger(a.log),
|
||||||
controlSvc.WithChainStorage(a.policyStorage),
|
controlSvc.WithChainStorage(a.policyStorage.LocalStorage()),
|
||||||
)
|
)
|
||||||
|
|
||||||
a.controlAPI = grpc.NewServer()
|
a.controlAPI = grpc.NewServer()
|
||||||
|
@ -451,6 +452,30 @@ func (a *App) initFrostfsID(ctx context.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (a *App) initPolicyStorage(ctx context.Context) {
|
||||||
|
if !a.cfg.GetBool(cfgPolicyEnabled) {
|
||||||
|
a.policyStorage = inmemory.NewInMemoryLocalOverrides()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
policyClient, err := contract.New(ctx, contract.Config{
|
||||||
|
RPCAddress: a.cfg.GetString(cfgRPCEndpoint),
|
||||||
|
Contract: a.cfg.GetString(cfgPolicyContract),
|
||||||
|
Key: a.key,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
a.log.Fatal(logs.InitPolicyContractFailed, zap.Error(err))
|
||||||
|
}
|
||||||
|
|
||||||
|
cachedMorph := policy.NewCachedMorph(policy.CachedMorphConfig{
|
||||||
|
Morph: policyClient,
|
||||||
|
Cache: cache.NewMorphPolicyCache(getMorphPolicyCacheConfig(a.cfg, a.log)),
|
||||||
|
Log: a.log,
|
||||||
|
})
|
||||||
|
|
||||||
|
a.policyStorage = policy.NewStorage(cachedMorph)
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) initResolver() {
|
func (a *App) initResolver() {
|
||||||
var err error
|
var err error
|
||||||
a.bucketResolver, err = resolver.NewBucketResolver(a.getResolverOrder(), a.getResolverConfig())
|
a.bucketResolver, err = resolver.NewBucketResolver(a.getResolverOrder(), a.getResolverConfig())
|
||||||
|
@ -919,6 +944,15 @@ func getAccessBoxCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
return cacheCfg
|
return cacheCfg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func getMorphPolicyCacheConfig(v *viper.Viper, l *zap.Logger) *cache.Config {
|
||||||
|
cacheCfg := cache.DefaultMorphPolicyConfig(l)
|
||||||
|
|
||||||
|
cacheCfg.Lifetime = fetchCacheLifetime(v, l, cfgMorphPolicyCacheLifetime, cacheCfg.Lifetime)
|
||||||
|
cacheCfg.Size = fetchCacheSize(v, l, cfgMorphPolicyCacheSize, cacheCfg.Size)
|
||||||
|
|
||||||
|
return cacheCfg
|
||||||
|
}
|
||||||
|
|
||||||
func (a *App) initHandler() {
|
func (a *App) initHandler() {
|
||||||
var err error
|
var err error
|
||||||
a.api, err = handler.New(a.log, a.obj, a.nc, a.settings)
|
a.api, err = handler.New(a.log, a.obj, a.nc, a.settings)
|
||||||
|
|
|
@ -108,6 +108,8 @@ const ( // Settings.
|
||||||
cfgAccessBoxCacheSize = "cache.accessbox.size"
|
cfgAccessBoxCacheSize = "cache.accessbox.size"
|
||||||
cfgAccessControlCacheLifetime = "cache.accesscontrol.lifetime"
|
cfgAccessControlCacheLifetime = "cache.accesscontrol.lifetime"
|
||||||
cfgAccessControlCacheSize = "cache.accesscontrol.size"
|
cfgAccessControlCacheSize = "cache.accesscontrol.size"
|
||||||
|
cfgMorphPolicyCacheLifetime = "cache.morph_policy.lifetime"
|
||||||
|
cfgMorphPolicyCacheSize = "cache.morph_policy.size"
|
||||||
|
|
||||||
// NATS.
|
// NATS.
|
||||||
cfgEnableNATS = "nats.enabled"
|
cfgEnableNATS = "nats.enabled"
|
||||||
|
@ -207,6 +209,10 @@ const ( // Settings.
|
||||||
cfgFrostfsIDEnabled = "frostfsid.enabled"
|
cfgFrostfsIDEnabled = "frostfsid.enabled"
|
||||||
cfgFrostfsIDContract = "frostfsid.contract"
|
cfgFrostfsIDContract = "frostfsid.contract"
|
||||||
|
|
||||||
|
// Policy.
|
||||||
|
cfgPolicyEnabled = "policy.enabled"
|
||||||
|
cfgPolicyContract = "policy.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"
|
||||||
)
|
)
|
||||||
|
@ -689,6 +695,10 @@ func newSettings() *viper.Viper {
|
||||||
v.SetDefault(cfgFrostfsIDContract, "frostfsid.frostfs")
|
v.SetDefault(cfgFrostfsIDContract, "frostfsid.frostfs")
|
||||||
v.SetDefault(cfgFrostfsIDEnabled, true)
|
v.SetDefault(cfgFrostfsIDEnabled, true)
|
||||||
|
|
||||||
|
// policy
|
||||||
|
v.SetDefault(cfgPolicyContract, "policy.frostfs")
|
||||||
|
v.SetDefault(cfgPolicyEnabled, true)
|
||||||
|
|
||||||
// resolve
|
// resolve
|
||||||
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
v.SetDefault(cfgResolveNamespaceHeader, defaultNamespaceHeader)
|
||||||
|
|
||||||
|
|
|
@ -97,6 +97,9 @@ S3_GW_CACHE_ACCESSBOX_SIZE=100
|
||||||
# Cache which stores owner to cache operation mapping
|
# Cache which stores owner to cache operation mapping
|
||||||
S3_GW_CACHE_ACCESSCONTROL_LIFETIME=1m
|
S3_GW_CACHE_ACCESSCONTROL_LIFETIME=1m
|
||||||
S3_GW_CACHE_ACCESSCONTROL_SIZE=100000
|
S3_GW_CACHE_ACCESSCONTROL_SIZE=100000
|
||||||
|
# Cache which stores list of policy chains
|
||||||
|
S3_GW_CACHE_MORPH_POLICY_LIFETIME=1m
|
||||||
|
S3_GW_CACHE_MORPH_POLICY_SIZE=10000
|
||||||
|
|
||||||
# NATS
|
# NATS
|
||||||
S3_GW_NATS_ENABLED=true
|
S3_GW_NATS_ENABLED=true
|
||||||
|
@ -195,6 +198,12 @@ S3_GW_FROSTFSID_ENABLED=true
|
||||||
# FrostfsID contract hash (LE) or name in NNS.
|
# FrostfsID contract hash (LE) or name in NNS.
|
||||||
S3_GW_FROSTFSID_CONTRACT=frostfsid.frostfs
|
S3_GW_FROSTFSID_CONTRACT=frostfsid.frostfs
|
||||||
|
|
||||||
|
# Policy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
|
||||||
|
# Enables using policies from Policy contract.
|
||||||
|
S3_GW_POLICY_ENABLED=true
|
||||||
|
# Policy contract hash (LE) or name in NNS.
|
||||||
|
S3_GW_POLICY_CONTRACT=policy.frostfs
|
||||||
|
|
||||||
# Namespaces configuration
|
# Namespaces configuration
|
||||||
S3_GW_NAMESPACES_CONFIG=namespaces.json
|
S3_GW_NAMESPACES_CONFIG=namespaces.json
|
||||||
|
|
||||||
|
|
|
@ -120,6 +120,10 @@ cache:
|
||||||
accesscontrol:
|
accesscontrol:
|
||||||
lifetime: 1m
|
lifetime: 1m
|
||||||
size: 100000
|
size: 100000
|
||||||
|
# Cache which stores list of policy chains
|
||||||
|
morph_policy:
|
||||||
|
lifetime: 1m
|
||||||
|
size: 10000
|
||||||
|
|
||||||
nats:
|
nats:
|
||||||
enabled: true
|
enabled: true
|
||||||
|
@ -229,5 +233,12 @@ frostfsid:
|
||||||
# FrostfsID contract hash (LE) or name in NNS.
|
# FrostfsID contract hash (LE) or name in NNS.
|
||||||
contract: frostfsid.frostfs
|
contract: frostfsid.frostfs
|
||||||
|
|
||||||
|
# Policy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
|
||||||
|
policy:
|
||||||
|
# Enables using policies from Policy contract.
|
||||||
|
enabled: true
|
||||||
|
# Policy contract hash (LE) or name in NNS.
|
||||||
|
contract: policy.frostfs
|
||||||
|
|
||||||
namespaces:
|
namespaces:
|
||||||
config: namespaces.json
|
config: namespaces.json
|
||||||
|
|
|
@ -190,6 +190,7 @@ There are some custom types used for brevity:
|
||||||
| `features` | [Features configuration](#features-section) |
|
| `features` | [Features configuration](#features-section) |
|
||||||
| `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) |
|
||||||
| `namespaces` | [Namespaces configuration](#namespaces-section) |
|
| `namespaces` | [Namespaces configuration](#namespaces-section) |
|
||||||
|
|
||||||
### General section
|
### General section
|
||||||
|
@ -409,6 +410,9 @@ cache:
|
||||||
accesscontrol:
|
accesscontrol:
|
||||||
lifetime: 1m
|
lifetime: 1m
|
||||||
size: 100000
|
size: 100000
|
||||||
|
morph_policy:
|
||||||
|
lifetime: 30s
|
||||||
|
size: 10000
|
||||||
```
|
```
|
||||||
|
|
||||||
| Parameter | Type | Default value | Description |
|
| Parameter | Type | Default value | Description |
|
||||||
|
@ -420,6 +424,7 @@ cache:
|
||||||
| `system` | [Cache config](#cache-subsection) | `lifetime: 5m`<br>`size: 10000` | Cache for system objects in a bucket: bucket settings, notification configuration etc. |
|
| `system` | [Cache config](#cache-subsection) | `lifetime: 5m`<br>`size: 10000` | Cache for system objects in a bucket: bucket settings, notification configuration etc. |
|
||||||
| `accessbox` | [Cache config](#cache-subsection) | `lifetime: 10m`<br>`size: 100` | Cache which stores access box with tokens by its address. |
|
| `accessbox` | [Cache config](#cache-subsection) | `lifetime: 10m`<br>`size: 100` | Cache which stores access box with tokens by its address. |
|
||||||
| `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 100000` | Cache which stores owner to cache operation mapping. |
|
| `accesscontrol` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 100000` | Cache which stores owner to cache operation mapping. |
|
||||||
|
| `morph_policy` | [Cache config](#cache-subsection) | `lifetime: 1m`<br>`size: 10000` | Cache which stores list of policy chains. |
|
||||||
|
|
||||||
#### `cache` subsection
|
#### `cache` subsection
|
||||||
|
|
||||||
|
@ -641,6 +646,21 @@ frostfsid:
|
||||||
| `enabled` | `bool` | no | true | Enables check that allow requests only users that is registered in FrostfsID contract. |
|
| `enabled` | `bool` | no | true | Enables check that allow requests only users that is registered in FrostfsID contract. |
|
||||||
| `contract` | `string` | no | frostfsid.frostfs | FrostfsID contract hash (LE) or name in NNS. |
|
| `contract` | `string` | no | frostfsid.frostfs | FrostfsID contract hash (LE) or name in NNS. |
|
||||||
|
|
||||||
|
# `policy` section
|
||||||
|
|
||||||
|
Policy contract configuration. To enable this functionality the `rpc_endpoint` param must be also set.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
policy:
|
||||||
|
enabled: false
|
||||||
|
contract: policy.frostfs
|
||||||
|
```
|
||||||
|
|
||||||
|
| Parameter | Type | SIGHUP reload | Default value | Description |
|
||||||
|
|------------|----------|---------------|----------------|-------------------------------------------------------------------|
|
||||||
|
| `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. |
|
||||||
|
|
||||||
# `namespaces` section
|
# `namespaces` section
|
||||||
|
|
||||||
Namespaces configuration.
|
Namespaces configuration.
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -4,7 +4,7 @@ go 1.20
|
||||||
|
|
||||||
require (
|
require (
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231109143925-dd5919348da9
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939
|
git.frostfs.info/TrueCloudLab/frostfs-sdk-go v0.0.0-20231107114540-ab75edd70939
|
||||||
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20231205092054-2d4a9fc6dcb3
|
git.frostfs.info/TrueCloudLab/policy-engine v0.0.0-20231205092054-2d4a9fc6dcb3
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -38,8 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4 h1:wjLfZ3WCt7qNGsQv+Jl0TXnmtg0uVk/jToKPFTBc/jo=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4 h1:wjLfZ3WCt7qNGsQv+Jl0TXnmtg0uVk/jToKPFTBc/jo=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
|
git.frostfs.info/TrueCloudLab/frostfs-api-go/v2 v2.16.1-0.20231121085847-241a9f1ad0a4/go.mod h1:uY0AYmCznjZdghDnAk7THFIe1Vlg531IxUcus7ZfUJI=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231109143925-dd5919348da9 h1:o14uxW6CLyweCdptexXn0ox0zGegdXc8lx8XauJ+b24=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958 h1:X9yPizADIhD3K/gdKVCthlAnf9aQ3UJJGnZgIwwixRQ=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231109143925-dd5919348da9/go.mod h1:rQWdsG18NaiFvkJpMguJev913KD/yleHaniRBkUyt0o=
|
git.frostfs.info/TrueCloudLab/frostfs-contract v0.18.1-0.20231129062201-a1b61d394958/go.mod h1:rQWdsG18NaiFvkJpMguJev913KD/yleHaniRBkUyt0o=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0 h1:FxqFDhQYYgpe41qsIHVOcdzSVCB8JNSfPG7Uk4r2oSk=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
git.frostfs.info/TrueCloudLab/frostfs-crypto v0.6.0/go.mod h1:RUIKZATQLJ+TaYQa60X2fTDwfuhMfm8Ar60bQ5fr+vU=
|
||||||
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
|
git.frostfs.info/TrueCloudLab/frostfs-observability v0.0.0-20230531082742-c97d21411eb6 h1:aGQ6QaAnTerQ5Dq5b2/f9DUQtSqPkZZ/bkMx/HKuLCo=
|
||||||
|
|
|
@ -8,11 +8,9 @@ import (
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
"git.frostfs.info/TrueCloudLab/frostfs-contract/frostfsid/client"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/middleware"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/authmate"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
|
|
||||||
"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/util"
|
|
||||||
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -39,7 +37,7 @@ var (
|
||||||
|
|
||||||
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
// New creates new FrostfsID contract wrapper that implements auth.FrostFSID interface.
|
||||||
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
func New(ctx context.Context, cfg Config) (*FrostFSID, error) {
|
||||||
contractHash, err := fetchContractHash(cfg)
|
contractHash, err := util.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
}
|
}
|
||||||
|
@ -79,25 +77,3 @@ func (f *FrostFSID) RegisterPublicKey(key *keys.PublicKey) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func fetchContractHash(cfg Config) (util.Uint160, error) {
|
|
||||||
if hash, err := util.Uint160DecodeStringLE(cfg.Contract); err == nil {
|
|
||||||
return hash, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
splitName := strings.Split(cfg.Contract, ".")
|
|
||||||
if len(splitName) != 2 {
|
|
||||||
return util.Uint160{}, fmt.Errorf("invalid contract name: '%s'", cfg.Contract)
|
|
||||||
}
|
|
||||||
|
|
||||||
var domain container.Domain
|
|
||||||
domain.SetName(splitName[0])
|
|
||||||
domain.SetZone(splitName[1])
|
|
||||||
|
|
||||||
var nns ns.NNS
|
|
||||||
if err := nns.Dial(cfg.RPCAddress); err != nil {
|
|
||||||
return util.Uint160{}, fmt.Errorf("dial nns %s: %w", cfg.RPCAddress, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nns.ResolveContractHash(domain)
|
|
||||||
}
|
|
||||||
|
|
60
internal/frostfs/policy/cached_morph.go
Normal file
60
internal/frostfs/policy/cached_morph.go
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/api/cache"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"go.uber.org/zap"
|
||||||
|
)
|
||||||
|
|
||||||
|
type CachedMorph struct {
|
||||||
|
morph engine.MorphRuleChainStorage
|
||||||
|
cache *cache.MorphPolicyCache
|
||||||
|
log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
type CachedMorphConfig struct {
|
||||||
|
Morph engine.MorphRuleChainStorage
|
||||||
|
Cache *cache.MorphPolicyCache
|
||||||
|
Log *zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ engine.MorphRuleChainStorage = (*CachedMorph)(nil)
|
||||||
|
|
||||||
|
func NewCachedMorph(config CachedMorphConfig) *CachedMorph {
|
||||||
|
return &CachedMorph{
|
||||||
|
morph: config.Morph,
|
||||||
|
cache: config.Cache,
|
||||||
|
log: config.Log,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedMorph) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) error {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
||||||
|
return c.morph.AddMorphRuleChain(name, target, policyChain)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedMorph) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) error {
|
||||||
|
c.cache.Delete(cache.MorphPolicyCacheKey{Target: target, Name: name})
|
||||||
|
return c.morph.RemoveMorphRuleChain(name, target, chainID)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *CachedMorph) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
key := cache.MorphPolicyCacheKey{Target: target, Name: name}
|
||||||
|
list := c.cache.Get(key)
|
||||||
|
if list != nil {
|
||||||
|
return list, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
list, err := c.morph.ListMorphRuleChains(name, target)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err = c.cache.Put(key, list); err != nil {
|
||||||
|
c.log.Warn(logs.CouldntCacheListPolicyChains)
|
||||||
|
}
|
||||||
|
|
||||||
|
return list, nil
|
||||||
|
}
|
112
internal/frostfs/policy/contract/contract.go
Normal file
112
internal/frostfs/policy/contract/contract.go
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
package contract
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"math/big"
|
||||||
|
|
||||||
|
policycontract "git.frostfs.info/TrueCloudLab/frostfs-contract/policy"
|
||||||
|
policyclient "git.frostfs.info/TrueCloudLab/frostfs-contract/rpcclient/policy"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/util"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"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/actor"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/wallet"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
actor *actor.Actor
|
||||||
|
policyContract *policyclient.Contract
|
||||||
|
}
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
// RPCAddress is an endpoint to connect to neo rpc.
|
||||||
|
RPCAddress string
|
||||||
|
|
||||||
|
// Contract is hash of contract or its name in NNS.
|
||||||
|
Contract string
|
||||||
|
|
||||||
|
// Key is used to interact with policy contract.
|
||||||
|
// If this is nil than random key will be generated.
|
||||||
|
Key *keys.PrivateKey
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ engine.MorphRuleChainStorage = (*Client)(nil)
|
||||||
|
|
||||||
|
// New creates new Policy contract wrapper.
|
||||||
|
func New(ctx context.Context, cfg Config) (*Client, error) {
|
||||||
|
contractHash, err := util.ResolveContractHash(cfg.Contract, cfg.RPCAddress)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("resolve frostfs contract hash: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
key := cfg.Key
|
||||||
|
if key == nil {
|
||||||
|
if key, err = keys.NewPrivateKey(); err != nil {
|
||||||
|
return nil, fmt.Errorf("generate anon private key for policy: %w", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rpcCli, err := rpcclient.New(ctx, cfg.RPCAddress, rpcclient.Options{})
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create policy rpc client: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
acc := wallet.NewAccountFromPrivateKey(key)
|
||||||
|
act, err := actor.NewSimple(rpcCli, acc)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("create new actor: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Client{
|
||||||
|
actor: act,
|
||||||
|
policyContract: policyclient.New(act, contractHash),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) AddMorphRuleChain(name chain.Name, target engine.Target, policyChain *chain.Chain) error {
|
||||||
|
chainName := append([]byte(name), []byte(policyChain.ID)...)
|
||||||
|
_, err := c.actor.Wait(c.policyContract.AddChain(getKind(target), target.Name, chainName, policyChain.Bytes()))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) RemoveMorphRuleChain(name chain.Name, target engine.Target, chainID chain.ID) error {
|
||||||
|
chainName := append([]byte(name), []byte(chainID)...)
|
||||||
|
_, err := c.actor.Wait(c.policyContract.RemoveChain(getKind(target), target.Name, chainName))
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListMorphRuleChains(name chain.Name, target engine.Target) ([]*chain.Chain, error) {
|
||||||
|
items, err := c.policyContract.ListChainsByPrefix(getKind(target), target.Name, []byte(name))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res := make([]*chain.Chain, len(items))
|
||||||
|
for i, item := range items {
|
||||||
|
data, err := item.TryBytes()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var policyChain chain.Chain
|
||||||
|
if err = policyChain.DecodeBytes(data); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
res[i] = &policyChain
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func getKind(target engine.Target) *big.Int {
|
||||||
|
var kind int64 = policycontract.Container
|
||||||
|
if target.Type != engine.Container {
|
||||||
|
kind = policycontract.Namespace
|
||||||
|
}
|
||||||
|
|
||||||
|
return big.NewInt(kind)
|
||||||
|
}
|
42
internal/frostfs/policy/storage.go
Normal file
42
internal/frostfs/policy/storage.go
Normal file
|
@ -0,0 +1,42 @@
|
||||||
|
package policy
|
||||||
|
|
||||||
|
import (
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/chain"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/engine/inmemory"
|
||||||
|
"git.frostfs.info/TrueCloudLab/policy-engine/pkg/resource"
|
||||||
|
)
|
||||||
|
|
||||||
|
const S3ChainName chain.Name = "s3"
|
||||||
|
|
||||||
|
type Storage struct {
|
||||||
|
router engine.ChainRouter
|
||||||
|
|
||||||
|
morph engine.MorphRuleChainStorage
|
||||||
|
|
||||||
|
local engine.LocalOverrideStorage
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ engine.LocalOverrideEngine = (*Storage)(nil)
|
||||||
|
|
||||||
|
func NewStorage(morph engine.MorphRuleChainStorage) *Storage {
|
||||||
|
local := inmemory.NewInmemoryLocalStorage()
|
||||||
|
|
||||||
|
return &Storage{
|
||||||
|
router: engine.NewDefaultChainRouterWithLocalOverrides(morph, local),
|
||||||
|
morph: morph,
|
||||||
|
local: local,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Storage) IsAllowed(name chain.Name, target engine.RequestTarget, r resource.Request) (status chain.Status, found bool, err error) {
|
||||||
|
return s.router.IsAllowed(name, target, r)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Storage) MorphRuleChainStorage() engine.MorphRuleChainStorage {
|
||||||
|
return s.morph
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s Storage) LocalStorage() engine.LocalOverrideStorage {
|
||||||
|
return s.local
|
||||||
|
}
|
33
internal/frostfs/util/util.go
Normal file
33
internal/frostfs/util/util.go
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
package util
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/container"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-sdk-go/ns"
|
||||||
|
"github.com/nspcc-dev/neo-go/pkg/util"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ResolveContractHash determine contract hash by resolving NNS name.
|
||||||
|
func ResolveContractHash(contractHash, rpcAddress string) (util.Uint160, error) {
|
||||||
|
if hash, err := util.Uint160DecodeStringLE(contractHash); err == nil {
|
||||||
|
return hash, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
splitName := strings.Split(contractHash, ".")
|
||||||
|
if len(splitName) != 2 {
|
||||||
|
return util.Uint160{}, fmt.Errorf("invalid contract name: '%s'", contractHash)
|
||||||
|
}
|
||||||
|
|
||||||
|
var domain container.Domain
|
||||||
|
domain.SetName(splitName[0])
|
||||||
|
domain.SetZone(splitName[1])
|
||||||
|
|
||||||
|
var nns ns.NNS
|
||||||
|
if err := nns.Dial(rpcAddress); err != nil {
|
||||||
|
return util.Uint160{}, fmt.Errorf("dial nns %s: %w", rpcAddress, err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return nns.ResolveContractHash(domain)
|
||||||
|
}
|
|
@ -99,6 +99,7 @@ const (
|
||||||
CouldntCacheBucketSettings = "couldn't cache bucket settings" // Warn in ../../api/layer/cache.go
|
CouldntCacheBucketSettings = "couldn't cache bucket settings" // Warn in ../../api/layer/cache.go
|
||||||
CouldntCacheCors = "couldn't cache cors" // Warn in ../../api/layer/cache.go
|
CouldntCacheCors = "couldn't cache cors" // Warn in ../../api/layer/cache.go
|
||||||
CouldntCacheNotificationConfiguration = "couldn't cache notification configuration" // Warn in ../../api/layer/cache.go
|
CouldntCacheNotificationConfiguration = "couldn't cache notification configuration" // Warn in ../../api/layer/cache.go
|
||||||
|
CouldntCacheListPolicyChains = "couldn't cache list policy chains" // Warn in ../../api/layer/cache.go
|
||||||
RequestEnd = "request end" // Info in ../../api/middleware/response.go
|
RequestEnd = "request end" // Info in ../../api/middleware/response.go
|
||||||
CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed = "couldn't receive access box for gate key, random key will be used" // Debug in ../../api/middleware/auth.go
|
CouldntReceiveAccessBoxForGateKeyRandomKeyWillBeUsed = "couldn't receive access box for gate key, random key will be used" // Debug in ../../api/middleware/auth.go
|
||||||
FailedToPassAuthentication = "failed to pass authentication" // Error in ../../api/middleware/auth.go
|
FailedToPassAuthentication = "failed to pass authentication" // Error in ../../api/middleware/auth.go
|
||||||
|
@ -128,6 +129,7 @@ const (
|
||||||
AnonRequestSkipFrostfsIDValidation = "anon request, skip FrostfsID validation" // Debug in ../../api/middleware/auth.go
|
AnonRequestSkipFrostfsIDValidation = "anon request, skip FrostfsID validation" // Debug in ../../api/middleware/auth.go
|
||||||
FrostfsIDValidationFailed = "FrostfsID validation failed" // Error in ../../api/middleware/auth.go
|
FrostfsIDValidationFailed = "FrostfsID validation failed" // Error in ../../api/middleware/auth.go
|
||||||
InitFrostfsIDContractFailed = "init frostfsid contract failed" // Fatal in ../../cmd/s3-gw/app.go
|
InitFrostfsIDContractFailed = "init frostfsid contract failed" // Fatal in ../../cmd/s3-gw/app.go
|
||||||
|
InitPolicyContractFailed = "init policy contract failed" // Fatal in ../../cmd/s3-gw/app.go
|
||||||
ControlAPIHealthcheck = "healthcheck request"
|
ControlAPIHealthcheck = "healthcheck request"
|
||||||
ControlAPIPutPolicies = "put policies request"
|
ControlAPIPutPolicies = "put policies request"
|
||||||
ControlAPIRemovePolicies = "remove policies request"
|
ControlAPIRemovePolicies = "remove policies request"
|
||||||
|
|
|
@ -9,6 +9,7 @@ import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
"git.frostfs.info/TrueCloudLab/frostfs-api-go/v2/refs"
|
||||||
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/frostfs/policy"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/internal/logs"
|
||||||
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"
|
"git.frostfs.info/TrueCloudLab/frostfs-s3-gw/pkg/service/control"
|
||||||
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
frostfscrypto "git.frostfs.info/TrueCloudLab/frostfs-sdk-go/crypto"
|
||||||
|
@ -43,14 +44,14 @@ type cfg struct {
|
||||||
|
|
||||||
settings Settings
|
settings Settings
|
||||||
|
|
||||||
chainStorage engine.LocalOverrideEngine
|
chainStorage engine.LocalOverrideStorage
|
||||||
}
|
}
|
||||||
|
|
||||||
func defaultCfg() *cfg {
|
func defaultCfg() *cfg {
|
||||||
return &cfg{
|
return &cfg{
|
||||||
log: zap.NewNop(),
|
log: zap.NewNop(),
|
||||||
settings: defaultSettings{},
|
settings: defaultSettings{},
|
||||||
chainStorage: inmemory.NewInMemoryLocalOverrides(),
|
chainStorage: inmemory.NewInmemoryLocalStorage(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -84,7 +85,7 @@ func WithLogger(log *zap.Logger) Option {
|
||||||
}
|
}
|
||||||
|
|
||||||
// WithChainStorage returns option to set logger.
|
// WithChainStorage returns option to set logger.
|
||||||
func WithChainStorage(chainStorage engine.LocalOverrideEngine) Option {
|
func WithChainStorage(chainStorage engine.LocalOverrideStorage) Option {
|
||||||
return func(c *cfg) {
|
return func(c *cfg) {
|
||||||
c.chainStorage = chainStorage
|
c.chainStorage = chainStorage
|
||||||
}
|
}
|
||||||
|
@ -141,7 +142,7 @@ func (s *Server) putPolicy(data *control.PutPoliciesRequest_ChainData) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(data.GetNamespace())
|
ns := s.settings.ResolveNamespaceAlias(data.GetNamespace())
|
||||||
if _, err := s.chainStorage.LocalStorage().AddOverride(chain.Ingress, engine.NamespaceTarget(ns), &overrideChain); err != nil {
|
if _, err := s.chainStorage.AddOverride(policy.S3ChainName, engine.NamespaceTarget(ns), &overrideChain); err != nil {
|
||||||
return status.Error(codes.Internal, err.Error())
|
return status.Error(codes.Internal, err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +171,7 @@ func (s *Server) RemovePolicies(_ context.Context, req *control.RemovePoliciesRe
|
||||||
|
|
||||||
func (s *Server) removePolicy(info *control.RemovePoliciesRequest_ChainInfo) error {
|
func (s *Server) removePolicy(info *control.RemovePoliciesRequest_ChainInfo) error {
|
||||||
ns := s.settings.ResolveNamespaceAlias(info.GetNamespace())
|
ns := s.settings.ResolveNamespaceAlias(info.GetNamespace())
|
||||||
err := s.chainStorage.LocalStorage().RemoveOverride(chain.Ingress, engine.NamespaceTarget(ns), chain.ID(info.GetChainID()))
|
err := s.chainStorage.RemoveOverride(policy.S3ChainName, engine.NamespaceTarget(ns), chain.ID(info.GetChainID()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if isNotFoundError(err) {
|
if isNotFoundError(err) {
|
||||||
return status.Error(codes.NotFound, err.Error())
|
return status.Error(codes.NotFound, err.Error())
|
||||||
|
@ -193,7 +194,7 @@ func (s *Server) GetPolicy(_ context.Context, req *control.GetPolicyRequest) (*c
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
||||||
overrideChain, err := s.chainStorage.LocalStorage().GetOverride(chain.Ingress, engine.NamespaceTarget(ns), chain.ID(req.GetBody().GetChainID()))
|
overrideChain, err := s.chainStorage.GetOverride(policy.S3ChainName, engine.NamespaceTarget(ns), chain.ID(req.GetBody().GetChainID()))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
@ -214,7 +215,7 @@ func (s *Server) ListPolicies(_ context.Context, req *control.ListPoliciesReques
|
||||||
}
|
}
|
||||||
|
|
||||||
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
ns := s.settings.ResolveNamespaceAlias(req.GetBody().GetNamespace())
|
||||||
chains, err := s.chainStorage.LocalStorage().ListOverrides(chain.Ingress, engine.NamespaceTarget(ns))
|
chains, err := s.chainStorage.ListOverrides(policy.S3ChainName, engine.NamespaceTarget(ns))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, status.Error(codes.InvalidArgument, err.Error())
|
return nil, status.Error(codes.InvalidArgument, err.Error())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue