mirror of
https://github.com/grafana/grafana.git
synced 2026-08-18 17:15:08 -05:00
Encryption: Refactor secrets service (#41771)
* Refactor kmsproviders pkg * Update tests * Fix linting Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com>
This commit is contained in:
co-authored by
Joan López de la Franca Beltran
parent
b8dd9fdd4a
commit
bc60ae3c66
@@ -3,7 +3,8 @@ package manager
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
@@ -24,15 +25,19 @@ func SetupTestService(tb testing.TB, store secrets.Store) *SecretsService {
|
||||
secret_key = ` + defaultKey))
|
||||
require.NoError(tb, err)
|
||||
cfg := &setting.Cfg{Raw: raw}
|
||||
cfg.FeatureToggles = map[string]bool{envelopeEncryptionFeatureToggle: true}
|
||||
cfg.FeatureToggles = map[string]bool{secrets.EnvelopeEncryptionFeatureToggle: true}
|
||||
|
||||
settings := &setting.OSSImpl{Cfg: cfg}
|
||||
assert.True(tb, settings.IsFeatureToggleEnabled(envelopeEncryptionFeatureToggle))
|
||||
assert.True(tb, settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle))
|
||||
|
||||
return ProvideSecretsService(
|
||||
encryption := ossencryption.ProvideService()
|
||||
secretsService, err := ProvideSecretsService(
|
||||
store,
|
||||
bus.New(),
|
||||
ossencryption.ProvideService(),
|
||||
osskmsproviders.ProvideService(encryption, settings),
|
||||
encryption,
|
||||
settings,
|
||||
)
|
||||
require.NoError(tb, err)
|
||||
|
||||
return secretsService
|
||||
}
|
||||
|
||||
@@ -9,22 +9,15 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/services/encryption"
|
||||
"github.com/grafana/grafana/pkg/services/kmsproviders"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
grafana "github.com/grafana/grafana/pkg/services/secrets/defaultprovider"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
const (
|
||||
defaultProvider = "secretKey"
|
||||
envelopeEncryptionFeatureToggle = "envelopeEncryption"
|
||||
)
|
||||
|
||||
type SecretsService struct {
|
||||
store secrets.Store
|
||||
bus bus.Bus
|
||||
enc encryption.Internal
|
||||
settings setting.Provider
|
||||
|
||||
@@ -33,15 +26,21 @@ type SecretsService struct {
|
||||
dataKeyCache map[string]dataKeyCacheItem
|
||||
}
|
||||
|
||||
func ProvideSecretsService(store secrets.Store, bus bus.Bus, enc encryption.Internal, settings setting.Provider) *SecretsService {
|
||||
providers := map[string]secrets.Provider{
|
||||
defaultProvider: grafana.New(settings, enc),
|
||||
func ProvideSecretsService(
|
||||
store secrets.Store,
|
||||
kmsProvidersService kmsproviders.Service,
|
||||
enc encryption.Internal,
|
||||
settings setting.Provider,
|
||||
) (*SecretsService, error) {
|
||||
providers, err := kmsProvidersService.Provide()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
currentProvider := settings.KeyValue("security", "encryption_provider").MustString(defaultProvider)
|
||||
|
||||
currentProvider := settings.KeyValue("security", "encryption_provider").MustString(kmsproviders.Default)
|
||||
|
||||
s := &SecretsService{
|
||||
store: store,
|
||||
bus: bus,
|
||||
enc: enc,
|
||||
settings: settings,
|
||||
providers: providers,
|
||||
@@ -49,7 +48,7 @@ func ProvideSecretsService(store secrets.Store, bus bus.Bus, enc encryption.Inte
|
||||
dataKeyCache: make(map[string]dataKeyCacheItem),
|
||||
}
|
||||
|
||||
return s
|
||||
return s, nil
|
||||
}
|
||||
|
||||
type dataKeyCacheItem struct {
|
||||
@@ -65,11 +64,11 @@ func (s *SecretsService) Encrypt(ctx context.Context, payload []byte, opt secret
|
||||
|
||||
func (s *SecretsService) EncryptWithDBSession(ctx context.Context, payload []byte, opt secrets.EncryptionOptions, sess *xorm.Session) ([]byte, error) {
|
||||
// Use legacy encryption service if envelopeEncryptionFeatureToggle toggle is off
|
||||
if !s.settings.IsFeatureToggleEnabled(envelopeEncryptionFeatureToggle) {
|
||||
if !s.settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle) {
|
||||
return s.enc.Encrypt(ctx, payload, setting.SecretKey)
|
||||
}
|
||||
|
||||
// If encryption envelopeEncryptionFeatureToggle toggle is on, use envelope encryption
|
||||
// If encryption secrets.EnvelopeEncryptionFeatureToggle toggle is on, use envelope encryption
|
||||
scope := opt()
|
||||
keyName := fmt.Sprintf("%s/%s@%s", time.Now().Format("2006-01-02"), scope, s.currentProvider)
|
||||
|
||||
@@ -103,12 +102,12 @@ func (s *SecretsService) EncryptWithDBSession(ctx context.Context, payload []byt
|
||||
}
|
||||
|
||||
func (s *SecretsService) Decrypt(ctx context.Context, payload []byte) ([]byte, error) {
|
||||
// Use legacy encryption service if envelopeEncryptionFeatureToggle toggle is off
|
||||
if !s.settings.IsFeatureToggleEnabled(envelopeEncryptionFeatureToggle) {
|
||||
// Use legacy encryption service if secrets.EnvelopeEncryptionFeatureToggle toggle is off
|
||||
if !s.settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle) {
|
||||
return s.enc.Decrypt(ctx, payload, setting.SecretKey)
|
||||
}
|
||||
|
||||
// If encryption envelopeEncryptionFeatureToggle toggle is on, use envelope encryption
|
||||
// If encryption secrets.EnvelopeEncryptionFeatureToggle toggle is on, use envelope encryption
|
||||
if len(payload) == 0 {
|
||||
return nil, fmt.Errorf("unable to decrypt empty payload")
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/bus"
|
||||
"github.com/grafana/grafana/pkg/services/encryption/ossencryption"
|
||||
"github.com/grafana/grafana/pkg/services/kmsproviders/osskmsproviders"
|
||||
"github.com/grafana/grafana/pkg/services/secrets"
|
||||
"github.com/grafana/grafana/pkg/services/secrets/database"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
@@ -160,15 +160,17 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
||||
raw, err := ini.Load([]byte(rawCfg))
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &setting.Cfg{Raw: raw, FeatureToggles: map[string]bool{envelopeEncryptionFeatureToggle: true}}
|
||||
cfg := &setting.Cfg{Raw: raw, FeatureToggles: map[string]bool{secrets.EnvelopeEncryptionFeatureToggle: true}}
|
||||
settings := &setting.OSSImpl{Cfg: cfg}
|
||||
|
||||
svc := ProvideSecretsService(
|
||||
encr := ossencryption.ProvideService()
|
||||
svc, err := ProvideSecretsService(
|
||||
database.ProvideSecretsStore(sqlstore.InitTestDB(t)),
|
||||
bus.New(),
|
||||
ossencryption.ProvideService(),
|
||||
osskmsproviders.ProvideService(encr, settings),
|
||||
encr,
|
||||
settings,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, "awskms.second_key", svc.currentProvider)
|
||||
})
|
||||
@@ -185,19 +187,21 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
||||
raw, err := ini.Load([]byte(rawCfg))
|
||||
require.NoError(t, err)
|
||||
|
||||
cfg := &setting.Cfg{Raw: raw, FeatureToggles: map[string]bool{envelopeEncryptionFeatureToggle: true}}
|
||||
cfg := &setting.Cfg{Raw: raw, FeatureToggles: map[string]bool{secrets.EnvelopeEncryptionFeatureToggle: true}}
|
||||
settings := &setting.OSSImpl{Cfg: cfg}
|
||||
|
||||
secretStore := database.ProvideSecretsStore(sqlstore.InitTestDB(t))
|
||||
fake := fakeProvider{}
|
||||
providerID := "fake-provider.some-key"
|
||||
|
||||
svcEncrypt := ProvideSecretsService(
|
||||
encr := ossencryption.ProvideService()
|
||||
svcEncrypt, err := ProvideSecretsService(
|
||||
secretStore,
|
||||
bus.New(),
|
||||
ossencryption.ProvideService(),
|
||||
osskmsproviders.ProvideService(encr, settings),
|
||||
encr,
|
||||
settings,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
svcEncrypt.RegisterProvider(providerID, &fake)
|
||||
require.NoError(t, err)
|
||||
@@ -208,12 +212,13 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
||||
|
||||
// secret service tries to find a DEK in a cache first before calling provider's decrypt
|
||||
// to bypass the cache, we set up one more secrets service to test decrypting
|
||||
svcDecrypt := ProvideSecretsService(
|
||||
svcDecrypt, err := ProvideSecretsService(
|
||||
secretStore,
|
||||
bus.New(),
|
||||
ossencryption.ProvideService(),
|
||||
osskmsproviders.ProvideService(encr, settings),
|
||||
encr,
|
||||
settings,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
svcDecrypt.RegisterProvider(providerID, &fake)
|
||||
_, _ = svcDecrypt.Decrypt(context.Background(), encrypted)
|
||||
assert.True(t, fake.decryptCalled, "fake provider's decrypt should be called")
|
||||
|
||||
@@ -6,6 +6,10 @@ import (
|
||||
"xorm.io/xorm"
|
||||
)
|
||||
|
||||
const (
|
||||
EnvelopeEncryptionFeatureToggle = "envelopeEncryption"
|
||||
)
|
||||
|
||||
// Service is an envelope encryption service in charge of encrypting/decrypting secrets.
|
||||
// It is a replacement for encryption.Service
|
||||
type Service interface {
|
||||
@@ -24,12 +28,6 @@ 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)
|
||||
|
||||
Reference in New Issue
Block a user