SecretsManager: Introduce metrics and logs (#107582)
Co-authored-by: Michael Mandrus <michael.mandrus@grafana.com>
This commit is contained in:
co-authored by
Michael Mandrus
parent
66d9a33cc9
commit
a59ec345c2
@@ -77,7 +77,7 @@ func TestEncryptionService_DataKeys(t *testing.T) {
|
||||
testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New()))
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
tracer := noop.NewTracerProvider().Tracer("test")
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features)
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
ctx := context.Background()
|
||||
@@ -183,7 +183,7 @@ func TestEncryptionService_UseCurrentProvider(t *testing.T) {
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New()))
|
||||
tracer := noop.NewTracerProvider().Tracer("test")
|
||||
encryptionStore, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features)
|
||||
encryptionStore, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
encMgr, err := ProvideEncryptionManager(
|
||||
@@ -374,7 +374,7 @@ func TestIntegration_SecretsService(t *testing.T) {
|
||||
EncryptionProvider: "secretKey.v1",
|
||||
},
|
||||
}
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features)
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database.ProvideDatabase(testDB, tracer), tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
usageStats := &usagestats.UsageStatsMock{T: t}
|
||||
|
||||
@@ -31,7 +31,7 @@ func setupTestService(tb testing.TB) *EncryptionManager {
|
||||
EncryptionProvider: "secretKey.v1",
|
||||
},
|
||||
}
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features)
|
||||
store, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features, nil)
|
||||
require.NoError(tb, err)
|
||||
|
||||
usageStats := &usagestats.UsageStatsMock{T: tb}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
const (
|
||||
namespace = "grafana_secrets_manager"
|
||||
subsystem = "keeper"
|
||||
)
|
||||
|
||||
// KeeperMetrics is a struct that contains all the metrics for an implementation of all keepers.
|
||||
type KeeperMetrics struct {
|
||||
StoreDuration *prometheus.HistogramVec
|
||||
UpdateDuration *prometheus.HistogramVec
|
||||
ExposeDuration *prometheus.HistogramVec
|
||||
DeleteDuration *prometheus.HistogramVec
|
||||
}
|
||||
|
||||
func newKeeperMetrics() *KeeperMetrics {
|
||||
return &KeeperMetrics{
|
||||
StoreDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "store_duration_seconds",
|
||||
Help: "Duration of keeper store operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"keeper_type"}),
|
||||
UpdateDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "update_duration_seconds",
|
||||
Help: "Duration of keeper update operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"keeper_type"}),
|
||||
ExposeDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "expose_duration_seconds",
|
||||
Help: "Duration of keeper expose operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"keeper_type"}),
|
||||
DeleteDuration: prometheus.NewHistogramVec(prometheus.HistogramOpts{
|
||||
Namespace: namespace,
|
||||
Subsystem: subsystem,
|
||||
Name: "delete_duration_seconds",
|
||||
Help: "Duration of keeper delete operations",
|
||||
Buckets: prometheus.DefBuckets,
|
||||
}, []string{"keeper_type"}),
|
||||
}
|
||||
}
|
||||
|
||||
// NewKeeperMetrics creates a new KeeperMetrics struct containing registered metrics
|
||||
func NewKeeperMetrics(reg prometheus.Registerer) *KeeperMetrics {
|
||||
m := newKeeperMetrics()
|
||||
|
||||
if reg != nil {
|
||||
reg.MustRegister(
|
||||
m.StoreDuration,
|
||||
m.UpdateDuration,
|
||||
m.ExposeDuration,
|
||||
m.DeleteDuration,
|
||||
)
|
||||
}
|
||||
|
||||
return m
|
||||
}
|
||||
|
||||
func NewTestMetrics() *KeeperMetrics {
|
||||
return newKeeperMetrics()
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/secretkeeper/sqlkeeper"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
)
|
||||
|
||||
// OSSKeeperService is the OSS implementation of the Service interface.
|
||||
@@ -19,10 +20,11 @@ func ProvideService(
|
||||
tracer trace.Tracer,
|
||||
store contracts.EncryptedValueStorage,
|
||||
encryptionManager contracts.EncryptionManager,
|
||||
reg prometheus.Registerer,
|
||||
) (*OSSKeeperService, error) {
|
||||
return &OSSKeeperService{
|
||||
// TODO: rename to system keeper or something like that
|
||||
systemKeeper: sqlkeeper.NewSQLKeeper(tracer, encryptionManager, store),
|
||||
systemKeeper: sqlkeeper.NewSQLKeeper(tracer, encryptionManager, store, reg),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ func setupTestService(t *testing.T, cfg *setting.Cfg) (*OSSKeeperService, error)
|
||||
database := database.ProvideDatabase(testDB, tracer)
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
|
||||
dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features)
|
||||
dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
encValueStore, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer, features)
|
||||
@@ -59,7 +59,7 @@ func setupTestService(t *testing.T, cfg *setting.Cfg) (*OSSKeeperService, error)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the keeper service
|
||||
keeperService, err := ProvideService(tracer, encValueStore, encryptionManager)
|
||||
keeperService, err := ProvideService(tracer, encValueStore, encryptionManager, nil)
|
||||
|
||||
return keeperService, err
|
||||
}
|
||||
|
||||
@@ -3,9 +3,12 @@ package sqlkeeper
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
secretv0alpha1 "github.com/grafana/grafana/pkg/apis/secret/v0alpha1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/secretkeeper/metrics"
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"go.opentelemetry.io/otel/attribute"
|
||||
"go.opentelemetry.io/otel/trace"
|
||||
)
|
||||
@@ -14,6 +17,7 @@ type SQLKeeper struct {
|
||||
tracer trace.Tracer
|
||||
encryptionManager contracts.EncryptionManager
|
||||
store contracts.EncryptedValueStorage
|
||||
metrics *metrics.KeeperMetrics
|
||||
}
|
||||
|
||||
var _ contracts.Keeper = (*SQLKeeper)(nil)
|
||||
@@ -22,19 +26,21 @@ func NewSQLKeeper(
|
||||
tracer trace.Tracer,
|
||||
encryptionManager contracts.EncryptionManager,
|
||||
store contracts.EncryptedValueStorage,
|
||||
reg prometheus.Registerer,
|
||||
) *SQLKeeper {
|
||||
return &SQLKeeper{
|
||||
tracer: tracer,
|
||||
encryptionManager: encryptionManager,
|
||||
store: store,
|
||||
metrics: metrics.NewKeeperMetrics(reg),
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: parameter cfg is not being used
|
||||
func (s *SQLKeeper) Store(ctx context.Context, _ secretv0alpha1.KeeperConfig, namespace string, exposedValueOrRef string) (contracts.ExternalID, error) {
|
||||
func (s *SQLKeeper) Store(ctx context.Context, cfg secretv0alpha1.KeeperConfig, namespace string, exposedValueOrRef string) (contracts.ExternalID, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Store", trace.WithAttributes(attribute.String("namespace", namespace)))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
encryptedData, err := s.encryptionManager.Encrypt(ctx, namespace, []byte(exposedValueOrRef))
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to encrypt value: %w", err)
|
||||
@@ -45,8 +51,8 @@ func (s *SQLKeeper) Store(ctx context.Context, _ secretv0alpha1.KeeperConfig, na
|
||||
return "", fmt.Errorf("unable to store encrypted value: %w", err)
|
||||
}
|
||||
|
||||
s.metrics.StoreDuration.WithLabelValues(string(cfg.Type())).Observe(time.Since(start).Seconds())
|
||||
externalID := contracts.ExternalID(encryptedVal.UID)
|
||||
|
||||
span.SetAttributes(attribute.String("externalID", externalID.String()))
|
||||
|
||||
return externalID, nil
|
||||
@@ -59,6 +65,7 @@ func (s *SQLKeeper) Expose(ctx context.Context, cfg secretv0alpha1.KeeperConfig,
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
encryptedValue, err := s.store.Get(ctx, namespace, externalID.String())
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get encrypted value: %w", err)
|
||||
@@ -70,6 +77,8 @@ func (s *SQLKeeper) Expose(ctx context.Context, cfg secretv0alpha1.KeeperConfig,
|
||||
}
|
||||
|
||||
exposedValue := secretv0alpha1.NewExposedSecureValue(string(exposedBytes))
|
||||
s.metrics.ExposeDuration.WithLabelValues(string(cfg.Type())).Observe(time.Since(start).Seconds())
|
||||
|
||||
return exposedValue, nil
|
||||
}
|
||||
|
||||
@@ -80,10 +89,14 @@ func (s *SQLKeeper) Delete(ctx context.Context, cfg secretv0alpha1.KeeperConfig,
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
err := s.store.Delete(ctx, namespace, externalID.String())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete encrypted value: %w", err)
|
||||
}
|
||||
|
||||
s.metrics.DeleteDuration.WithLabelValues(string(cfg.Type())).Observe(time.Since(start).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -94,6 +107,7 @@ func (s *SQLKeeper) Update(ctx context.Context, cfg secretv0alpha1.KeeperConfig,
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
encryptedData, err := s.encryptionManager.Encrypt(ctx, namespace, []byte(exposedValueOrRef))
|
||||
if err != nil {
|
||||
return fmt.Errorf("unable to encrypt value: %w", err)
|
||||
@@ -103,5 +117,8 @@ func (s *SQLKeeper) Update(ctx context.Context, cfg secretv0alpha1.KeeperConfig,
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update encrypted value: %w", err)
|
||||
}
|
||||
|
||||
s.metrics.UpdateDuration.WithLabelValues(string(cfg.Type())).Observe(time.Since(start).Seconds())
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func setupTestService(t *testing.T, cfg *setting.Cfg) (*SQLKeeper, error) {
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
|
||||
// Initialize the encryption manager
|
||||
dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features)
|
||||
dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
usageStats := &usagestats.UsageStatsMock{T: t}
|
||||
@@ -178,7 +178,7 @@ func setupTestService(t *testing.T, cfg *setting.Cfg) (*SQLKeeper, error) {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the SQLKeeper
|
||||
sqlKeeper := NewSQLKeeper(tracer, encMgr, encValueStore)
|
||||
sqlKeeper := NewSQLKeeper(tracer, encMgr, encValueStore, nil)
|
||||
|
||||
return sqlKeeper, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user