mirror of
https://github.com/grafana/grafana.git
synced 2025-07-30 01:12:09 +08:00
Secrets: Make the Migrator extensible (#67307)
* [Chore] Remove setting provider from secret service Co-authored-by: Tania B <yalyna.ts@gmail.com> Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com> * Add a ShouldBeRedacted func Co-authored-by: Tania B <yalyna.ts@gmail.com> Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com> * Secrets: Make Migrator extensible Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Tania B <yalyna.ts@gmail.com> * Alerting: Fix tests after refactor Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com> Co-authored-by: Tania B <yalyna.ts@gmail.com> * Remove commented code no longer used * Fix Wire bindings Co-authored-by: Tania B <yalyna.ts@gmail.com> * Add constructors to secrets * Linting * Undo undesired change --------- Co-authored-by: gamab <gabi.mabs@gmail.com> Co-authored-by: Tania B <yalyna.ts@gmail.com> Co-authored-by: Gabriel MABILLE <gamab@users.noreply.github.com>
This commit is contained in:

committed by
GitHub

parent
a50afe67d3
commit
cc65b4d46a
@ -111,7 +111,6 @@ import (
|
|||||||
secretsStore "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
secretsStore "github.com/grafana/grafana/pkg/services/secrets/kvstore"
|
||||||
secretsMigrations "github.com/grafana/grafana/pkg/services/secrets/kvstore/migrations"
|
secretsMigrations "github.com/grafana/grafana/pkg/services/secrets/kvstore/migrations"
|
||||||
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
secretsManager "github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
secretsMigrator "github.com/grafana/grafana/pkg/services/secrets/migrator"
|
|
||||||
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
"github.com/grafana/grafana/pkg/services/serviceaccounts"
|
||||||
serviceaccountsmanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
|
serviceaccountsmanager "github.com/grafana/grafana/pkg/services/serviceaccounts/manager"
|
||||||
serviceaccountsretriever "github.com/grafana/grafana/pkg/services/serviceaccounts/retriever"
|
serviceaccountsretriever "github.com/grafana/grafana/pkg/services/serviceaccounts/retriever"
|
||||||
@ -264,8 +263,6 @@ var wireBasicSet = wire.NewSet(
|
|||||||
wire.Bind(new(secrets.Service), new(*secretsManager.SecretsService)),
|
wire.Bind(new(secrets.Service), new(*secretsManager.SecretsService)),
|
||||||
secretsDatabase.ProvideSecretsStore,
|
secretsDatabase.ProvideSecretsStore,
|
||||||
wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)),
|
wire.Bind(new(secrets.Store), new(*secretsDatabase.SecretsStoreImpl)),
|
||||||
secretsMigrator.ProvideSecretsMigrator,
|
|
||||||
wire.Bind(new(secrets.Migrator), new(*secretsMigrator.SecretsMigrator)),
|
|
||||||
grafanads.ProvideService,
|
grafanads.ProvideService,
|
||||||
wire.Bind(new(dashboardsnapshots.Store), new(*dashsnapstore.DashboardSnapshotStore)),
|
wire.Bind(new(dashboardsnapshots.Store), new(*dashsnapstore.DashboardSnapshotStore)),
|
||||||
dashsnapstore.ProvideStore,
|
dashsnapstore.ProvideStore,
|
||||||
|
@ -35,6 +35,8 @@ import (
|
|||||||
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
publicdashboardsService "github.com/grafana/grafana/pkg/services/publicdashboards/service"
|
||||||
"github.com/grafana/grafana/pkg/services/searchusers"
|
"github.com/grafana/grafana/pkg/services/searchusers"
|
||||||
"github.com/grafana/grafana/pkg/services/searchusers/filters"
|
"github.com/grafana/grafana/pkg/services/searchusers/filters"
|
||||||
|
"github.com/grafana/grafana/pkg/services/secrets"
|
||||||
|
secretsMigrator "github.com/grafana/grafana/pkg/services/secrets/migrator"
|
||||||
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
|
"github.com/grafana/grafana/pkg/services/sqlstore/migrations"
|
||||||
"github.com/grafana/grafana/pkg/services/user"
|
"github.com/grafana/grafana/pkg/services/user"
|
||||||
"github.com/grafana/grafana/pkg/services/validations"
|
"github.com/grafana/grafana/pkg/services/validations"
|
||||||
@ -88,6 +90,8 @@ var wireExtsBasicSet = wire.NewSet(
|
|||||||
wire.Bind(new(publicdashboards.ServiceWrapper), new(*publicdashboardsService.PublicDashboardServiceWrapperImpl)),
|
wire.Bind(new(publicdashboards.ServiceWrapper), new(*publicdashboardsService.PublicDashboardServiceWrapperImpl)),
|
||||||
caching.ProvideCachingService,
|
caching.ProvideCachingService,
|
||||||
wire.Bind(new(caching.CachingService), new(*caching.OSSCachingService)),
|
wire.Bind(new(caching.CachingService), new(*caching.OSSCachingService)),
|
||||||
|
secretsMigrator.ProvideSecretsMigrator,
|
||||||
|
wire.Bind(new(secrets.Migrator), new(*secretsMigrator.SecretsMigrator)),
|
||||||
)
|
)
|
||||||
|
|
||||||
var wireExtsSet = wire.NewSet(
|
var wireExtsSet = wire.NewSet(
|
||||||
|
@ -31,10 +31,7 @@ func TestIntegrationEngineTimeouts(t *testing.T) {
|
|||||||
usValidatorMock := &validator.FakeUsageStatsValidator{}
|
usValidatorMock := &validator.FakeUsageStatsValidator{}
|
||||||
|
|
||||||
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
||||||
cfg := setting.NewCfg()
|
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, setting.NewCfg())
|
||||||
settings := &setting.OSSImpl{Cfg: cfg}
|
|
||||||
|
|
||||||
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
tracer := tracing.InitializeTracerForTest()
|
tracer := tracing.InitializeTracerForTest()
|
||||||
|
@ -122,10 +122,7 @@ func TestEngineProcessJob(t *testing.T) {
|
|||||||
usValidatorMock := &validator.FakeUsageStatsValidator{}
|
usValidatorMock := &validator.FakeUsageStatsValidator{}
|
||||||
|
|
||||||
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
||||||
cfg := setting.NewCfg()
|
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, setting.NewCfg())
|
||||||
settings := &setting.OSSImpl{Cfg: cfg}
|
|
||||||
|
|
||||||
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
tracer := tracing.InitializeTracerForTest()
|
tracer := tracing.InitializeTracerForTest()
|
||||||
|
|
||||||
|
@ -33,9 +33,7 @@ func TestService(t *testing.T) {
|
|||||||
usMock := &usagestats.UsageStatsMock{T: t}
|
usMock := &usagestats.UsageStatsMock{T: t}
|
||||||
|
|
||||||
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
encProvider := encryptionprovider.ProvideEncryptionProvider()
|
||||||
settings := &setting.OSSImpl{Cfg: setting.NewCfg()}
|
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, setting.NewCfg())
|
||||||
|
|
||||||
encService, err := encryptionservice.ProvideEncryptionService(encProvider, usMock, settings)
|
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
s := ProvideService(sqlStore.db, encService, nil)
|
s := ProvideService(sqlStore.db, encService, nil)
|
||||||
|
@ -15,7 +15,7 @@ func SetupTestService(tb testing.TB) *Service {
|
|||||||
|
|
||||||
usMock := &usagestats.UsageStatsMock{T: tb}
|
usMock := &usagestats.UsageStatsMock{T: tb}
|
||||||
provider := encryptionprovider.ProvideEncryptionProvider()
|
provider := encryptionprovider.ProvideEncryptionProvider()
|
||||||
settings := &setting.OSSImpl{Cfg: setting.NewCfg()}
|
settings := setting.NewCfg()
|
||||||
|
|
||||||
service, err := ProvideEncryptionService(provider, usMock, settings)
|
service, err := ProvideEncryptionService(provider, usMock, settings)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
@ -26,8 +26,8 @@ const (
|
|||||||
type Service struct {
|
type Service struct {
|
||||||
log log.Logger
|
log log.Logger
|
||||||
|
|
||||||
settingsProvider setting.Provider
|
cfg *setting.Cfg
|
||||||
usageMetrics usagestats.Service
|
usageMetrics usagestats.Service
|
||||||
|
|
||||||
ciphers map[string]encryption.Cipher
|
ciphers map[string]encryption.Cipher
|
||||||
deciphers map[string]encryption.Decipher
|
deciphers map[string]encryption.Decipher
|
||||||
@ -36,7 +36,7 @@ type Service struct {
|
|||||||
func ProvideEncryptionService(
|
func ProvideEncryptionService(
|
||||||
provider encryption.Provider,
|
provider encryption.Provider,
|
||||||
usageMetrics usagestats.Service,
|
usageMetrics usagestats.Service,
|
||||||
settingsProvider setting.Provider,
|
cfg *setting.Cfg,
|
||||||
) (*Service, error) {
|
) (*Service, error) {
|
||||||
s := &Service{
|
s := &Service{
|
||||||
log: log.New("encryption"),
|
log: log.New("encryption"),
|
||||||
@ -44,20 +44,17 @@ func ProvideEncryptionService(
|
|||||||
ciphers: provider.ProvideCiphers(),
|
ciphers: provider.ProvideCiphers(),
|
||||||
deciphers: provider.ProvideDeciphers(),
|
deciphers: provider.ProvideDeciphers(),
|
||||||
|
|
||||||
usageMetrics: usageMetrics,
|
usageMetrics: usageMetrics,
|
||||||
settingsProvider: settingsProvider,
|
cfg: cfg,
|
||||||
}
|
}
|
||||||
|
|
||||||
algorithm := s.settingsProvider.
|
algorithm := s.cfg.SectionWithEnvOverrides(securitySection).Key(encryptionAlgorithmKey).
|
||||||
KeyValue(securitySection, encryptionAlgorithmKey).
|
|
||||||
MustString(defaultEncryptionAlgorithm)
|
MustString(defaultEncryptionAlgorithm)
|
||||||
|
|
||||||
if err := s.checkEncryptionAlgorithm(algorithm); err != nil {
|
if err := s.checkEncryptionAlgorithm(algorithm); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
settingsProvider.RegisterReloadHandler(securitySection, s)
|
|
||||||
|
|
||||||
s.registerUsageMetrics()
|
s.registerUsageMetrics()
|
||||||
|
|
||||||
return s, nil
|
return s, nil
|
||||||
@ -86,8 +83,7 @@ func (s *Service) checkEncryptionAlgorithm(algorithm string) error {
|
|||||||
|
|
||||||
func (s *Service) registerUsageMetrics() {
|
func (s *Service) registerUsageMetrics() {
|
||||||
s.usageMetrics.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
|
s.usageMetrics.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
|
||||||
algorithm := s.settingsProvider.
|
algorithm := s.cfg.SectionWithEnvOverrides(securitySection).Key(encryptionAlgorithmKey).
|
||||||
KeyValue(securitySection, encryptionAlgorithmKey).
|
|
||||||
MustString(defaultEncryptionAlgorithm)
|
MustString(defaultEncryptionAlgorithm)
|
||||||
|
|
||||||
return map[string]interface{}{
|
return map[string]interface{}{
|
||||||
@ -174,8 +170,7 @@ func (s *Service) Encrypt(ctx context.Context, payload []byte, secret string) ([
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
algorithm := s.settingsProvider.
|
algorithm := s.cfg.SectionWithEnvOverrides(securitySection).Key(encryptionAlgorithmKey).
|
||||||
KeyValue(securitySection, encryptionAlgorithmKey).
|
|
||||||
MustString(defaultEncryptionAlgorithm)
|
MustString(defaultEncryptionAlgorithm)
|
||||||
|
|
||||||
cipher, ok := s.ciphers[algorithm]
|
cipher, ok := s.ciphers[algorithm]
|
||||||
@ -237,20 +232,3 @@ func (s *Service) GetDecryptedValue(ctx context.Context, sjd map[string][]byte,
|
|||||||
|
|
||||||
return fallback
|
return fallback
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *Service) Validate(section setting.Section) error {
|
|
||||||
s.log.Debug("Validating encryption config")
|
|
||||||
|
|
||||||
algorithm := section.KeyValue(encryptionAlgorithmKey).
|
|
||||||
MustString(defaultEncryptionAlgorithm)
|
|
||||||
|
|
||||||
if err := s.checkEncryptionAlgorithm(algorithm); err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *Service) Reload(_ setting.Section) error {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
@ -18,7 +18,7 @@ func Test_Service(t *testing.T) {
|
|||||||
|
|
||||||
encProvider := provider.Provider{}
|
encProvider := provider.Provider{}
|
||||||
usageStats := &usagestats.UsageStatsMock{}
|
usageStats := &usagestats.UsageStatsMock{}
|
||||||
settings := &setting.OSSImpl{Cfg: setting.NewCfg()}
|
settings := setting.NewCfg()
|
||||||
|
|
||||||
svc, err := ProvideEncryptionService(encProvider, usageStats, settings)
|
svc, err := ProvideEncryptionService(encProvider, usageStats, settings)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -31,7 +31,7 @@ func Test_Service(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("encrypt and decrypt with aes-cfb should work", func(t *testing.T) {
|
t.Run("encrypt and decrypt with aes-cfb should work", func(t *testing.T) {
|
||||||
settings.Cfg.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesCfb)
|
settings.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesCfb)
|
||||||
|
|
||||||
encrypted, err := svc.Encrypt(ctx, []byte("grafana"), "1234")
|
encrypted, err := svc.Encrypt(ctx, []byte("grafana"), "1234")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
@ -55,7 +55,7 @@ func Test_Service(t *testing.T) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
t.Run("encrypt with aes-gcm should fail", func(t *testing.T) {
|
t.Run("encrypt with aes-gcm should fail", func(t *testing.T) {
|
||||||
settings.Cfg.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesGcm)
|
settings.Raw.Section(securitySection).Key(encryptionAlgorithmKey).SetValue(encryption.AesGcm)
|
||||||
|
|
||||||
_, err := svc.Encrypt(ctx, []byte("grafana"), "1234")
|
_, err := svc.Encrypt(ctx, []byte("grafana"), "1234")
|
||||||
require.Error(t, err)
|
require.Error(t, err)
|
||||||
@ -77,7 +77,7 @@ func Test_Service(t *testing.T) {
|
|||||||
func Test_Service_MissingProvider(t *testing.T) {
|
func Test_Service_MissingProvider(t *testing.T) {
|
||||||
encProvider := fakeProvider{}
|
encProvider := fakeProvider{}
|
||||||
usageStats := &usagestats.UsageStatsMock{}
|
usageStats := &usagestats.UsageStatsMock{}
|
||||||
settings := &setting.OSSImpl{Cfg: setting.NewCfg()}
|
settings := setting.NewCfg()
|
||||||
|
|
||||||
service, err := ProvideEncryptionService(encProvider, usageStats, settings)
|
service, err := ProvideEncryptionService(encProvider, usageStats, settings)
|
||||||
assert.Nil(t, service)
|
assert.Nil(t, service)
|
||||||
|
@ -9,23 +9,23 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type grafanaProvider struct {
|
type grafanaProvider struct {
|
||||||
settings setting.Provider
|
cfg *setting.Cfg
|
||||||
encryption encryption.Internal
|
encryption encryption.Internal
|
||||||
}
|
}
|
||||||
|
|
||||||
func New(settings setting.Provider, encryption encryption.Internal) secrets.Provider {
|
func New(cfg *setting.Cfg, encryption encryption.Internal) secrets.Provider {
|
||||||
return grafanaProvider{
|
return grafanaProvider{
|
||||||
settings: settings,
|
cfg: cfg,
|
||||||
encryption: encryption,
|
encryption: encryption,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p grafanaProvider) Encrypt(ctx context.Context, blob []byte) ([]byte, error) {
|
func (p grafanaProvider) Encrypt(ctx context.Context, blob []byte) ([]byte, error) {
|
||||||
key := p.settings.KeyValue("security", "secret_key").Value()
|
key := p.cfg.SectionWithEnvOverrides("security").Key("secret_key").Value()
|
||||||
return p.encryption.Encrypt(ctx, blob, key)
|
return p.encryption.Encrypt(ctx, blob, key)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p grafanaProvider) Decrypt(ctx context.Context, blob []byte) ([]byte, error) {
|
func (p grafanaProvider) Decrypt(ctx context.Context, blob []byte) ([]byte, error) {
|
||||||
key := p.settings.KeyValue("security", "secret_key").Value()
|
key := p.cfg.SectionWithEnvOverrides("security").Key("secret_key").Value()
|
||||||
return p.encryption.Decrypt(ctx, blob, key)
|
return p.encryption.Decrypt(ctx, blob, key)
|
||||||
}
|
}
|
||||||
|
@ -11,20 +11,20 @@ import (
|
|||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
enc encryption.Internal
|
enc encryption.Internal
|
||||||
settings setting.Provider
|
cfg *setting.Cfg
|
||||||
features featuremgmt.FeatureToggles
|
features featuremgmt.FeatureToggles
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideService(enc encryption.Internal, settings setting.Provider, features featuremgmt.FeatureToggles) Service {
|
func ProvideService(enc encryption.Internal, cfg *setting.Cfg, features featuremgmt.FeatureToggles) Service {
|
||||||
return Service{
|
return Service{
|
||||||
enc: enc,
|
enc: enc,
|
||||||
settings: settings,
|
cfg: cfg,
|
||||||
features: features,
|
features: features,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s Service) Provide() (map[secrets.ProviderID]secrets.Provider, error) {
|
func (s Service) Provide() (map[secrets.ProviderID]secrets.Provider, error) {
|
||||||
return map[secrets.ProviderID]secrets.Provider{
|
return map[secrets.ProviderID]secrets.Provider{
|
||||||
kmsproviders.Default: grafana.New(s.settings, s.enc),
|
kmsproviders.Default: grafana.New(s.cfg, s.enc),
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
@ -39,19 +39,18 @@ func setupTestService(tb testing.TB, store secrets.Store, features *featuremgmt.
|
|||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
cfg := &setting.Cfg{Raw: raw}
|
cfg := &setting.Cfg{Raw: raw}
|
||||||
settings := &setting.OSSImpl{Cfg: cfg}
|
|
||||||
|
|
||||||
encProvider := encryptionprovider.Provider{}
|
encProvider := encryptionprovider.Provider{}
|
||||||
usageStats := &usagestats.UsageStatsMock{}
|
usageStats := &usagestats.UsageStatsMock{}
|
||||||
|
|
||||||
encryption, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, settings)
|
encryption, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, cfg)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
secretsService, err := ProvideSecretsService(
|
secretsService, err := ProvideSecretsService(
|
||||||
store,
|
store,
|
||||||
osskmsproviders.ProvideService(encryption, settings, features),
|
osskmsproviders.ProvideService(encryption, cfg, features),
|
||||||
encryption,
|
encryption,
|
||||||
settings,
|
cfg,
|
||||||
features,
|
features,
|
||||||
&usagestats.UsageStatsMock{T: tb},
|
&usagestats.UsageStatsMock{T: tb},
|
||||||
)
|
)
|
||||||
|
@ -37,7 +37,7 @@ var (
|
|||||||
type SecretsService struct {
|
type SecretsService struct {
|
||||||
store secrets.Store
|
store secrets.Store
|
||||||
enc encryption.Internal
|
enc encryption.Internal
|
||||||
settings setting.Provider
|
cfg *setting.Cfg
|
||||||
features featuremgmt.FeatureToggles
|
features featuremgmt.FeatureToggles
|
||||||
usageStats usagestats.Service
|
usageStats usagestats.Service
|
||||||
|
|
||||||
@ -57,20 +57,20 @@ func ProvideSecretsService(
|
|||||||
store secrets.Store,
|
store secrets.Store,
|
||||||
kmsProvidersService kmsproviders.Service,
|
kmsProvidersService kmsproviders.Service,
|
||||||
enc encryption.Internal,
|
enc encryption.Internal,
|
||||||
settings setting.Provider,
|
cfg *setting.Cfg,
|
||||||
features featuremgmt.FeatureToggles,
|
features featuremgmt.FeatureToggles,
|
||||||
usageStats usagestats.Service,
|
usageStats usagestats.Service,
|
||||||
) (*SecretsService, error) {
|
) (*SecretsService, error) {
|
||||||
ttl := settings.KeyValue("security.encryption", "data_keys_cache_ttl").MustDuration(15 * time.Minute)
|
ttl := cfg.SectionWithEnvOverrides("security.encryption").Key("data_keys_cache_ttl").MustDuration(15 * time.Minute)
|
||||||
|
|
||||||
currentProviderID := kmsproviders.NormalizeProviderID(secrets.ProviderID(
|
currentProviderID := kmsproviders.NormalizeProviderID(secrets.ProviderID(
|
||||||
settings.KeyValue("security", "encryption_provider").MustString(kmsproviders.Default),
|
cfg.SectionWithEnvOverrides("security").Key("encryption_provider").MustString(kmsproviders.Default),
|
||||||
))
|
))
|
||||||
|
|
||||||
s := &SecretsService{
|
s := &SecretsService{
|
||||||
store: store,
|
store: store,
|
||||||
enc: enc,
|
enc: enc,
|
||||||
settings: settings,
|
cfg: cfg,
|
||||||
usageStats: usageStats,
|
usageStats: usageStats,
|
||||||
kmsProvidersService: kmsProvidersService,
|
kmsProvidersService: kmsProvidersService,
|
||||||
dataKeyCache: newDataKeyCache(ttl),
|
dataKeyCache: newDataKeyCache(ttl),
|
||||||
@ -342,7 +342,7 @@ func (s *SecretsService) Decrypt(ctx context.Context, payload []byte) ([]byte, e
|
|||||||
var dataKey []byte
|
var dataKey []byte
|
||||||
|
|
||||||
if !s.encryptedWithEnvelopeEncryption(payload) {
|
if !s.encryptedWithEnvelopeEncryption(payload) {
|
||||||
secretKey := s.settings.KeyValue("security", "secret_key").Value()
|
secretKey := s.cfg.SectionWithEnvOverrides("security").Key("secret_key").Value()
|
||||||
dataKey = []byte(secretKey)
|
dataKey = []byte(secretKey)
|
||||||
} else {
|
} else {
|
||||||
payload = payload[1:]
|
payload = payload[1:]
|
||||||
@ -491,7 +491,7 @@ func (s *SecretsService) ReEncryptDataKeys(ctx context.Context) error {
|
|||||||
|
|
||||||
func (s *SecretsService) Run(ctx context.Context) error {
|
func (s *SecretsService) Run(ctx context.Context) error {
|
||||||
gc := time.NewTicker(
|
gc := time.NewTicker(
|
||||||
s.settings.KeyValue("security.encryption", "data_keys_cache_cleanup_interval").
|
s.cfg.SectionWithEnvOverrides("security.encryption").Key("data_keys_cache_cleanup_interval").
|
||||||
MustDuration(time.Minute),
|
MustDuration(time.Minute),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -182,16 +182,16 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
|||||||
raw, err := ini.Load([]byte(rawCfg))
|
raw, err := ini.Load([]byte(rawCfg))
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
settings := &setting.OSSImpl{Cfg: &setting.Cfg{Raw: raw}}
|
cfg := &setting.Cfg{Raw: raw}
|
||||||
|
|
||||||
encProvider := encryptionprovider.Provider{}
|
encProvider := encryptionprovider.Provider{}
|
||||||
usageStats := &usagestats.UsageStatsMock{}
|
usageStats := &usagestats.UsageStatsMock{}
|
||||||
|
|
||||||
encryptionService, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, settings)
|
encryptionService, err := encryptionservice.ProvideEncryptionService(encProvider, usageStats, cfg)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
features := featuremgmt.WithFeatures()
|
features := featuremgmt.WithFeatures()
|
||||||
kms := newFakeKMS(osskmsproviders.ProvideService(encryptionService, settings, features))
|
kms := newFakeKMS(osskmsproviders.ProvideService(encryptionService, cfg, features))
|
||||||
testDB := db.InitTestDB(t)
|
testDB := db.InitTestDB(t)
|
||||||
secretStore := database.ProvideSecretsStore(testDB)
|
secretStore := database.ProvideSecretsStore(testDB)
|
||||||
|
|
||||||
@ -199,7 +199,7 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
|||||||
secretStore,
|
secretStore,
|
||||||
&kms,
|
&kms,
|
||||||
encryptionService,
|
encryptionService,
|
||||||
settings,
|
cfg,
|
||||||
features,
|
features,
|
||||||
&usagestats.UsageStatsMock{T: t},
|
&usagestats.UsageStatsMock{T: t},
|
||||||
)
|
)
|
||||||
@ -217,7 +217,7 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
|
|||||||
secretStore,
|
secretStore,
|
||||||
&kms,
|
&kms,
|
||||||
encryptionService,
|
encryptionService,
|
||||||
settings,
|
cfg,
|
||||||
features,
|
features,
|
||||||
&usagestats.UsageStatsMock{T: t},
|
&usagestats.UsageStatsMock{T: t},
|
||||||
)
|
)
|
||||||
|
@ -13,12 +13,18 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/setting"
|
"github.com/grafana/grafana/pkg/setting"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type SecretsRotator interface {
|
||||||
|
ReEncrypt(context.Context, *manager.SecretsService, db.DB) bool
|
||||||
|
Rollback(context.Context, *manager.SecretsService, encryption.Internal, db.DB, string) bool
|
||||||
|
}
|
||||||
|
|
||||||
type SecretsMigrator struct {
|
type SecretsMigrator struct {
|
||||||
encryptionSrv encryption.Internal
|
encryptionSrv encryption.Internal
|
||||||
secretsSrv *manager.SecretsService
|
secretsSrv *manager.SecretsService
|
||||||
sqlStore db.DB
|
sqlStore db.DB
|
||||||
settings setting.Provider
|
settings setting.Provider
|
||||||
features featuremgmt.FeatureToggles
|
features featuremgmt.FeatureToggles
|
||||||
|
rotators []SecretsRotator
|
||||||
}
|
}
|
||||||
|
|
||||||
func ProvideSecretsMigrator(
|
func ProvideSecretsMigrator(
|
||||||
@ -28,24 +34,7 @@ func ProvideSecretsMigrator(
|
|||||||
settings setting.Provider,
|
settings setting.Provider,
|
||||||
features featuremgmt.FeatureToggles,
|
features featuremgmt.FeatureToggles,
|
||||||
) *SecretsMigrator {
|
) *SecretsMigrator {
|
||||||
return &SecretsMigrator{
|
rotators := []SecretsRotator{
|
||||||
encryptionSrv: encryptionSrv,
|
|
||||||
secretsSrv: service,
|
|
||||||
sqlStore: sqlStore,
|
|
||||||
settings: settings,
|
|
||||||
features: features,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (m *SecretsMigrator) ReEncryptSecrets(ctx context.Context) (bool, error) {
|
|
||||||
err := m.initProvidersIfNeeded()
|
|
||||||
if err != nil {
|
|
||||||
return false, err
|
|
||||||
}
|
|
||||||
|
|
||||||
toReencrypt := []interface {
|
|
||||||
reencrypt(context.Context, *manager.SecretsService, db.DB) bool
|
|
||||||
}{
|
|
||||||
simpleSecret{tableName: "dashboard_snapshot", columnName: "dashboard_encrypted"},
|
simpleSecret{tableName: "dashboard_snapshot", columnName: "dashboard_encrypted"},
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_access_token"}, encoding: base64.StdEncoding},
|
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_access_token"}, encoding: base64.StdEncoding},
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_refresh_token"}, encoding: base64.StdEncoding},
|
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_refresh_token"}, encoding: base64.StdEncoding},
|
||||||
@ -56,10 +45,30 @@ func (m *SecretsMigrator) ReEncryptSecrets(ctx context.Context) (bool, error) {
|
|||||||
alertingSecret{},
|
alertingSecret{},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return &SecretsMigrator{
|
||||||
|
encryptionSrv: encryptionSrv,
|
||||||
|
secretsSrv: service,
|
||||||
|
sqlStore: sqlStore,
|
||||||
|
settings: settings,
|
||||||
|
features: features,
|
||||||
|
rotators: rotators,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SecretsMigrator) RegisterRotators(rotators ...SecretsRotator) {
|
||||||
|
m.rotators = append(m.rotators, rotators...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (m *SecretsMigrator) ReEncryptSecrets(ctx context.Context) (bool, error) {
|
||||||
|
err := m.initProvidersIfNeeded()
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
|
||||||
var anyFailure bool
|
var anyFailure bool
|
||||||
|
|
||||||
for _, r := range toReencrypt {
|
for _, r := range m.rotators {
|
||||||
if success := r.reencrypt(ctx, m.secretsSrv, m.sqlStore); !success {
|
if success := r.ReEncrypt(ctx, m.secretsSrv, m.sqlStore); !success {
|
||||||
anyFailure = true
|
anyFailure = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,23 +82,10 @@ func (m *SecretsMigrator) RollBackSecrets(ctx context.Context) (bool, error) {
|
|||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
|
|
||||||
toRollback := []interface {
|
|
||||||
rollback(context.Context, *manager.SecretsService, encryption.Internal, db.DB, string) bool
|
|
||||||
}{
|
|
||||||
simpleSecret{tableName: "dashboard_snapshot", columnName: "dashboard_encrypted"},
|
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_access_token"}, encoding: base64.StdEncoding},
|
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_refresh_token"}, encoding: base64.StdEncoding},
|
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "user_auth", columnName: "o_auth_token_type"}, encoding: base64.StdEncoding},
|
|
||||||
b64Secret{simpleSecret: simpleSecret{tableName: "secrets", columnName: "value"}, hasUpdatedColumn: true, encoding: base64.RawStdEncoding},
|
|
||||||
jsonSecret{tableName: "data_source"},
|
|
||||||
jsonSecret{tableName: "plugin_setting"},
|
|
||||||
alertingSecret{},
|
|
||||||
}
|
|
||||||
|
|
||||||
var anyFailure bool
|
var anyFailure bool
|
||||||
|
|
||||||
for _, r := range toRollback {
|
for _, r := range m.rotators {
|
||||||
if failed := r.rollback(ctx,
|
if failed := r.Rollback(ctx,
|
||||||
m.secretsSrv,
|
m.secretsSrv,
|
||||||
m.encryptionSrv,
|
m.encryptionSrv,
|
||||||
m.sqlStore,
|
m.sqlStore,
|
||||||
@ -133,12 +129,26 @@ type simpleSecret struct {
|
|||||||
columnName string
|
columnName string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewSimpleSecret(tableName, columnName string) simpleSecret {
|
||||||
|
return simpleSecret{
|
||||||
|
tableName: tableName,
|
||||||
|
columnName: columnName,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type b64Secret struct {
|
type b64Secret struct {
|
||||||
simpleSecret
|
simpleSecret
|
||||||
hasUpdatedColumn bool
|
hasUpdatedColumn bool
|
||||||
encoding *base64.Encoding
|
encoding *base64.Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NewBase64Secret(simple simpleSecret, encoding *base64.Encoding) b64Secret {
|
||||||
|
return b64Secret{
|
||||||
|
simpleSecret: simple,
|
||||||
|
encoding: encoding,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
type jsonSecret struct {
|
type jsonSecret struct {
|
||||||
tableName string
|
tableName string
|
||||||
}
|
}
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s simpleSecret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
func (s simpleSecret) ReEncrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
||||||
var rows []struct {
|
var rows []struct {
|
||||||
Id int
|
Id int
|
||||||
Secret []byte
|
Secret []byte
|
||||||
@ -72,7 +72,7 @@ func (s simpleSecret) reencrypt(ctx context.Context, secretsSrv *manager.Secrets
|
|||||||
return !anyFailure
|
return !anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s b64Secret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
func (s b64Secret) ReEncrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
||||||
var rows []struct {
|
var rows []struct {
|
||||||
Id int
|
Id int
|
||||||
Secret string
|
Secret string
|
||||||
@ -143,7 +143,7 @@ func (s b64Secret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsSer
|
|||||||
return !anyFailure
|
return !anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s jsonSecret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
func (s jsonSecret) ReEncrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
||||||
var rows []struct {
|
var rows []struct {
|
||||||
Id int
|
Id int
|
||||||
SecureJsonData map[string][]byte
|
SecureJsonData map[string][]byte
|
||||||
@ -206,7 +206,7 @@ func (s jsonSecret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsSe
|
|||||||
return !anyFailure
|
return !anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s alertingSecret) reencrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
func (s alertingSecret) ReEncrypt(ctx context.Context, secretsSrv *manager.SecretsService, sqlStore db.DB) bool {
|
||||||
var results []struct {
|
var results []struct {
|
||||||
Id int
|
Id int
|
||||||
AlertmanagerConfiguration string
|
AlertmanagerConfiguration string
|
||||||
|
@ -12,7 +12,7 @@ import (
|
|||||||
"github.com/grafana/grafana/pkg/services/secrets/manager"
|
"github.com/grafana/grafana/pkg/services/secrets/manager"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (s simpleSecret) rollback(
|
func (s simpleSecret) Rollback(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
secretsSrv *manager.SecretsService,
|
secretsSrv *manager.SecretsService,
|
||||||
encryptionSrv encryption.Internal,
|
encryptionSrv encryption.Internal,
|
||||||
@ -72,7 +72,7 @@ func (s simpleSecret) rollback(
|
|||||||
return anyFailure
|
return anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s b64Secret) rollback(
|
func (s b64Secret) Rollback(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
secretsSrv *manager.SecretsService,
|
secretsSrv *manager.SecretsService,
|
||||||
encryptionSrv encryption.Internal,
|
encryptionSrv encryption.Internal,
|
||||||
@ -146,7 +146,7 @@ func (s b64Secret) rollback(
|
|||||||
return anyFailure
|
return anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s jsonSecret) rollback(
|
func (s jsonSecret) Rollback(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
secretsSrv *manager.SecretsService,
|
secretsSrv *manager.SecretsService,
|
||||||
encryptionSrv encryption.Internal,
|
encryptionSrv encryption.Internal,
|
||||||
@ -210,7 +210,7 @@ func (s jsonSecret) rollback(
|
|||||||
return anyFailure
|
return anyFailure
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s alertingSecret) rollback(
|
func (s alertingSecret) Rollback(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
secretsSrv *manager.SecretsService,
|
secretsSrv *manager.SecretsService,
|
||||||
encryptionSrv encryption.Internal,
|
encryptionSrv encryption.Internal,
|
||||||
|
Reference in New Issue
Block a user