Usage Stats: Add metrics to count enabled kms providers per kind (#43640)

* Usage Insights: Add metrics to count enabled kms providers per kind

* Add backwards compatibility
pull/43850/head
Joan López de la Franca Beltran 3 years ago committed by GitHub
parent e2dcfbf916
commit 532e71554f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      conf/defaults.ini
  2. 6
      conf/sample.ini
  3. 12
      pkg/services/kmsproviders/kmsproviders.go
  4. 4
      pkg/services/kmsproviders/osskmsproviders/osskmsproviders.go
  5. 87
      pkg/services/secrets/manager/manager.go
  6. 10
      pkg/services/secrets/manager/manager_test.go
  7. 15
      pkg/services/secrets/secrets.go
  8. 2
      pkg/services/secrets/types.go

@ -235,7 +235,7 @@ admin_password = admin
secret_key = SW2YcwTIb9zpOOhoPsMm
# current key provider used for envelope encryption, default to static value specified by secret_key
encryption_provider = secretKey
encryption_provider = secretKey.v1
# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
available_encryption_providers =

@ -235,7 +235,7 @@
;secret_key = SW2YcwTIb9zpOOhoPsMm
# current key provider used for envelope encryption, default to static value specified by secret_key
;encryption_provider = secretKey
;encryption_provider = secretKey.v1
# list of configured key providers, space separated (Enterprise only): e.g., awskms.v1 azurekv.v1
;available_encryption_providers =
@ -1055,8 +1055,8 @@
;license_path =
[feature_toggles]
# there are currently two ways to enable feature toggles in the `grafana.ini`.
# you can either pass an array of feature you want to enable to the `enable` field or
# there are currently two ways to enable feature toggles in the `grafana.ini`.
# you can either pass an array of feature you want to enable to the `enable` field or
# configure each toggle by setting the name of the toggle to true/false. Toggles set to true/false
# will take presidence over toggles in the `enable` list.

@ -3,9 +3,17 @@ package kmsproviders
import "github.com/grafana/grafana/pkg/services/secrets"
const (
Default = "secretKey"
// Legacy is used for historical reasons (keeping backwards).
// In older versions, the default value was a non-valid identifier,
// so it was updated to a valid one. See Default.
Legacy = "secretKey"
// Default is the identifier of the default kms provider
// which fallbacks to Grafana's secret key. See the
// defaultprovider package for further information.
Default = "secretKey.v1"
)
type Service interface {
Provide() (map[string]secrets.Provider, error)
Provide() (map[secrets.ProviderID]secrets.Provider, error)
}

@ -20,12 +20,12 @@ func ProvideService(enc encryption.Internal, settings setting.Provider) Service
}
}
func (s Service) Provide() (map[string]secrets.Provider, error) {
func (s Service) Provide() (map[secrets.ProviderID]secrets.Provider, error) {
if !s.settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle) {
return nil, nil
}
return map[string]secrets.Provider{
return map[secrets.ProviderID]secrets.Provider{
kmsproviders.Default: grafana.New(s.settings, s.enc),
}, nil
}

@ -24,10 +24,10 @@ type SecretsService struct {
settings setting.Provider
usageStats usagestats.Service
currentProvider string
providers map[string]secrets.Provider
dataKeyCache map[string]dataKeyCacheItem
log log.Logger
currentProviderID secrets.ProviderID
providers map[secrets.ProviderID]secrets.Provider
dataKeyCache map[string]dataKeyCacheItem
log log.Logger
}
func ProvideSecretsService(
@ -44,27 +44,27 @@ func ProvideSecretsService(
logger := log.New("secrets")
enabled := settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle)
currentProvider := settings.KeyValue("security", "encryption_provider").MustString(kmsproviders.Default)
currentProviderID := readCurrentProviderID(settings)
if _, ok := providers[currentProvider]; enabled && !ok {
return nil, fmt.Errorf("missing configuration for current encryption provider %s", currentProvider)
if _, ok := providers[currentProviderID]; enabled && !ok {
return nil, fmt.Errorf("missing configuration for current encryption provider %s", currentProviderID)
}
if !enabled && currentProvider != kmsproviders.Default {
if !enabled && currentProviderID != kmsproviders.Default {
logger.Warn("Changing encryption provider requires enabling envelope encryption feature")
}
logger.Debug("Envelope encryption state", "enabled", enabled, "current provider", currentProvider)
logger.Debug("Envelope encryption state", "enabled", enabled, "current provider", currentProviderID)
s := &SecretsService{
store: store,
enc: enc,
settings: settings,
usageStats: usageStats,
providers: providers,
currentProvider: currentProvider,
dataKeyCache: make(map[string]dataKeyCacheItem),
log: logger,
store: store,
enc: enc,
settings: settings,
usageStats: usageStats,
providers: providers,
currentProviderID: currentProviderID,
dataKeyCache: make(map[string]dataKeyCacheItem),
log: logger,
}
s.registerUsageMetrics()
@ -72,15 +72,48 @@ func ProvideSecretsService(
return s, nil
}
func readCurrentProviderID(settings setting.Provider) secrets.ProviderID {
currentProvider := settings.KeyValue("security", "encryption_provider").MustString(kmsproviders.Default)
if currentProvider == kmsproviders.Legacy {
currentProvider = kmsproviders.Default
}
return secrets.ProviderID(currentProvider)
}
func (s *SecretsService) registerUsageMetrics() {
s.usageStats.RegisterMetricsFunc(func(context.Context) (map[string]interface{}, error) {
enabled := 0
usageMetrics := make(map[string]interface{})
// Enabled / disabled
usageMetrics["stats.encryption.envelope_encryption_enabled.count"] = 0
if s.settings.IsFeatureToggleEnabled(secrets.EnvelopeEncryptionFeatureToggle) {
enabled = 1
usageMetrics["stats.encryption.envelope_encryption_enabled.count"] = 1
}
// Current provider
kind, err := s.currentProviderID.Kind()
if err != nil {
return nil, err
}
usageMetrics[fmt.Sprintf("stats.encryption.current_provider.%s.count", kind)] = 1
// Count by kind
countByKind := make(map[string]int)
for id := range s.providers {
kind, err := id.Kind()
if err != nil {
return nil, err
}
countByKind[kind]++
}
return map[string]interface{}{
"stats.encryption.envelope_encryption_enabled.count": enabled,
}, nil
for kind, count := range countByKind {
usageMetrics[fmt.Sprintf(`stats.encryption.providers.%s.count`, kind)] = count
}
return usageMetrics, nil
})
}
@ -135,7 +168,7 @@ func (s *SecretsService) EncryptWithDBSession(ctx context.Context, payload []byt
}
func (s *SecretsService) keyName(scope string) string {
return fmt.Sprintf("%s/%s@%s", now().Format("2006-01-02"), scope, s.currentProvider)
return fmt.Sprintf("%s/%s@%s", now().Format("2006-01-02"), scope, s.currentProviderID)
}
func (s *SecretsService) Decrypt(ctx context.Context, payload []byte) ([]byte, error) {
@ -237,9 +270,9 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
if err != nil {
return nil, err
}
provider, exists := s.providers[s.currentProvider]
provider, exists := s.providers[s.currentProviderID]
if !exists {
return nil, fmt.Errorf("could not find encryption provider '%s'", s.currentProvider)
return nil, fmt.Errorf("could not find encryption provider '%s'", s.currentProviderID)
}
// 2. Encrypt it
@ -252,7 +285,7 @@ func (s *SecretsService) newDataKey(ctx context.Context, name string, scope stri
dek := secrets.DataKey{
Active: true, // TODO: right now we never mark a key as deactivated
Name: name,
Provider: s.currentProvider,
Provider: s.currentProviderID,
EncryptedData: encrypted,
Scope: scope,
}
@ -310,7 +343,7 @@ func (s *SecretsService) dataKey(ctx context.Context, name string) ([]byte, erro
return decrypted, nil
}
func (s *SecretsService) GetProviders() map[string]secrets.Provider {
func (s *SecretsService) GetProviders() map[secrets.ProviderID]secrets.Provider {
return s.providers
}

@ -87,6 +87,8 @@ func TestSecretsService_EnvelopeEncryption(t *testing.T) {
require.NoError(t, err)
assert.Equal(t, 1, reports.Metrics["stats.encryption.envelope_encryption_enabled.count"])
assert.Equal(t, 1, reports.Metrics["stats.encryption.current_provider.secretKey.count"])
assert.Equal(t, 1, reports.Metrics["stats.encryption.providers.secretKey.count"])
})
}
@ -159,7 +161,7 @@ func TestSecretsService_DataKeys(t *testing.T) {
func TestSecretsService_UseCurrentProvider(t *testing.T) {
t.Run("When encryption_provider is not specified explicitly, should use 'secretKey' as a current provider", func(t *testing.T) {
svc := SetupTestService(t, database.ProvideSecretsStore(sqlstore.InitTestDB(t)))
assert.Equal(t, "secretKey", svc.currentProvider)
assert.Equal(t, secrets.ProviderID("secretKey.v1"), svc.currentProviderID)
})
t.Run("Should use encrypt/decrypt methods of the current encryption provider", func(t *testing.T) {
@ -175,7 +177,7 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
raw, err := ini.Load([]byte(rawCfg))
require.NoError(t, err)
providerID := "fakeProvider.v1"
providerID := secrets.ProviderID("fakeProvider.v1")
settings := &setting.OSSImpl{
Cfg: &setting.Cfg{
Raw: raw,
@ -195,7 +197,7 @@ func TestSecretsService_UseCurrentProvider(t *testing.T) {
)
require.NoError(t, err)
assert.Equal(t, providerID, svcEncrypt.currentProvider)
assert.Equal(t, providerID, svcEncrypt.currentProviderID)
assert.Equal(t, 2, len(svcEncrypt.GetProviders()))
encrypted, _ := svcEncrypt.Encrypt(context.Background(), []byte{}, secrets.WithoutScope())
@ -244,7 +246,7 @@ func newFakeKMS(kms osskmsproviders.Service) fakeKMS {
}
}
func (f *fakeKMS) Provide() (map[string]secrets.Provider, error) {
func (f *fakeKMS) Provide() (map[secrets.ProviderID]secrets.Provider, error) {
providers, err := f.kms.Provide()
if err != nil {
return providers, err

@ -2,6 +2,8 @@ package secrets
import (
"context"
"fmt"
"strings"
"xorm.io/xorm"
)
@ -42,3 +44,16 @@ type Provider interface {
Encrypt(ctx context.Context, blob []byte) ([]byte, error)
Decrypt(ctx context.Context, blob []byte) ([]byte, error)
}
type ProviderID string
func (id ProviderID) Kind() (string, error) {
idStr := string(id)
parts := strings.SplitN(idStr, ".", 2)
if len(parts) != 2 {
return "", fmt.Errorf("malformatted provider identifier %s: expected format <provider>.<keyName>", idStr)
}
return parts[0], nil
}

@ -11,7 +11,7 @@ type DataKey struct {
Active bool
Name string
Scope string
Provider string
Provider ProviderID
EncryptedData []byte
Created time.Time
Updated time.Time

Loading…
Cancel
Save