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 <selenepinillos@gmail.com>
This commit is contained in:
Tania B 2021-11-04 19:25:01 +02:00 committed by GitHub
parent 9f205cf1d7
commit e81d434edf
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 81 additions and 2 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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) {}

View File

@ -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
}

View File

@ -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)
})
}

View File

@ -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)