From 8a4ac7b6db055c1e49010ceed2e6385b589ddd4d Mon Sep 17 00:00:00 2001 From: Michael Mandrus Date: Tue, 24 May 2022 14:22:11 -0400 Subject: [PATCH] update kvstore provider to check if we should use the grpc plugin. return false always in OSS --- pkg/server/wire.go | 1 + pkg/services/secrets/kvstore/kvstore.go | 13 +- pkg/services/secrets/kvstore/remote_plugin.go | 123 ++++++++++++++++++ .../secrets/kvstore/remote_plugin_check.go | 7 + 4 files changed, 142 insertions(+), 2 deletions(-) create mode 100644 pkg/services/secrets/kvstore/remote_plugin.go create mode 100644 pkg/services/secrets/kvstore/remote_plugin_check.go diff --git a/pkg/server/wire.go b/pkg/server/wire.go index f3b2db696bd..548bab4ff65 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -145,6 +145,7 @@ var wireBasicSet = wire.NewSet( wire.Bind(new(plugins.DashboardFileStore), new(*manager.PluginManager)), wire.Bind(new(plugins.StaticRouteResolver), new(*manager.PluginManager)), wire.Bind(new(plugins.RendererManager), new(*manager.PluginManager)), + wire.Bind(new(plugins.SecretsManagerManager), new(*manager.PluginManager)), coreplugin.ProvideCoreRegistry, loader.ProvideService, wire.Bind(new(plugins.Loader), new(*loader.Loader)), diff --git a/pkg/services/secrets/kvstore/kvstore.go b/pkg/services/secrets/kvstore/kvstore.go index b438aec3c41..a0fe9474e88 100644 --- a/pkg/services/secrets/kvstore/kvstore.go +++ b/pkg/services/secrets/kvstore/kvstore.go @@ -4,6 +4,7 @@ import ( "context" "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/sqlstore" ) @@ -13,11 +14,19 @@ const ( AllOrganizations = -1 ) -func ProvideService(sqlStore sqlstore.Store, secretsService secrets.Service) SecretsKVStore { +func ProvideService(sqlStore sqlstore.Store, secretsService secrets.Service, sm plugins.SecretsManagerManager) SecretsKVStore { + logger := log.New("secrets.kvstore") + if shouldUseRemoteSecretsPlugin(&sm) { + return &secretsKVStorePlugin{ + secretsPlugin: sm.SecretsManager().SecretsManager, + secretsService: secretsService, + log: logger, + } + } return &secretsKVStoreSQL{ sqlStore: sqlStore, secretsService: secretsService, - log: log.New("secrets.kvstore"), + log: logger, decryptionCache: decryptionCache{ cache: make(map[int64]cachedDecrypted), }, diff --git a/pkg/services/secrets/kvstore/remote_plugin.go b/pkg/services/secrets/kvstore/remote_plugin.go new file mode 100644 index 00000000000..12555d4b4d6 --- /dev/null +++ b/pkg/services/secrets/kvstore/remote_plugin.go @@ -0,0 +1,123 @@ +package kvstore + +import ( + "context" + "fmt" + + "github.com/grafana/grafana/pkg/infra/log" + "github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin" + smp "github.com/grafana/grafana/pkg/plugins/backendplugin/secretsmanagerplugin" + "github.com/grafana/grafana/pkg/services/secrets" +) + +// secretsKVStorePlugin provides a key/value store backed by the Grafana plugin gRPC interface +type secretsKVStorePlugin struct { + log log.Logger + secretsPlugin secretsmanagerplugin.SecretsManagerPlugin + secretsService secrets.Service +} + +// Get an item from the store +func (kv *secretsKVStorePlugin) Get(ctx context.Context, orgId int64, namespace string, typ string) (string, bool, error) { + req := &smp.SecretsGetRequest{ + KeyDescriptor: &smp.Key{ + OrgId: orgId, + Namespace: namespace, + Type: typ, + }, + } + + res, err := kv.secretsPlugin.Get(ctx, req) + if err == nil && res.Error != "" { + err = fmt.Errorf(res.Error) + } + + return res.DecryptedValue, res.Exists, err +} + +// Set an item in the store +func (kv *secretsKVStorePlugin) Set(ctx context.Context, orgId int64, namespace string, typ string, value string) error { + req := &smp.SecretsSetRequest{ + KeyDescriptor: &smp.Key{ + OrgId: orgId, + Namespace: namespace, + Type: typ, + }, + Value: value, + } + + res, err := kv.secretsPlugin.Set(ctx, req) + if err == nil && res.Error != "" { + err = fmt.Errorf(res.Error) + } + + return err +} + +// Del deletes an item from the store. +func (kv *secretsKVStorePlugin) Del(ctx context.Context, orgId int64, namespace string, typ string) error { + req := &smp.SecretsDelRequest{ + KeyDescriptor: &smp.Key{ + OrgId: orgId, + Namespace: namespace, + Type: typ, + }, + } + + res, err := kv.secretsPlugin.Del(ctx, req) + if err == nil && res.Error != "" { + err = fmt.Errorf(res.Error) + } + + return err +} + +// Keys get all keys for a given namespace. To query for all +// organizations the constant 'kvstore.AllOrganizations' can be passed as orgId. +func (kv *secretsKVStorePlugin) Keys(ctx context.Context, orgId int64, namespace string, typ string) ([]Key, error) { + req := &smp.SecretsKeysRequest{ + KeyDescriptor: &smp.Key{ + OrgId: orgId, + Namespace: namespace, + Type: typ, + }, + AllOrganizations: orgId == AllOrganizations, + } + + res, err := kv.secretsPlugin.Keys(ctx, req) + if err == nil && res.Error != "" { + err = fmt.Errorf(res.Error) + } + + return parseKeys(res.Keys), err +} + +// Rename an item in the store +func (kv *secretsKVStorePlugin) Rename(ctx context.Context, orgId int64, namespace string, typ string, newNamespace string) error { + req := &smp.SecretsRenameRequest{ + KeyDescriptor: &smp.Key{ + OrgId: orgId, + Namespace: namespace, + Type: typ, + }, + NewNamespace: newNamespace, + } + + res, err := kv.secretsPlugin.Rename(ctx, req) + if err == nil && res.Error != "" { + err = fmt.Errorf(res.Error) + } + + return err +} + +func parseKeys(keys []*secretsmanagerplugin.Key) []Key { + var newKeys []Key + + for _, k := range keys { + newKey := Key{OrgId: k.OrgId, Namespace: k.Namespace, Type: k.Type} + newKeys = append(newKeys, newKey) + } + + return newKeys +} diff --git a/pkg/services/secrets/kvstore/remote_plugin_check.go b/pkg/services/secrets/kvstore/remote_plugin_check.go new file mode 100644 index 00000000000..5568840d146 --- /dev/null +++ b/pkg/services/secrets/kvstore/remote_plugin_check.go @@ -0,0 +1,7 @@ +package kvstore + +import "github.com/grafana/grafana/pkg/plugins" + +func shouldUseRemoteSecretsPlugin(sm *plugins.SecretsManagerManager) bool { + return false +}