From e81d434edff6a7a44a1ad9ad5d74be37429fe0ec Mon Sep 17 00:00:00 2001 From: Tania B Date: Thu, 4 Nov 2021 19:25:01 +0200 Subject: [PATCH] Encryption: Extend secrets service to support registering key providers (#40626) * Draft adding kms providers * Rename defaultProvider to currentProvider * Add getting current provider from config * Remove comments * Make current provider service struct field * Add methods to secrets service * Test getting current provider * Implements missing methods for fake secrets service * Remove accidental changes * Fix linter issue * Update configuration examples * Rename CurrentProvider method * Split service interface * Update wire Co-authored-by: spinillos --- conf/defaults.ini | 3 ++ conf/sample.ini | 3 ++ pkg/server/wire.go | 1 + pkg/services/secrets/fakes/fake_service.go | 10 +++++ pkg/services/secrets/manager/manager.go | 15 ++++++- pkg/services/secrets/manager/manager_test.go | 45 +++++++++++++++++++- pkg/services/secrets/secrets.go | 6 +++ 7 files changed, 81 insertions(+), 2 deletions(-) diff --git a/conf/defaults.ini b/conf/defaults.ini index d2cb5fc0437..a9b1b285971 100644 --- a/conf/defaults.ini +++ b/conf/defaults.ini @@ -228,6 +228,9 @@ admin_password = admin # used for signing secret_key = SW2YcwTIb9zpOOhoPsMm +# key provider used for envelope encryption, default to static value specified by secret_key +encryption_provider = secretKey + # disable gravatar profile images disable_gravatar = false diff --git a/conf/sample.ini b/conf/sample.ini index d6666163af7..dd2b3f72c05 100644 --- a/conf/sample.ini +++ b/conf/sample.ini @@ -222,6 +222,9 @@ # used for signing ;secret_key = SW2YcwTIb9zpOOhoPsMm +# key provider used for envelope encryption, default to static value specified by secret_key +;encryption_provider = secretKey + # disable gravatar profile images ;disable_gravatar = false diff --git a/pkg/server/wire.go b/pkg/server/wire.go index 7ef39447763..cef774bc4e1 100644 --- a/pkg/server/wire.go +++ b/pkg/server/wire.go @@ -156,6 +156,7 @@ var wireBasicSet = wire.NewSet( elasticsearch.ProvideService, secretsManager.ProvideSecretsService, wire.Bind(new(secrets.Service), new(*secretsManager.SecretsService)), + wire.Bind(new(secrets.ProvidersRegistrar), new(*secretsManager.SecretsService)), secretsDatabase.ProvideSecretsStore, wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)), grafanads.ProvideService, diff --git a/pkg/services/secrets/fakes/fake_service.go b/pkg/services/secrets/fakes/fake_service.go index 43f480da682..b743c3af7ec 100644 --- a/pkg/services/secrets/fakes/fake_service.go +++ b/pkg/services/secrets/fakes/fake_service.go @@ -39,3 +39,13 @@ func (f FakeSecretsService) GetDecryptedValue(_ context.Context, sjd map[string] } return fallback } + +func (f FakeSecretsService) CurrentProviderID() string { + return "fakeProvider" +} + +func (f FakeSecretsService) GetProviders() map[string]secrets.Provider { + return make(map[string]secrets.Provider) +} + +func (f FakeSecretsService) RegisterProvider(_ string, _ secrets.Provider) {} diff --git a/pkg/services/secrets/manager/manager.go b/pkg/services/secrets/manager/manager.go index acb86d69421..3027031a79d 100644 --- a/pkg/services/secrets/manager/manager.go +++ b/pkg/services/secrets/manager/manager.go @@ -36,14 +36,15 @@ func ProvideSecretsService(store secrets.Store, bus bus.Bus, enc encryption.Serv providers := map[string]secrets.Provider{ defaultProvider: grafana.New(settings, enc), } + currentProvider := settings.KeyValue("security", "encryption_provider").MustString(defaultProvider) s := &SecretsService{ store: store, bus: bus, enc: enc, settings: settings, - currentProvider: defaultProvider, providers: providers, + currentProvider: currentProvider, dataKeyCache: make(map[string]dataKeyCacheItem), } @@ -257,3 +258,15 @@ func (s *SecretsService) dataKey(ctx context.Context, name string) ([]byte, erro return decrypted, nil } + +func (s *SecretsService) RegisterProvider(providerID string, provider secrets.Provider) { + s.providers[providerID] = provider +} + +func (s *SecretsService) CurrentProviderID() string { + return s.currentProvider +} + +func (s *SecretsService) GetProviders() map[string]secrets.Provider { + return s.providers +} diff --git a/pkg/services/secrets/manager/manager_test.go b/pkg/services/secrets/manager/manager_test.go index b3bca2b7ede..6c600eee25f 100644 --- a/pkg/services/secrets/manager/manager_test.go +++ b/pkg/services/secrets/manager/manager_test.go @@ -4,15 +4,19 @@ import ( "context" "testing" + "github.com/grafana/grafana/pkg/bus" + "github.com/grafana/grafana/pkg/services/encryption/ossencryption" "github.com/grafana/grafana/pkg/services/secrets" "github.com/grafana/grafana/pkg/services/secrets/database" "github.com/grafana/grafana/pkg/services/sqlstore" + "github.com/grafana/grafana/pkg/setting" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "gopkg.in/ini.v1" ) -func TestSecrets_EnvelopeEncryption(t *testing.T) { +func TestSecretsService_EnvelopeEncryption(t *testing.T) { store := database.ProvideSecretsStore(sqlstore.InitTestDB(t)) svc := SetupTestService(t, store) ctx := context.Background() @@ -141,3 +145,42 @@ func TestSecretsService_DataKeys(t *testing.T) { assert.Nil(t, res) }) } + +func TestSecretsService_GetCurrentProvider(t *testing.T) { + t.Run("When encryption_provider is not specified explicitly, should use 'secretKey' as a current provider", func(t *testing.T) { + cfg := `[security] + secret_key = sdDkslslld` + + raw, err := ini.Load([]byte(cfg)) + require.NoError(t, err) + settings := &setting.OSSImpl{Cfg: &setting.Cfg{Raw: raw}} + + svc := ProvideSecretsService( + database.ProvideSecretsStore(sqlstore.InitTestDB(t)), + bus.New(), + ossencryption.ProvideService(), + settings, + ) + + assert.Equal(t, "secretKey", svc.currentProvider) + }) + + t.Run("When encryption_provider value is set, should use it as a current provider", func(t *testing.T) { + cfg := `[security] + secret_key = sdDkslslld + encryption_provider = awskms.second_key` + + raw, err := ini.Load([]byte(cfg)) + require.NoError(t, err) + settings := &setting.OSSImpl{Cfg: &setting.Cfg{Raw: raw}} + + svc := ProvideSecretsService( + database.ProvideSecretsStore(sqlstore.InitTestDB(t)), + bus.New(), + ossencryption.ProvideService(), + settings, + ) + + assert.Equal(t, "awskms.second_key", svc.currentProvider) + }) +} diff --git a/pkg/services/secrets/secrets.go b/pkg/services/secrets/secrets.go index 08090897ae8..cb034ccc5c4 100644 --- a/pkg/services/secrets/secrets.go +++ b/pkg/services/secrets/secrets.go @@ -16,6 +16,12 @@ type Service interface { GetDecryptedValue(ctx context.Context, sjd map[string][]byte, key, fallback string) string } +type ProvidersRegistrar interface { + CurrentProviderID() string + GetProviders() map[string]Provider + RegisterProvider(providerID string, provider Provider) +} + // Store defines methods to interact with secrets storage type Store interface { GetDataKey(ctx context.Context, name string) (*DataKey, error)