Encryption: Use secrets service (#40251)

* Use secrets service in pluginproxy

* Use secrets service in pluginxontext

* Use secrets service in pluginsettings

* Use secrets service in provisioning

* Use secrets service in authinfoservice

* Use secrets service in api

* Use secrets service in sqlstore

* Use secrets service in dashboardshapshots

* Use secrets service in tsdb

* Use secrets service in datasources

* Use secrets service in alerting

* Use secrets service in ngalert

* Break cyclic dependancy

* Refactor service

* Break cyclic dependancy

* Add FakeSecretsStore

* Setup Secrets Service in sqlstore

* Fix

* Continue secrets service refactoring

* Fix cyclic dependancy in sqlstore tests

* Fix secrets service references

* Fix linter errors

* Add fake secrets service for tests

* Refactor SetupTestSecretsService

* Update setting up secret service in tests

* Fix missing secrets service in multiorg_alertmanager_test

* Use fake db in tests and sort imports

* Use fake db in datasources tests

* Fix more tests

* Fix linter issues

* Attempt to fix plugin proxy tests

* Pass secrets service to getPluginProxiedRequest in pluginproxy tests

* Fix pluginproxy tests

* Revert using secrets service in alerting and provisioning

* Update decryptFn in alerting migration

* Rename defaultProvider to currentProvider

* Use fake secrets service in alert channels tests

* Refactor secrets service test helper

* Update setting up secrets service in tests

* Revert alerting changes in api

* Add comments

* Remove secrets service from background services

* Convert global encryption functions into vars

* Revert "Convert global encryption functions into vars"

This reverts commit 498eb19859.

* Add feature toggle for envelope encryption

* Rename toggle

Co-authored-by: Emil Tullstedt <emil.tullstedt@grafana.com>
Co-authored-by: Joan López de la Franca Beltran <joanjan14@gmail.com>
This commit is contained in:
Tania B
2021-11-04 18:47:21 +02:00
committed by GitHub
co-authored by Emil Tullstedt Joan López de la Franca Beltran
parent 9e29484c80
commit 5652bde447
58 changed files with 441 additions and 364 deletions
+7 -12
View File
@@ -6,23 +6,14 @@ import (
"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/secrets/fakes"
"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 SetupTestService(tb testing.TB, db *sqlstore.SQLStore) *SecretsService {
if db == nil {
return setupTestService(tb, fakes.NewFakeSecretsStore())
}
return setupTestService(tb, database.ProvideSecretsStore(db))
}
func setupTestService(tb testing.TB, store secrets.Store) *SecretsService {
func SetupTestService(tb testing.TB, store secrets.Store) *SecretsService {
tb.Helper()
defaultKey := "SdlklWklckeLS"
if len(setting.SecretKey) > 0 {
@@ -32,7 +23,11 @@ func setupTestService(tb testing.TB, store secrets.Store) *SecretsService {
[security]
secret_key = ` + defaultKey))
require.NoError(tb, err)
settings := &setting.OSSImpl{Cfg: &setting.Cfg{Raw: raw}}
cfg := &setting.Cfg{Raw: raw}
cfg.FeatureToggles = map[string]bool{envelopeEncryptionFeatureToggle: true}
settings := &setting.OSSImpl{Cfg: cfg}
assert.True(tb, settings.IsFeatureToggleEnabled(envelopeEncryptionFeatureToggle))
return ProvideSecretsService(
store,
+22 -7
View File
@@ -16,7 +16,10 @@ import (
"github.com/grafana/grafana/pkg/setting"
)
const defaultProvider = "secretKey"
const (
defaultProvider = "secretKey"
envelopeEncryptionFeatureToggle = "envelopeEncryption"
)
type SecretsService struct {
store secrets.Store
@@ -24,7 +27,7 @@ type SecretsService struct {
enc encryption.Service
settings setting.Provider
defaultProvider string
currentProvider string
providers map[string]secrets.Provider
dataKeyCache map[string]dataKeyCacheItem
}
@@ -39,7 +42,7 @@ func ProvideSecretsService(store secrets.Store, bus bus.Bus, enc encryption.Serv
bus: bus,
enc: enc,
settings: settings,
defaultProvider: defaultProvider,
currentProvider: defaultProvider,
providers: providers,
dataKeyCache: make(map[string]dataKeyCacheItem),
}
@@ -55,8 +58,14 @@ type dataKeyCacheItem struct {
var b64 = base64.RawStdEncoding
func (s *SecretsService) Encrypt(ctx context.Context, payload []byte, opt secrets.EncryptionOptions) ([]byte, error) {
// Use legacy encryption service if envelopeEncryptionFeatureToggle toggle is off
if !s.settings.IsFeatureToggleEnabled(envelopeEncryptionFeatureToggle) {
return s.enc.Encrypt(ctx, payload, setting.SecretKey)
}
// If encryption envelopeEncryptionFeatureToggle toggle is on, use envelope encryption
scope := opt()
keyName := fmt.Sprintf("%s/%s@%s", time.Now().Format("2006-01-02"), scope, s.defaultProvider)
keyName := fmt.Sprintf("%s/%s@%s", time.Now().Format("2006-01-02"), scope, s.currentProvider)
dataKey, err := s.dataKey(ctx, keyName)
if err != nil {
@@ -88,6 +97,12 @@ func (s *SecretsService) Encrypt(ctx context.Context, payload []byte, opt secret
}
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) {
return s.enc.Decrypt(ctx, payload, setting.SecretKey)
}
// If encryption envelopeEncryptionFeatureToggle toggle is on, use envelope encryption
if len(payload) == 0 {
return nil, fmt.Errorf("unable to decrypt empty payload")
}
@@ -175,9 +190,9 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
if err != nil {
return nil, err
}
provider, exists := s.providers[s.defaultProvider]
provider, exists := s.providers[s.currentProvider]
if !exists {
return nil, fmt.Errorf("could not find encryption provider '%s'", s.defaultProvider)
return nil, fmt.Errorf("could not find encryption provider '%s'", s.currentProvider)
}
// 2. Encrypt it
@@ -190,7 +205,7 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
err = s.store.CreateDataKey(ctx, secrets.DataKey{
Active: true, // TODO: right now we never mark a key as deactivated
Name: name,
Provider: s.defaultProvider,
Provider: s.currentProvider,
EncryptedData: encrypted,
Scope: scope,
})
+2 -3
View File
@@ -4,18 +4,17 @@ import (
"context"
"testing"
"github.com/grafana/grafana/pkg/services/secrets"
"github.com/grafana/grafana/pkg/services/secrets/database"
"github.com/grafana/grafana/pkg/services/sqlstore"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/grafana/grafana/pkg/services/secrets"
)
func TestSecrets_EnvelopeEncryption(t *testing.T) {
store := database.ProvideSecretsStore(sqlstore.InitTestDB(t))
svc := setupTestService(t, store)
svc := SetupTestService(t, store)
ctx := context.Background()
t.Run("encrypting with no entity_id should create DEK", func(t *testing.T) {
+4
View File
@@ -6,6 +6,8 @@ import (
"xorm.io/xorm"
)
// Service is an envelope encryption service in charge of encrypting/decrypting secrets.
// It is a replacement for encryption.Service
type Service interface {
Encrypt(ctx context.Context, payload []byte, opt EncryptionOptions) ([]byte, error)
Decrypt(ctx context.Context, payload []byte) ([]byte, error)
@@ -14,6 +16,7 @@ type Service interface {
GetDecryptedValue(ctx context.Context, sjd map[string][]byte, key, fallback string) string
}
// Store defines methods to interact with secrets storage
type Store interface {
GetDataKey(ctx context.Context, name string) (*DataKey, error)
GetAllDataKeys(ctx context.Context) ([]*DataKey, error)
@@ -22,6 +25,7 @@ type Store interface {
DeleteDataKey(ctx context.Context, name string) error
}
// Provider is a key encryption key provider for envelope encryption
type Provider interface {
Encrypt(ctx context.Context, blob []byte) ([]byte, error)
Decrypt(ctx context.Context, blob []byte) ([]byte, error)