From 71889234b772297fbc5b016d1d6ec384b6ae8d21 Mon Sep 17 00:00:00 2001 From: Anton Nikiforov Date: Fri, 23 Jun 2023 11:25:08 +0300 Subject: [PATCH] [#449] tree: Allow reading requests signed by keys from allow list Signed-off-by: Anton Nikiforov --- cmd/frostfs-node/config/tree/config.go | 21 +++++++++++++++++++++ cmd/frostfs-node/tree.go | 1 + pkg/services/tree/options.go | 12 ++++++++++++ pkg/services/tree/signature.go | 15 +++++++++++++++ 4 files changed, 49 insertions(+) diff --git a/cmd/frostfs-node/config/tree/config.go b/cmd/frostfs-node/config/tree/config.go index f6087c53d3..8a8919999f 100644 --- a/cmd/frostfs-node/config/tree/config.go +++ b/cmd/frostfs-node/config/tree/config.go @@ -1,9 +1,11 @@ package treeconfig import ( + "fmt" "time" "git.frostfs.info/TrueCloudLab/frostfs-node/cmd/frostfs-node/config" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" ) const ( @@ -71,3 +73,22 @@ func (c TreeConfig) ReplicationWorkerCount() int { func (c TreeConfig) SyncInterval() time.Duration { return config.DurationSafe(c.cfg, "sync_interval") } + +// AuthorizedKeys parses and returns an array of "authorized_keys" config +// parameter from "tree" section. +// +// Returns an empty list if not set. +func (c TreeConfig) AuthorizedKeys() keys.PublicKeys { + authorizedKeysStr := config.StringSliceSafe(c.cfg, "authorized_keys") + authorizedKeys := make(keys.PublicKeys, 0, len(authorizedKeysStr)) + + for i := range authorizedKeysStr { + pub, err := keys.NewPublicKeyFromString(authorizedKeysStr[i]) + if err != nil { + panic(fmt.Errorf("could not parse Tree authorized key %s: %w", authorizedKeysStr[i], err)) + } + + authorizedKeys = append(authorizedKeys, pub) + } + return authorizedKeys +} diff --git a/cmd/frostfs-node/tree.go b/cmd/frostfs-node/tree.go index fffaa01d19..1f73b7956a 100644 --- a/cmd/frostfs-node/tree.go +++ b/cmd/frostfs-node/tree.go @@ -56,6 +56,7 @@ func initTreeService(c *cfg) { tree.WithReplicationTimeout(treeConfig.ReplicationTimeout()), tree.WithReplicationChannelCapacity(treeConfig.ReplicationChannelCapacity()), tree.WithReplicationWorkerCount(treeConfig.ReplicationWorkerCount()), + tree.WithAuthorizedKeys(treeConfig.AuthorizedKeys()), tree.WithMetrics(c.metricsCollector.TreeService())) for _, srv := range c.cfgGRPC.servers { diff --git a/pkg/services/tree/options.go b/pkg/services/tree/options.go index bcaf21f92d..a6e23c6257 100644 --- a/pkg/services/tree/options.go +++ b/pkg/services/tree/options.go @@ -33,6 +33,7 @@ type cfg struct { replicatorWorkerCount int replicatorTimeout time.Duration containerCacheSize int + authorizedKeys [][]byte metrics MetricsRegister } @@ -124,3 +125,14 @@ func WithMetrics(v MetricsRegister) Option { c.metrics = v } } + +// WithAuthorizedKeys returns option to add list of public +// keys that have rights to use Tree service. +func WithAuthorizedKeys(keys keys.PublicKeys) Option { + return func(c *cfg) { + c.authorizedKeys = nil + for _, key := range keys { + c.authorizedKeys = append(c.authorizedKeys, key.Bytes()) + } + } +} diff --git a/pkg/services/tree/signature.go b/pkg/services/tree/signature.go index 4399129698..976fc8d070 100644 --- a/pkg/services/tree/signature.go +++ b/pkg/services/tree/signature.go @@ -51,6 +51,21 @@ func (s *Service) verifyClient(req message, cid cidSDK.ID, rawBearer []byte, op if err != nil { return err } + if op == acl.OpObjectGet { + // verify if the request for a client operation + // was signed by a key from authorized list. + // Operation must be one of READ. + sign := req.GetSignature() + if sign == nil { + return errors.New("missing signature") + } + var key = sign.GetKey() + for i := range s.authorizedKeys { + if bytes.Equal(s.authorizedKeys[i], key) { + return nil + } + } + } cnr, err := s.cnrSource.Get(cid) if err != nil {