mirror of
https://github.com/grafana/grafana.git
synced 2025-08-06 09:39:24 +08:00
SecretsManager: Add encrypted value store (#106607)
* SecretsManager: add encrypted value store Co-authored-by: Dana Axinte <53751979+dana-axinte@users.noreply.github.com> Co-authored-by: Leandro Deveikis <leandro.deveikis@gmail.com> Co-authored-by: Matheus Macabu <macabu@users.noreply.github.com> Co-authored-by: PoorlyDefinedBehaviour <brunotj2015@hotmail.com> * SecretsManager: wiring of encrypted value store --------- Co-authored-by: Leandro Deveikis <leandro.deveikis@gmail.com> Co-authored-by: Matheus Macabu <macabu@users.noreply.github.com> Co-authored-by: PoorlyDefinedBehaviour <brunotj2015@hotmail.com>
This commit is contained in:
@ -0,0 +1,13 @@
|
||||
INSERT INTO {{ .Ident "secret_encrypted_value" }} (
|
||||
{{ .Ident "uid" }},
|
||||
{{ .Ident "namespace" }},
|
||||
{{ .Ident "encrypted_data" }},
|
||||
{{ .Ident "created" }},
|
||||
{{ .Ident "updated" }}
|
||||
) VALUES (
|
||||
{{ .Arg .Row.UID }},
|
||||
{{ .Arg .Row.Namespace }},
|
||||
{{ .Arg .Row.EncryptedData }},
|
||||
{{ .Arg .Row.Created }},
|
||||
{{ .Arg .Row.Updated }}
|
||||
);
|
@ -0,0 +1,4 @@
|
||||
DELETE FROM {{ .Ident "secret_encrypted_value" }}
|
||||
WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND
|
||||
{{ .Ident "uid" }} = {{ .Arg .UID }}
|
||||
;
|
11
pkg/storage/secret/encryption/data/encrypted_value_read.sql
Normal file
11
pkg/storage/secret/encryption/data/encrypted_value_read.sql
Normal file
@ -0,0 +1,11 @@
|
||||
SELECT
|
||||
{{ .Ident "uid" }},
|
||||
{{ .Ident "namespace" }},
|
||||
{{ .Ident "encrypted_data" }},
|
||||
{{ .Ident "created" }},
|
||||
{{ .Ident "updated" }}
|
||||
FROM
|
||||
{{ .Ident "secret_encrypted_value" }}
|
||||
WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND
|
||||
{{ .Ident "uid" }} = {{ .Arg .UID }}
|
||||
;
|
@ -0,0 +1,8 @@
|
||||
UPDATE
|
||||
{{ .Ident "secret_encrypted_value" }}
|
||||
SET
|
||||
{{ .Ident "encrypted_data" }} = {{ .Arg .EncryptedData }},
|
||||
{{ .Ident "updated" }} = {{ .Arg .Updated }}
|
||||
WHERE {{ .Ident "namespace" }} = {{ .Arg .Namespace }} AND
|
||||
{{ .Ident "uid" }} = {{ .Arg .UID }}
|
||||
;
|
15
pkg/storage/secret/encryption/encrypted_value_model.go
Normal file
15
pkg/storage/secret/encryption/encrypted_value_model.go
Normal file
@ -0,0 +1,15 @@
|
||||
package encryption
|
||||
|
||||
import "github.com/grafana/grafana/pkg/storage/secret/migrator"
|
||||
|
||||
type EncryptedValue struct {
|
||||
UID string
|
||||
Namespace string
|
||||
EncryptedData []byte
|
||||
Created int64
|
||||
Updated int64
|
||||
}
|
||||
|
||||
func (*EncryptedValue) TableName() string {
|
||||
return migrator.TableNameEncryptedValue
|
||||
}
|
159
pkg/storage/secret/encryption/encrypted_value_store.go
Normal file
159
pkg/storage/secret/encryption/encrypted_value_store.go
Normal file
@ -0,0 +1,159 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
|
||||
"github.com/grafana/grafana/pkg/registry/apis/secret/contracts"
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrEncryptedValueNotFound = errors.New("encrypted value not found")
|
||||
)
|
||||
|
||||
func ProvideEncryptedValueStorage(db contracts.Database, features featuremgmt.FeatureToggles) (contracts.EncryptedValueStorage, error) {
|
||||
if !features.IsEnabledGlobally(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs) ||
|
||||
!features.IsEnabledGlobally(featuremgmt.FlagSecretsManagementAppPlatform) {
|
||||
return &encryptedValStorage{}, nil
|
||||
}
|
||||
|
||||
return &encryptedValStorage{
|
||||
db: db,
|
||||
dialect: sqltemplate.DialectForDriver(db.DriverName()),
|
||||
}, nil
|
||||
}
|
||||
|
||||
type encryptedValStorage struct {
|
||||
db contracts.Database
|
||||
dialect sqltemplate.Dialect
|
||||
}
|
||||
|
||||
func (s *encryptedValStorage) Create(ctx context.Context, namespace string, encryptedData []byte) (*contracts.EncryptedValue, error) {
|
||||
createdTime := time.Now().Unix()
|
||||
encryptedValue := &EncryptedValue{
|
||||
UID: uuid.New().String(),
|
||||
Namespace: namespace,
|
||||
EncryptedData: encryptedData,
|
||||
Created: createdTime,
|
||||
Updated: createdTime,
|
||||
}
|
||||
|
||||
req := createEncryptedValue{
|
||||
SQLTemplate: sqltemplate.New(s.dialect),
|
||||
Row: encryptedValue,
|
||||
}
|
||||
query, err := sqltemplate.Execute(sqlEncryptedValueCreate, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("executing template %q: %w", sqlEncryptedValueCreate.Name(), err)
|
||||
}
|
||||
|
||||
res, err := s.db.ExecContext(ctx, query, req.GetArgs()...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("inserting row: %w", err)
|
||||
}
|
||||
|
||||
if rowsAffected, err := res.RowsAffected(); err != nil {
|
||||
return nil, fmt.Errorf("getting rows affected: %w", err)
|
||||
} else if rowsAffected != 1 {
|
||||
return nil, fmt.Errorf("expected 1 row affected, got %d", rowsAffected)
|
||||
}
|
||||
|
||||
return &contracts.EncryptedValue{
|
||||
UID: encryptedValue.UID,
|
||||
Namespace: encryptedValue.Namespace,
|
||||
EncryptedData: encryptedValue.EncryptedData,
|
||||
Created: encryptedValue.Created,
|
||||
Updated: encryptedValue.Updated,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *encryptedValStorage) Update(ctx context.Context, namespace string, uid string, encryptedData []byte) error {
|
||||
req := updateEncryptedValue{
|
||||
SQLTemplate: sqltemplate.New(s.dialect),
|
||||
Namespace: namespace,
|
||||
UID: uid,
|
||||
EncryptedData: encryptedData,
|
||||
Updated: time.Now().Unix(),
|
||||
}
|
||||
|
||||
query, err := sqltemplate.Execute(sqlEncryptedValueUpdate, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("executing template %q: %w", sqlEncryptedValueUpdate.Name(), err)
|
||||
}
|
||||
|
||||
res, err := s.db.ExecContext(ctx, query, req.GetArgs()...)
|
||||
if err != nil {
|
||||
return fmt.Errorf("updating row: %w", err)
|
||||
}
|
||||
|
||||
if rowsAffected, err := res.RowsAffected(); err != nil {
|
||||
return fmt.Errorf("getting rows affected: %w", err)
|
||||
} else if rowsAffected != 1 {
|
||||
return fmt.Errorf("expected 1 row affected, got %d on %s", rowsAffected, namespace)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *encryptedValStorage) Get(ctx context.Context, namespace string, uid string) (*contracts.EncryptedValue, error) {
|
||||
req := &readEncryptedValue{
|
||||
SQLTemplate: sqltemplate.New(s.dialect),
|
||||
Namespace: namespace,
|
||||
UID: uid,
|
||||
}
|
||||
query, err := sqltemplate.Execute(sqlEncryptedValueRead, req)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("executing template %q: %w", sqlEncryptedValueRead.Name(), err)
|
||||
}
|
||||
|
||||
rows, err := s.db.QueryContext(ctx, query, req.GetArgs()...)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("getting row: %w", err)
|
||||
}
|
||||
defer func() { _ = rows.Close() }()
|
||||
|
||||
if !rows.Next() {
|
||||
return nil, ErrEncryptedValueNotFound
|
||||
}
|
||||
|
||||
var encryptedValue EncryptedValue
|
||||
err = rows.Scan(&encryptedValue.UID, &encryptedValue.Namespace, &encryptedValue.EncryptedData, &encryptedValue.Created, &encryptedValue.Updated)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to scan encrypted value row: %w", err)
|
||||
}
|
||||
if err := rows.Err(); err != nil {
|
||||
return nil, fmt.Errorf("read rows error: %w", err)
|
||||
}
|
||||
|
||||
return &contracts.EncryptedValue{
|
||||
UID: encryptedValue.UID,
|
||||
Namespace: encryptedValue.Namespace,
|
||||
EncryptedData: encryptedValue.EncryptedData,
|
||||
Created: encryptedValue.Created,
|
||||
Updated: encryptedValue.Updated,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (s *encryptedValStorage) Delete(ctx context.Context, namespace string, uid string) error {
|
||||
req := deleteEncryptedValue{
|
||||
SQLTemplate: sqltemplate.New(s.dialect),
|
||||
Namespace: namespace,
|
||||
UID: uid,
|
||||
}
|
||||
query, err := sqltemplate.Execute(sqlEncryptedValueDelete, req)
|
||||
if err != nil {
|
||||
return fmt.Errorf("executing template %q: %w", sqlEncryptedValueDelete.Name(), err)
|
||||
}
|
||||
|
||||
if _, err = s.db.ExecContext(ctx, query, req.GetArgs()...); err != nil {
|
||||
return fmt.Errorf("deleting row: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
105
pkg/storage/secret/encryption/encrypted_value_store_test.go
Normal file
105
pkg/storage/secret/encryption/encrypted_value_store_test.go
Normal file
@ -0,0 +1,105 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/services/featuremgmt"
|
||||
"github.com/grafana/grafana/pkg/services/sqlstore"
|
||||
"github.com/grafana/grafana/pkg/storage/secret/database"
|
||||
"github.com/grafana/grafana/pkg/storage/secret/migrator"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestEncryptedValueStoreImpl(t *testing.T) {
|
||||
// Initialize data key storage with a fake db
|
||||
testDB := sqlstore.NewTestStore(t, sqlstore.WithMigrator(migrator.New()))
|
||||
database := database.ProvideDatabase(testDB)
|
||||
features := featuremgmt.WithFeatures(featuremgmt.FlagGrafanaAPIServerWithExperimentalAPIs, featuremgmt.FlagSecretsManagementAppPlatform)
|
||||
ctx := context.Background()
|
||||
|
||||
store, err := ProvideEncryptedValueStorage(database, features)
|
||||
require.NoError(t, err)
|
||||
|
||||
t.Run("creating an encrypted value returns it", func(t *testing.T) {
|
||||
createdEV, err := store.Create(ctx, "test-namespace", []byte("test-data"))
|
||||
require.NoError(t, err)
|
||||
require.NotEmpty(t, createdEV.UID)
|
||||
require.NotEmpty(t, createdEV.Created)
|
||||
require.NotEmpty(t, createdEV.Updated)
|
||||
require.NotEmpty(t, createdEV.EncryptedData)
|
||||
require.Equal(t, "test-namespace", createdEV.Namespace)
|
||||
})
|
||||
|
||||
t.Run("get an existent encrypted value returns it", func(t *testing.T) {
|
||||
createdEV, err := store.Create(ctx, "test-namespace", []byte("test-data"))
|
||||
require.NoError(t, err)
|
||||
|
||||
obtainedEV, err := store.Get(ctx, "test-namespace", createdEV.UID)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, createdEV.UID, obtainedEV.UID)
|
||||
require.Equal(t, createdEV.Created, obtainedEV.Created)
|
||||
require.Equal(t, createdEV.Updated, obtainedEV.Updated)
|
||||
require.Equal(t, createdEV.EncryptedData, obtainedEV.EncryptedData)
|
||||
require.Equal(t, createdEV.Namespace, obtainedEV.Namespace)
|
||||
})
|
||||
|
||||
t.Run("get an existent encrypted value with a different namespace returns error", func(t *testing.T) {
|
||||
createdEV, err := store.Create(ctx, "test-namespace", []byte("test-data"))
|
||||
require.NoError(t, err)
|
||||
|
||||
obtainedEV, err := store.Get(ctx, "other-test-namespace", createdEV.UID)
|
||||
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "encrypted value not found", err.Error())
|
||||
require.Nil(t, obtainedEV)
|
||||
})
|
||||
|
||||
t.Run("get a non existent encrypted value returns error", func(t *testing.T) {
|
||||
obtainedEV, err := store.Get(ctx, "test-namespace", "test-uid")
|
||||
require.Error(t, err)
|
||||
require.Equal(t, "encrypted value not found", err.Error())
|
||||
require.Nil(t, obtainedEV)
|
||||
})
|
||||
|
||||
t.Run("updating an existing encrypted value returns no error", func(t *testing.T) {
|
||||
createdEV, err := store.Create(ctx, "test-namespace", []byte("test-data"))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = store.Update(ctx, "test-namespace", createdEV.UID, []byte("test-data-updated"))
|
||||
require.NoError(t, err)
|
||||
|
||||
updatedEV, err := store.Get(ctx, "test-namespace", createdEV.UID)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, []byte("test-data-updated"), updatedEV.EncryptedData)
|
||||
require.Equal(t, createdEV.Created, updatedEV.Created)
|
||||
require.Equal(t, createdEV.Namespace, updatedEV.Namespace)
|
||||
})
|
||||
|
||||
t.Run("updating a non existing encrypted value returns error", func(t *testing.T) {
|
||||
err := store.Update(ctx, "test-namespace", "test-uid", []byte("test-data"))
|
||||
require.Error(t, err)
|
||||
})
|
||||
|
||||
t.Run("delete an existing encrypted value returns error", func(t *testing.T) {
|
||||
createdEV, err := store.Create(ctx, "test-namespace", []byte("ttttest-data"))
|
||||
require.NoError(t, err)
|
||||
|
||||
obtainedEV, err := store.Get(ctx, "test-namespace", createdEV.UID)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = store.Delete(ctx, "test-namespace", obtainedEV.UID)
|
||||
require.NoError(t, err)
|
||||
|
||||
obtainedEV, err = store.Get(ctx, "test-namespace", createdEV.UID)
|
||||
require.Error(t, err)
|
||||
require.Nil(t, obtainedEV)
|
||||
})
|
||||
|
||||
t.Run("delete a non existing encrypted value does not return error", func(t *testing.T) {
|
||||
err := store.Delete(ctx, "test-namespace", "test-uid")
|
||||
require.NoError(t, err)
|
||||
})
|
||||
}
|
81
pkg/storage/secret/encryption/query.go
Normal file
81
pkg/storage/secret/encryption/query.go
Normal file
@ -0,0 +1,81 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"embed"
|
||||
"fmt"
|
||||
"text/template"
|
||||
|
||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate"
|
||||
)
|
||||
|
||||
var (
|
||||
//go:embed data/*.sql
|
||||
sqlTemplatesFS embed.FS
|
||||
|
||||
sqlTemplates = template.Must(template.New("sql").ParseFS(sqlTemplatesFS, `data/*.sql`))
|
||||
|
||||
// The SQL Commands
|
||||
sqlEncryptedValueCreate = mustTemplate("encrypted_value_create.sql")
|
||||
sqlEncryptedValueRead = mustTemplate("encrypted_value_read.sql")
|
||||
sqlEncryptedValueUpdate = mustTemplate("encrypted_value_update.sql")
|
||||
sqlEncryptedValueDelete = mustTemplate("encrypted_value_delete.sql")
|
||||
)
|
||||
|
||||
// TODO: Move this to a common place so that all stores can use
|
||||
func mustTemplate(filename string) *template.Template {
|
||||
if t := sqlTemplates.Lookup(filename); t != nil {
|
||||
return t
|
||||
}
|
||||
panic(fmt.Sprintf("template file not found: %s", filename))
|
||||
}
|
||||
|
||||
/*************************************/
|
||||
/**-- Encrypted Value Queries --**/
|
||||
/*************************************/
|
||||
type createEncryptedValue struct {
|
||||
sqltemplate.SQLTemplate
|
||||
Row *EncryptedValue
|
||||
}
|
||||
|
||||
// Validate is only used if we use `dbutil` from `unifiedstorage`
|
||||
func (r createEncryptedValue) Validate() error {
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
// Read Encrypted Value
|
||||
type readEncryptedValue struct {
|
||||
sqltemplate.SQLTemplate
|
||||
Namespace string
|
||||
UID string
|
||||
}
|
||||
|
||||
// Validate is only used if we use `dbutil` from `unifiedstorage`
|
||||
func (r readEncryptedValue) Validate() error {
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
// Update Encrypted Value
|
||||
type updateEncryptedValue struct {
|
||||
sqltemplate.SQLTemplate
|
||||
Namespace string
|
||||
UID string
|
||||
EncryptedData []byte
|
||||
Updated int64
|
||||
}
|
||||
|
||||
// Validate is only used if we use `dbutil` from `unifiedstorage`
|
||||
func (r updateEncryptedValue) Validate() error {
|
||||
return nil // TODO
|
||||
}
|
||||
|
||||
// Delete Encrypted Value
|
||||
type deleteEncryptedValue struct {
|
||||
sqltemplate.SQLTemplate
|
||||
Namespace string
|
||||
UID string
|
||||
}
|
||||
|
||||
// Validate is only used if we use `dbutil` from `unifiedstorage`
|
||||
func (r deleteEncryptedValue) Validate() error {
|
||||
return nil // TODO
|
||||
}
|
63
pkg/storage/secret/encryption/query_test.go
Normal file
63
pkg/storage/secret/encryption/query_test.go
Normal file
@ -0,0 +1,63 @@
|
||||
package encryption
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"text/template"
|
||||
|
||||
"github.com/grafana/grafana/pkg/storage/unified/sql/sqltemplate/mocks"
|
||||
)
|
||||
|
||||
func TestEncryptedValueQueries(t *testing.T) {
|
||||
mocks.CheckQuerySnapshots(t, mocks.TemplateTestSetup{
|
||||
RootDir: "testdata",
|
||||
Templates: map[*template.Template][]mocks.TemplateTestCase{
|
||||
sqlEncryptedValueCreate: {
|
||||
{
|
||||
Name: "create",
|
||||
Data: &createEncryptedValue{
|
||||
SQLTemplate: mocks.NewTestingSQLTemplate(),
|
||||
Row: &EncryptedValue{
|
||||
Namespace: "ns",
|
||||
UID: "abc123",
|
||||
EncryptedData: []byte("secret"),
|
||||
Created: 1234,
|
||||
Updated: 5678,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
sqlEncryptedValueRead: {
|
||||
{
|
||||
Name: "read",
|
||||
Data: &readEncryptedValue{
|
||||
SQLTemplate: mocks.NewTestingSQLTemplate(),
|
||||
Namespace: "ns",
|
||||
UID: "abc123",
|
||||
},
|
||||
},
|
||||
},
|
||||
sqlEncryptedValueUpdate: {
|
||||
{
|
||||
Name: "update",
|
||||
Data: &updateEncryptedValue{
|
||||
SQLTemplate: mocks.NewTestingSQLTemplate(),
|
||||
Namespace: "ns",
|
||||
UID: "abc123",
|
||||
EncryptedData: []byte("secret"),
|
||||
Updated: 5679,
|
||||
},
|
||||
},
|
||||
},
|
||||
sqlEncryptedValueDelete: {
|
||||
{
|
||||
Name: "delete",
|
||||
Data: &deleteEncryptedValue{
|
||||
SQLTemplate: mocks.NewTestingSQLTemplate(),
|
||||
Namespace: "ns",
|
||||
UID: "abc123",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
13
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_create-create.sql
vendored
Executable file
13
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_create-create.sql
vendored
Executable file
@ -0,0 +1,13 @@
|
||||
INSERT INTO `secret_encrypted_value` (
|
||||
`uid`,
|
||||
`namespace`,
|
||||
`encrypted_data`,
|
||||
`created`,
|
||||
`updated`
|
||||
) VALUES (
|
||||
'abc123',
|
||||
'ns',
|
||||
'[115 101 99 114 101 116]',
|
||||
1234,
|
||||
5678
|
||||
);
|
4
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_delete-delete.sql
vendored
Executable file
4
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_delete-delete.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
DELETE FROM `secret_encrypted_value`
|
||||
WHERE `namespace` = 'ns' AND
|
||||
`uid` = 'abc123'
|
||||
;
|
11
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_read-read.sql
vendored
Executable file
11
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_read-read.sql
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
SELECT
|
||||
`uid`,
|
||||
`namespace`,
|
||||
`encrypted_data`,
|
||||
`created`,
|
||||
`updated`
|
||||
FROM
|
||||
`secret_encrypted_value`
|
||||
WHERE `namespace` = 'ns' AND
|
||||
`uid` = 'abc123'
|
||||
;
|
8
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_update-update.sql
vendored
Executable file
8
pkg/storage/secret/encryption/testdata/mysql--encrypted_value_update-update.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
UPDATE
|
||||
`secret_encrypted_value`
|
||||
SET
|
||||
`encrypted_data` = '[115 101 99 114 101 116]',
|
||||
`updated` = 5679
|
||||
WHERE `namespace` = 'ns' AND
|
||||
`uid` = 'abc123'
|
||||
;
|
13
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_create-create.sql
vendored
Executable file
13
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_create-create.sql
vendored
Executable file
@ -0,0 +1,13 @@
|
||||
INSERT INTO "secret_encrypted_value" (
|
||||
"uid",
|
||||
"namespace",
|
||||
"encrypted_data",
|
||||
"created",
|
||||
"updated"
|
||||
) VALUES (
|
||||
'abc123',
|
||||
'ns',
|
||||
'[115 101 99 114 101 116]',
|
||||
1234,
|
||||
5678
|
||||
);
|
4
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_delete-delete.sql
vendored
Executable file
4
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_delete-delete.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
DELETE FROM "secret_encrypted_value"
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
11
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_read-read.sql
vendored
Executable file
11
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_read-read.sql
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
SELECT
|
||||
"uid",
|
||||
"namespace",
|
||||
"encrypted_data",
|
||||
"created",
|
||||
"updated"
|
||||
FROM
|
||||
"secret_encrypted_value"
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
8
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_update-update.sql
vendored
Executable file
8
pkg/storage/secret/encryption/testdata/postgres--encrypted_value_update-update.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
UPDATE
|
||||
"secret_encrypted_value"
|
||||
SET
|
||||
"encrypted_data" = '[115 101 99 114 101 116]',
|
||||
"updated" = 5679
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
13
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_create-create.sql
vendored
Executable file
13
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_create-create.sql
vendored
Executable file
@ -0,0 +1,13 @@
|
||||
INSERT INTO "secret_encrypted_value" (
|
||||
"uid",
|
||||
"namespace",
|
||||
"encrypted_data",
|
||||
"created",
|
||||
"updated"
|
||||
) VALUES (
|
||||
'abc123',
|
||||
'ns',
|
||||
'[115 101 99 114 101 116]',
|
||||
1234,
|
||||
5678
|
||||
);
|
4
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_delete-delete.sql
vendored
Executable file
4
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_delete-delete.sql
vendored
Executable file
@ -0,0 +1,4 @@
|
||||
DELETE FROM "secret_encrypted_value"
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
11
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_read-read.sql
vendored
Executable file
11
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_read-read.sql
vendored
Executable file
@ -0,0 +1,11 @@
|
||||
SELECT
|
||||
"uid",
|
||||
"namespace",
|
||||
"encrypted_data",
|
||||
"created",
|
||||
"updated"
|
||||
FROM
|
||||
"secret_encrypted_value"
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
8
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_update-update.sql
vendored
Executable file
8
pkg/storage/secret/encryption/testdata/sqlite--encrypted_value_update-update.sql
vendored
Executable file
@ -0,0 +1,8 @@
|
||||
UPDATE
|
||||
"secret_encrypted_value"
|
||||
SET
|
||||
"encrypted_data" = '[115 101 99 114 101 116]',
|
||||
"updated" = 5679
|
||||
WHERE "namespace" = 'ns' AND
|
||||
"uid" = 'abc123'
|
||||
;
|
@ -12,7 +12,8 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
TableNameKeeper = "secret_keeper"
|
||||
TableNameKeeper = "secret_keeper"
|
||||
TableNameEncryptedValue = "secret_encrypted_value"
|
||||
)
|
||||
|
||||
type SecretDB struct {
|
||||
@ -67,6 +68,18 @@ func (*SecretDB) AddMigration(mg *migrator.Migrator) {
|
||||
},
|
||||
})
|
||||
|
||||
tables = append(tables, migrator.Table{
|
||||
Name: TableNameEncryptedValue,
|
||||
Columns: []*migrator.Column{
|
||||
{Name: "namespace", Type: migrator.DB_NVarchar, Length: 253, Nullable: false}, // Limit enforced by K8s.
|
||||
{Name: "uid", Type: migrator.DB_NVarchar, Length: 36, IsPrimaryKey: true}, // Fixed size of a UUID.
|
||||
{Name: "encrypted_data", Type: migrator.DB_Blob, Nullable: false},
|
||||
{Name: "created", Type: migrator.DB_BigInt, Nullable: false},
|
||||
{Name: "updated", Type: migrator.DB_BigInt, Nullable: false},
|
||||
},
|
||||
Indices: []*migrator.Index{}, // TODO: add indexes based on the queries we make.
|
||||
})
|
||||
|
||||
// Initialize all tables
|
||||
for t := range tables {
|
||||
mg.AddMigration("drop table "+tables[t].Name, migrator.NewDropTableMigration(tables[t].Name))
|
||||
|
Reference in New Issue
Block a user