Secrets: encryption encryption storage uses versioning (#108036)
* Secrets: delete unused FakeKeeper * Secrets: encrypted value storage stores versions * add version to span * trigger build * remove ineffectual assignment * lint * drop secret_encrypted_value.uid / add name and version columns
This commit is contained in:
@@ -13,16 +13,17 @@ type EncryptionManager interface {
|
||||
}
|
||||
|
||||
type EncryptedValue struct {
|
||||
UID string
|
||||
Namespace string
|
||||
Name string
|
||||
Version int64
|
||||
EncryptedData []byte
|
||||
Created int64
|
||||
Updated int64
|
||||
}
|
||||
|
||||
type EncryptedValueStorage interface {
|
||||
Create(ctx context.Context, namespace string, encryptedData []byte) (*EncryptedValue, error)
|
||||
Update(ctx context.Context, namespace string, uid string, encryptedData []byte) error
|
||||
Get(ctx context.Context, namespace string, uid string) (*EncryptedValue, error)
|
||||
Delete(ctx context.Context, namespace string, uid string) error
|
||||
Create(ctx context.Context, namespace, name string, version int64, encryptedData []byte) (*EncryptedValue, error)
|
||||
Update(ctx context.Context, namespace, name string, version int64, encryptedData []byte) error
|
||||
Get(ctx context.Context, namespace, name string, version int64) (*EncryptedValue, error)
|
||||
Delete(ctx context.Context, namespace, name string, version int64) error
|
||||
}
|
||||
|
||||
@@ -95,10 +95,10 @@ func (s ExternalID) String() string {
|
||||
|
||||
// Keeper is the interface for secret keepers.
|
||||
type Keeper interface {
|
||||
Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, exposedValueOrRef string) (ExternalID, error)
|
||||
Update(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID ExternalID, exposedValueOrRef string) error
|
||||
Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID ExternalID) (secretv1beta1.ExposedSecureValue, error)
|
||||
Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID ExternalID) error
|
||||
Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64, exposedValueOrRef string) (ExternalID, error)
|
||||
Update(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64, exposedValueOrRef string) error
|
||||
Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64) (secretv1beta1.ExposedSecureValue, error)
|
||||
Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64) error
|
||||
}
|
||||
|
||||
// Service is the interface for secret keeper services.
|
||||
|
||||
@@ -1,68 +0,0 @@
|
||||
package fakes
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
secretv1beta1 "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
)
|
||||
|
||||
var ErrSecretNotFound = errors.New("secret not found")
|
||||
|
||||
type FakeKeeper struct {
|
||||
values map[string]map[string]string
|
||||
}
|
||||
|
||||
var _ contracts.Keeper = (*FakeKeeper)(nil)
|
||||
|
||||
func NewFakeKeeper() *FakeKeeper {
|
||||
return &FakeKeeper{
|
||||
values: make(map[string]map[string]string),
|
||||
}
|
||||
}
|
||||
|
||||
func (s *FakeKeeper) Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, exposedValueOrRef string) (contracts.ExternalID, error) {
|
||||
ns, ok := s.values[namespace]
|
||||
if !ok {
|
||||
ns = make(map[string]string)
|
||||
}
|
||||
uid := uuid.New().String()
|
||||
ns[uid] = exposedValueOrRef
|
||||
s.values[namespace] = ns
|
||||
|
||||
return contracts.ExternalID(uid), nil
|
||||
}
|
||||
|
||||
func (s *FakeKeeper) Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID) (secretv1beta1.ExposedSecureValue, error) {
|
||||
ns, ok := s.values[namespace]
|
||||
if !ok {
|
||||
return "", ErrSecretNotFound
|
||||
}
|
||||
exposedVal, ok := ns[externalID.String()]
|
||||
if !ok {
|
||||
return "", ErrSecretNotFound
|
||||
}
|
||||
|
||||
return secretv1beta1.NewExposedSecureValue(exposedVal), nil
|
||||
}
|
||||
|
||||
func (s *FakeKeeper) Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *FakeKeeper) Update(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID, exposedValueOrRef string) error {
|
||||
ns, ok := s.values[namespace]
|
||||
if !ok {
|
||||
return ErrSecretNotFound
|
||||
}
|
||||
_, ok = ns[externalID.String()]
|
||||
if !ok {
|
||||
return ErrSecretNotFound
|
||||
}
|
||||
|
||||
ns[externalID.String()] = exposedValueOrRef
|
||||
return nil
|
||||
}
|
||||
@@ -36,8 +36,13 @@ func NewSQLKeeper(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *SQLKeeper) Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, exposedValueOrRef string) (contracts.ExternalID, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Store", trace.WithAttributes(attribute.String("namespace", namespace)))
|
||||
func (s *SQLKeeper) Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64, exposedValueOrRef string) (contracts.ExternalID, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Store",
|
||||
trace.WithAttributes(
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("name", name),
|
||||
attribute.Int64("version", version)),
|
||||
)
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
@@ -46,27 +51,28 @@ func (s *SQLKeeper) Store(ctx context.Context, cfg secretv1beta1.KeeperConfig, n
|
||||
return "", fmt.Errorf("unable to encrypt value: %w", err)
|
||||
}
|
||||
|
||||
encryptedVal, err := s.store.Create(ctx, namespace, encryptedData)
|
||||
_, err = s.store.Create(ctx, namespace, name, version, encryptedData)
|
||||
if err != nil {
|
||||
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
|
||||
// An external id is not required to interact with the sql keeper.
|
||||
// An empty string is returned just to comply with the Keeper interface.
|
||||
return contracts.ExternalID(""), nil
|
||||
}
|
||||
|
||||
func (s *SQLKeeper) Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID) (secretv1beta1.ExposedSecureValue, error) {
|
||||
func (s *SQLKeeper) Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64) (secretv1beta1.ExposedSecureValue, error) {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Expose", trace.WithAttributes(
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("externalID", externalID.String()),
|
||||
attribute.String("name", name),
|
||||
attribute.Int64("version", version),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
encryptedValue, err := s.store.Get(ctx, namespace, externalID.String())
|
||||
encryptedValue, err := s.store.Get(ctx, namespace, name, version)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("unable to get encrypted value: %w", err)
|
||||
}
|
||||
@@ -82,15 +88,16 @@ func (s *SQLKeeper) Expose(ctx context.Context, cfg secretv1beta1.KeeperConfig,
|
||||
return exposedValue, nil
|
||||
}
|
||||
|
||||
func (s *SQLKeeper) Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID) error {
|
||||
func (s *SQLKeeper) Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64) error {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Delete", trace.WithAttributes(
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("externalID", externalID.String()),
|
||||
attribute.String("name", name),
|
||||
attribute.Int64("version", version),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
start := time.Now()
|
||||
err := s.store.Delete(ctx, namespace, externalID.String())
|
||||
err := s.store.Delete(ctx, namespace, name, version)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to delete encrypted value: %w", err)
|
||||
}
|
||||
@@ -100,10 +107,11 @@ func (s *SQLKeeper) Delete(ctx context.Context, cfg secretv1beta1.KeeperConfig,
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *SQLKeeper) Update(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace string, externalID contracts.ExternalID, exposedValueOrRef string) error {
|
||||
func (s *SQLKeeper) Update(ctx context.Context, cfg secretv1beta1.KeeperConfig, namespace, name string, version int64, exposedValueOrRef string) error {
|
||||
ctx, span := s.tracer.Start(ctx, "SQLKeeper.Update", trace.WithAttributes(
|
||||
attribute.String("namespace", namespace),
|
||||
attribute.String("externalID", externalID.String()),
|
||||
attribute.String("name", name),
|
||||
attribute.Int64("version", version),
|
||||
))
|
||||
defer span.End()
|
||||
|
||||
@@ -113,7 +121,7 @@ func (s *SQLKeeper) Update(ctx context.Context, cfg secretv1beta1.KeeperConfig,
|
||||
return fmt.Errorf("unable to encrypt value: %w", err)
|
||||
}
|
||||
|
||||
err = s.store.Update(ctx, namespace, externalID.String(), encryptedData)
|
||||
err = s.store.Update(ctx, namespace, name, version, encryptedData)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to update encrypted value: %w", err)
|
||||
}
|
||||
|
||||
@@ -1,23 +1,13 @@
|
||||
package sqlkeeper
|
||||
package sqlkeeper_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"go.opentelemetry.io/otel/trace/noop"
|
||||
|
||||
secretv1beta1 "github.com/grafana/grafana/apps/secret/pkg/apis/secret/v1beta1"
|
||||
"github.com/grafana/grafana/pkg/infra/usagestats"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
encryptionmanager "github.com/grafana/grafana/pkg/registry/apis/secret/encryption/manager"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/setting"
|
||||
"github.com/grafana/grafana/pkg/storage/secret/database"
|
||||
encryptionstorage "github.com/grafana/grafana/pkg/storage/secret/encryption"
|
||||
"github.com/grafana/grafana/pkg/storage/secret/migrator"
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/testutils"
|
||||
"github.com/grafana/grafana/pkg/tests/testsuite"
|
||||
)
|
||||
|
||||
@@ -26,159 +16,133 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func Test_SQLKeeperSetup(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
namespace1 := "namespace1"
|
||||
name1 := "name1"
|
||||
version1 := int64(1)
|
||||
namespace2 := "namespace2"
|
||||
name2 := "name2"
|
||||
plaintext1 := "very secret string in namespace 1"
|
||||
plaintext2 := "very secret string in namespace 2"
|
||||
nonExistentID := contracts.ExternalID("non existent")
|
||||
|
||||
cfg := &setting.Cfg{
|
||||
SecretsManagement: setting.SecretsManagerSettings{
|
||||
SecretKey: "sdDkslslld",
|
||||
EncryptionProvider: "secretKey.v1",
|
||||
},
|
||||
}
|
||||
|
||||
sqlKeeper, err := setupTestService(t, cfg)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, sqlKeeper)
|
||||
|
||||
keeperCfg := &secretv1beta1.SystemKeeperConfig{}
|
||||
|
||||
t.Run("storing an encrypted value returns no error", func(t *testing.T) {
|
||||
externalId1, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
externalId2, err := sqlKeeper.Store(ctx, keeperCfg, namespace2, plaintext2)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
_, err = sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace2, name2, version1, plaintext2)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId2)
|
||||
|
||||
t.Run("expose the encrypted value from existing namespace", func(t *testing.T) {
|
||||
exposedVal1, err := sqlKeeper.Expose(ctx, keeperCfg, namespace1, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal1, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace1, name1, version1)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, exposedVal1)
|
||||
assert.Equal(t, plaintext1, exposedVal1.DangerouslyExposeAndConsumeValue())
|
||||
|
||||
exposedVal2, err := sqlKeeper.Expose(ctx, keeperCfg, namespace2, externalId2)
|
||||
_, err = sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace2, name2, version1, plaintext2)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal2, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace2, name2, version1)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, exposedVal2)
|
||||
assert.Equal(t, plaintext2, exposedVal2.DangerouslyExposeAndConsumeValue())
|
||||
})
|
||||
|
||||
t.Run("expose encrypted value from different namespace returns error", func(t *testing.T) {
|
||||
exposedVal, err := sqlKeeper.Expose(ctx, keeperCfg, namespace2, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
_, err = sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace2, name1, version1)
|
||||
require.Error(t, err)
|
||||
assert.Empty(t, exposedVal)
|
||||
|
||||
exposedVal, err = sqlKeeper.Expose(ctx, keeperCfg, namespace1, externalId2)
|
||||
exposedVal, err = sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace1, name2, version1)
|
||||
require.Error(t, err)
|
||||
assert.Empty(t, exposedVal)
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("storing same value in same namespace returns no error", func(t *testing.T) {
|
||||
externalId1, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId1)
|
||||
t.Run("storing same value in same namespace returns error", func(t *testing.T) {
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
externalId2, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId2)
|
||||
|
||||
assert.NotEqual(t, externalId1, externalId2)
|
||||
_, err = sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NotNil(t, err)
|
||||
})
|
||||
|
||||
t.Run("storing same value in different namespace returns no error", func(t *testing.T) {
|
||||
externalId1, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
externalId2, err := sqlKeeper.Store(ctx, keeperCfg, namespace2, plaintext1)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId2)
|
||||
|
||||
assert.NotEqual(t, externalId1, externalId2)
|
||||
_, err = sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace2, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("exposing non existing values returns error", func(t *testing.T) {
|
||||
exposedVal, err := sqlKeeper.Expose(ctx, keeperCfg, namespace1, nonExistentID)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
exposedVal, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace1, "non_existing_name", version1)
|
||||
require.Error(t, err)
|
||||
assert.Empty(t, exposedVal)
|
||||
})
|
||||
|
||||
t.Run("deleting an existing encrypted value does not return error", func(t *testing.T) {
|
||||
externalID, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalID)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
exposedVal, err := sqlKeeper.Expose(ctx, keeperCfg, namespace1, externalID)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace1, name1, version1)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, exposedVal)
|
||||
assert.Equal(t, plaintext1, exposedVal.DangerouslyExposeAndConsumeValue())
|
||||
|
||||
err = sqlKeeper.Delete(ctx, keeperCfg, namespace1, externalID)
|
||||
err = sut.SQLKeeper.Delete(t.Context(), keeperCfg, namespace1, name1, version1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("deleting an non existing encrypted value does not return error", func(t *testing.T) {
|
||||
err = sqlKeeper.Delete(ctx, keeperCfg, namespace1, nonExistentID)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
err := sut.SQLKeeper.Delete(t.Context(), keeperCfg, namespace1, "non_existing_name", version1)
|
||||
require.NoError(t, err)
|
||||
})
|
||||
|
||||
t.Run("updating an existent encrypted value returns no error", func(t *testing.T) {
|
||||
externalId1, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
err = sqlKeeper.Update(ctx, keeperCfg, namespace1, externalId1, plaintext2)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal, err := sqlKeeper.Expose(ctx, keeperCfg, namespace1, externalId1)
|
||||
err = sut.SQLKeeper.Update(t.Context(), keeperCfg, namespace1, name1, version1, plaintext2)
|
||||
require.NoError(t, err)
|
||||
|
||||
exposedVal, err := sut.SQLKeeper.Expose(t.Context(), keeperCfg, namespace1, name1, version1)
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, exposedVal)
|
||||
assert.Equal(t, plaintext2, exposedVal.DangerouslyExposeAndConsumeValue())
|
||||
})
|
||||
|
||||
t.Run("updating a non existent encrypted value returns error", func(t *testing.T) {
|
||||
externalId1, err := sqlKeeper.Store(ctx, keeperCfg, namespace1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, externalId1)
|
||||
sut := testutils.Setup(t)
|
||||
|
||||
err = sqlKeeper.Update(ctx, nil, namespace1, nonExistentID, plaintext2)
|
||||
_, err := sut.SQLKeeper.Store(t.Context(), keeperCfg, namespace1, name1, version1, plaintext1)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = sut.SQLKeeper.Update(t.Context(), nil, namespace1, "non_existing_name", version1, plaintext2)
|
||||
require.Error(t, err)
|
||||
})
|
||||
}
|
||||
|
||||
func setupTestService(t *testing.T, cfg *setting.Cfg) (*SQLKeeper, error) {
|
||||
testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New()))
|
||||
tracer := noop.NewTracerProvider().Tracer("test")
|
||||
database := database.ProvideDatabase(testDB, tracer)
|
||||
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
|
||||
// Initialize the encryption manager
|
||||
dataKeyStore, err := encryptionstorage.ProvideDataKeyStorage(database, tracer, features, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
usageStats := &usagestats.UsageStatsMock{T: t}
|
||||
|
||||
encMgr, err := encryptionmanager.ProvideEncryptionManager(
|
||||
tracer,
|
||||
dataKeyStore,
|
||||
cfg,
|
||||
usageStats,
|
||||
nil,
|
||||
)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize encrypted value storage with a fake db
|
||||
encValueStore, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer, features)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize the SQLKeeper
|
||||
sqlKeeper := NewSQLKeeper(tracer, encMgr, encValueStore, nil)
|
||||
|
||||
return sqlKeeper, nil
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv
|
||||
defer span.End()
|
||||
|
||||
if newSecureValue.Spec.Value == nil {
|
||||
decrypted, err := s.secureValueMetadataStorage.ReadForDecrypt(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name)
|
||||
currentVersion, err := s.secureValueMetadataStorage.Read(ctx, xkube.Namespace(newSecureValue.Namespace), newSecureValue.Name, contracts.ReadOpts{})
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("reading secure value secret: %+w", err)
|
||||
}
|
||||
@@ -77,7 +77,7 @@ func (s *SecureValueService) Update(ctx context.Context, newSecureValue *secretv
|
||||
}
|
||||
logging.FromContext(ctx).Debug("retrieved keeper", "namespace", newSecureValue.Namespace, "keeperName", newSecureValue.Spec.Keeper, "type", keeperCfg.Type())
|
||||
|
||||
secret, err := keeper.Expose(ctx, keeperCfg, newSecureValue.Namespace, contracts.ExternalID(decrypted.ExternalID))
|
||||
secret, err := keeper.Expose(ctx, keeperCfg, newSecureValue.Namespace, newSecureValue.Name, currentVersion.Status.Version)
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("reading secret value from keeper: %w", err)
|
||||
}
|
||||
@@ -100,31 +100,31 @@ func (s *SecureValueService) createNewVersion(ctx context.Context, sv *secretv1b
|
||||
}
|
||||
|
||||
// TODO: does this need to be for update?
|
||||
keeperCfg, err := s.keeperMetadataStorage.GetKeeperConfig(ctx, sv.Namespace, sv.Spec.Keeper, contracts.ReadOpts{ForUpdate: true})
|
||||
keeperCfg, err := s.keeperMetadataStorage.GetKeeperConfig(ctx, createdSv.Namespace, createdSv.Spec.Keeper, contracts.ReadOpts{ForUpdate: true})
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("fetching keeper config: namespace=%+v keeperName=%+v %w", sv.Namespace, sv.Spec.Keeper, err)
|
||||
return nil, fmt.Errorf("fetching keeper config: namespace=%+v keeperName=%+v %w", createdSv.Namespace, createdSv.Spec.Keeper, err)
|
||||
}
|
||||
|
||||
keeper, err := s.keeperService.KeeperForConfig(keeperCfg)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", sv.Namespace, sv.Spec.Keeper, err)
|
||||
return nil, fmt.Errorf("getting keeper for config: namespace=%+v keeperName=%+v %w", createdSv.Namespace, createdSv.Spec.Keeper, err)
|
||||
}
|
||||
logging.FromContext(ctx).Debug("retrieved keeper", "namespace", sv.Namespace, "keeperName", sv.Spec.Keeper, "type", keeperCfg.Type())
|
||||
logging.FromContext(ctx).Debug("retrieved keeper", "namespace", createdSv.Namespace, "keeperName", createdSv.Spec.Keeper, "type", keeperCfg.Type())
|
||||
|
||||
// TODO: can we stop using external id?
|
||||
// TODO: store uses only the namespace and returns and id. It could be a kv instead.
|
||||
// TODO: check that the encrypted store works with multiple versions
|
||||
externalID, err := keeper.Store(ctx, keeperCfg, sv.Namespace, sv.Spec.Value.DangerouslyExposeAndConsumeValue())
|
||||
externalID, err := keeper.Store(ctx, keeperCfg, createdSv.Namespace, createdSv.Name, createdSv.Status.Version, sv.Spec.Value.DangerouslyExposeAndConsumeValue())
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("storing secure value in keeper: %w", err)
|
||||
}
|
||||
createdSv.Status.ExternalID = string(externalID)
|
||||
|
||||
if err := s.secureValueMetadataStorage.SetExternalID(ctx, xkube.Namespace(sv.Namespace), sv.Name, createdSv.Status.Version, externalID); err != nil {
|
||||
if err := s.secureValueMetadataStorage.SetExternalID(ctx, xkube.Namespace(createdSv.Namespace), createdSv.Name, createdSv.Status.Version, externalID); err != nil {
|
||||
return nil, fmt.Errorf("setting secure value external id: %w", err)
|
||||
}
|
||||
|
||||
if err := s.secureValueMetadataStorage.SetVersionToActive(ctx, xkube.Namespace(sv.Namespace), sv.Name, createdSv.Status.Version); err != nil {
|
||||
if err := s.secureValueMetadataStorage.SetVersionToActive(ctx, xkube.Namespace(createdSv.Namespace), createdSv.Name, createdSv.Status.Version); err != nil {
|
||||
return nil, fmt.Errorf("marking secure value version as active: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -101,10 +101,10 @@ func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Initialize encrypted value storage with a fake db
|
||||
encValueStore, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer, features)
|
||||
encryptedValueStorage, err := encryptionstorage.ProvideEncryptedValueStorage(database, tracer, features)
|
||||
require.NoError(t, err)
|
||||
|
||||
sqlKeeper := sqlkeeper.NewSQLKeeper(tracer, encryptionManager, encValueStore, nil)
|
||||
sqlKeeper := sqlkeeper.NewSQLKeeper(tracer, encryptionManager, encryptedValueStorage, nil)
|
||||
|
||||
var keeperService contracts.KeeperService = newKeeperServiceWrapper(sqlKeeper)
|
||||
|
||||
@@ -124,9 +124,11 @@ func Setup(t *testing.T, opts ...func(*SetupConfig)) Sut {
|
||||
return Sut{
|
||||
SecureValueService: secureValueService,
|
||||
SecureValueMetadataStorage: secureValueMetadataStorage,
|
||||
Database: database,
|
||||
DecryptStorage: decryptStorage,
|
||||
DecryptService: decryptService,
|
||||
EncryptedValueStorage: encryptedValueStorage,
|
||||
SQLKeeper: sqlKeeper,
|
||||
Database: database,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -135,6 +137,8 @@ type Sut struct {
|
||||
SecureValueMetadataStorage contracts.SecureValueMetadataStorage
|
||||
DecryptStorage contracts.DecryptStorage
|
||||
DecryptService service.DecryptService
|
||||
EncryptedValueStorage contracts.EncryptedValueStorage
|
||||
SQLKeeper *sqlkeeper.SQLKeeper
|
||||
Database *database.Database
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user