diff --git a/internal/auth/oidc/rewrapping.go b/internal/auth/oidc/rewrapping.go index 2fd8a4b8a..2038a12fe 100644 --- a/internal/auth/oidc/rewrapping.go +++ b/internal/auth/oidc/rewrapping.go @@ -13,7 +13,7 @@ func init() { kms.RegisterTableRewrapFn(defaultAuthMethodTableName, authMethodRewrapFn) } -func authMethodRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func authMethodRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "oidc.authMethodRewrapFn" if dataKeyVersionId == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing data key version id") diff --git a/internal/auth/password/rewrapping.go b/internal/auth/password/rewrapping.go index 427148d10..98d346e6d 100644 --- a/internal/auth/password/rewrapping.go +++ b/internal/auth/password/rewrapping.go @@ -13,7 +13,7 @@ func init() { kms.RegisterTableRewrapFn("auth_password_argon2_cred", argon2ConfigRewrapFn) } -func argon2ConfigRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func argon2ConfigRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "password.argon2ConfigRewrapFn" if dataKeyVersionId == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing data key version id") diff --git a/internal/authtoken/rewrapping.go b/internal/authtoken/rewrapping.go index 50b70e194..44ec59ccd 100644 --- a/internal/authtoken/rewrapping.go +++ b/internal/authtoken/rewrapping.go @@ -13,7 +13,7 @@ func init() { kms.RegisterTableRewrapFn(defaultAuthTokenTableName, authTokenRewrapFn) } -func authTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func authTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "authtoken.authTokenRewrapFn" if dataKeyVersionId == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing data key version id") diff --git a/internal/credential/static/rewrapping.go b/internal/credential/static/rewrapping.go index 3cf527d90..5a878b556 100644 --- a/internal/credential/static/rewrapping.go +++ b/internal/credential/static/rewrapping.go @@ -15,7 +15,7 @@ func init() { kms.RegisterTableRewrapFn("credential_static_json_credential", credStaticJsonRewrapFn) } -func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) string { +func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) string { if dataKeyVersionId == "" { return "missing data key version id" } @@ -34,7 +34,7 @@ func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId return "" } -func credStaticUsernamePasswordRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func credStaticUsernamePasswordRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "static.credStaticUsernamePasswordRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -79,7 +79,7 @@ func credStaticUsernamePasswordRewrapFn(ctx context.Context, dataKeyVersionId, s return nil } -func credStaticSshPrivKeyRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func credStaticSshPrivKeyRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "static.credStaticSshPrivKeyRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -125,7 +125,7 @@ func credStaticSshPrivKeyRewrapFn(ctx context.Context, dataKeyVersionId, scopeId return nil } -func credStaticJsonRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func credStaticJsonRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "static.credStaticJsonRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) diff --git a/internal/credential/vault/rewrapping.go b/internal/credential/vault/rewrapping.go index 472af2ebd..c27d83003 100644 --- a/internal/credential/vault/rewrapping.go +++ b/internal/credential/vault/rewrapping.go @@ -14,7 +14,7 @@ func init() { kms.RegisterTableRewrapFn("credential_vault_token", credVaultTokenRewrapFn) } -func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) string { +func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) string { if dataKeyVersionId == "" { return "missing data key version id" } @@ -33,7 +33,7 @@ func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId return "" } -func credVaultClientCertificateRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func credVaultClientCertificateRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "vault.credVaultClientCertificateRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -62,7 +62,7 @@ func credVaultClientCertificateRewrapFn(ctx context.Context, dataKeyVersionId, s return nil } -func credVaultTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func credVaultTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "vault.credVaultTokenRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) diff --git a/internal/host/plugin/rewrapping.go b/internal/host/plugin/rewrapping.go index 4b838de8d..387831d9d 100644 --- a/internal/host/plugin/rewrapping.go +++ b/internal/host/plugin/rewrapping.go @@ -13,7 +13,7 @@ func init() { kms.RegisterTableRewrapFn("host_plugin_catalog_secret", hostCatalogSecretRewrapFn) } -func hostCatalogSecretRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func hostCatalogSecretRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "plugin.hostCatalogSecretRewrapFn" if dataKeyVersionId == "" { return errors.New(ctx, errors.InvalidParameter, op, "missing data key version id") diff --git a/internal/kms/kms_test.go b/internal/kms/kms_test.go index a48d0bdd4..86eb7fdcb 100644 --- a/internal/kms/kms_test.go +++ b/internal/kms/kms_test.go @@ -439,7 +439,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { t.Run("does-nothing-when-no-run-available", func(t *testing.T) { callbackCalled := false - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { callbackCalled = true return nil } @@ -476,7 +476,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { require.NoError(t, err) }) callbackCalled := false - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { callbackCalled = true return nil } @@ -501,7 +501,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { }) callbackCalled := make(chan struct{}) returnFromCallback := make(chan struct{}) - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { close(callbackCalled) assert.Equal(t, "global", scopeId) // Block here until we want it to return @@ -568,7 +568,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { require.NoError(t, err) }) rewrappedKeyVersion := "" - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { rewrappedKeyVersion = dataKeyVersionId return nil } @@ -600,7 +600,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { require.NoError(t, err) }) rewrappedKeyVersion := "" - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { rewrappedKeyVersion = dataKeyVersionId return nil } @@ -624,7 +624,7 @@ func TestMonitorTableRewrappingRuns(t *testing.T) { require.NoError(t, err) }) callbackCalled := make(chan struct{}) - tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + tableNameToRewrapFn["auth_token"] = func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { close(callbackCalled) // Block here until we want it to return <-ctx.Done() @@ -909,7 +909,7 @@ func TestDestroyKeyVersion(t *testing.T) { } func Test_RegisterTableRewrapFn(t *testing.T) { - rewrapFn := func(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + rewrapFn := func(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { return nil } RegisterTableRewrapFn("a_table", rewrapFn) @@ -923,7 +923,7 @@ func Test_RegisterTableRewrapFn(t *testing.T) { func Test_ListTablesSupportingRewrap(t *testing.T) { assert.Empty(t, ListTablesSupportingRewrap()) - rewrapFn := func(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error { + rewrapFn := func(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error { return nil } RegisterTableRewrapFn("a_table", rewrapFn) diff --git a/internal/kms/rewrapping.go b/internal/kms/rewrapping.go index 0eb3ac678..efc914bcd 100644 --- a/internal/kms/rewrapping.go +++ b/internal/kms/rewrapping.go @@ -5,10 +5,18 @@ import ( "fmt" "github.com/hashicorp/boundary/internal/db" + wrapping "github.com/hashicorp/go-kms-wrapping/v2" "golang.org/x/exp/maps" ) -type RewrapFn func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms *Kms) error +// GetWrapperer defines (and constrains) the kms features required by the +// RewrapFn +type GetWrapperer interface { + // GetWrapper returns a wrapper for the given scope and purpose. + GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose, opt ...Option) (wrapping.Wrapper, error) +} + +type RewrapFn func(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kms GetWrapperer) error var tableNameToRewrapFn = map[string]RewrapFn{} diff --git a/internal/kms/testing.go b/internal/kms/testing.go index 027170554..02473fc6b 100644 --- a/internal/kms/testing.go +++ b/internal/kms/testing.go @@ -39,3 +39,92 @@ func TestKmsDeleteAllKeys(t testing.TB, conn *db.DB) { type dataKey struct{} func (*dataKey) TableName() string { return "kms_data_key" } + +// MockGetWrapperer provides a mock for returning a set of mock values for a +// GetWrapperer +type MockGetWrapperer struct { + // Kms is the underlying kms which is used to provide the mock's default + // behavior + Kms *Kms + + // GetErr is a mock value to return for the GetWrapper(...) operation + GetErr error + + // ReturnWrapper is a mock value to return for the GetWrapper(...) operation + ReturnWrapper wrapping.Wrapper +} + +// GetWrapper returns a wrapper for a given scope and purpose. Supports mock +// values: ReturnWrapper, GetErr +func (m *MockGetWrapperer) GetWrapper(ctx context.Context, scopeId string, purpose KeyPurpose, opt ...Option) (wrapping.Wrapper, error) { + switch { + case m.ReturnWrapper != nil: + return m.ReturnWrapper, nil + case m.GetErr != nil: + return nil, m.GetErr + default: + return m.Kms.GetWrapper(ctx, scopeId, purpose, opt...) + } +} + +// MockWrapper provides a mock for returning a set of mock values for a Wrapper +type MockWrapper struct { + // Wrapper is the underlying wrapping.Wrapper which is used to provide the + // mock's default behavior + Wrapper wrapping.Wrapper + + // EncryptErr is a mock value to return for the Encrypt(...) operation + EncryptErr error + + // DecryptErr is a mock value to return for the Decrypt(...) operation + DecryptErr error + + // KeyIdErr is a mock value to return for the KeyId(...) operation + KeyIdErr error + + // KeyIdReturned is a mock value to return for the KeyId(...) operation + KeyIdReturned string +} + +// Type of the wrapper. No mock values supported +func (w *MockWrapper) Type(ctx context.Context) (wrapping.WrapperType, error) { + return w.Wrapper.Type(ctx) +} + +// KeyId is the id of the key currently used for encryption operations. Mock +// values supported: KeyIdErr, KeyIdReturned +func (w *MockWrapper) KeyId(ctx context.Context) (string, error) { // nolint + switch { + case w.KeyIdErr != nil: + return "", w.KeyIdErr + case w.KeyIdReturned != "": + return w.KeyIdReturned, nil + default: + return w.Wrapper.KeyId(ctx) + } +} + +// SetConfig applies the given options to a wrapper and returns +// configuration information. No mock values supported. +func (w *MockWrapper) SetConfig(ctx context.Context, options ...wrapping.Option) (*wrapping.WrapperConfig, error) { + return w.Wrapper.SetConfig(ctx, options...) +} + +// / Encrypt encrypts the given byte slice and stores the resulting information +// in the returned blob info. Mock values supported: EncryptErr +func (w *MockWrapper) Encrypt(ctx context.Context, plaintext []byte, options ...wrapping.Option) (*wrapping.BlobInfo, error) { + if w.EncryptErr != nil { + return nil, w.EncryptErr + } + + return w.Wrapper.Encrypt(ctx, plaintext, options...) +} + +// Decrypt decrypts the given byte slice and stores the resulting information in +// the returned byte slice. Mock values supported: DecryptErr +func (w *MockWrapper) Decrypt(ctx context.Context, ciphertext *wrapping.BlobInfo, options ...wrapping.Option) ([]byte, error) { + if w.DecryptErr != nil { + return nil, w.DecryptErr + } + return w.Wrapper.Decrypt(ctx, ciphertext, options...) +} diff --git a/internal/server/rewrapping.go b/internal/server/rewrapping.go index a1b268f8a..41b41f630 100644 --- a/internal/server/rewrapping.go +++ b/internal/server/rewrapping.go @@ -15,7 +15,7 @@ func init() { kms.RegisterTableRewrapFn("worker_auth_server_led_activation_token", workerAuthServerLedActivationTokenRewrapFn) } -func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) string { +func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) string { if dataKeyVersionId == "" { return "missing data key version id" } @@ -34,7 +34,7 @@ func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId return "" } -func workerAuthCertRewrapFn(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func workerAuthCertRewrapFn(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "server.workerAuthCertRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -63,7 +63,7 @@ func workerAuthCertRewrapFn(ctx context.Context, dataKeyVersionId string, scopeI return nil } -func workerAuthRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func workerAuthRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "server.workerAuthRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -108,7 +108,7 @@ func workerAuthRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, r return nil } -func workerAuthServerLedActivationTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func workerAuthServerLedActivationTokenRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "server.workerAuthServerLedActivationTokenRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) diff --git a/internal/session/repository_session.go b/internal/session/repository_session.go index 68ac5408e..fd14dd913 100644 --- a/internal/session/repository_session.go +++ b/internal/session/repository_session.go @@ -686,9 +686,9 @@ func fetchConnections(ctx context.Context, r db.Reader, sessionId string, opt .. // the session uses a legacy private key or not. It also updates the encrypted session // in the database (if necessary). Eventually we should be able to remove this function // and use the session key unconditionally. -func decryptAndMaybeUpdateSession(ctx context.Context, kmsRepo *kms.Kms, session *Session, writer db.Writer) error { +func decryptAndMaybeUpdateSession(ctx context.Context, kmsRepo kms.GetWrapperer, session *Session, writer db.Writer) error { const op = "session.decryptAndMaybeUpdateSession" - if kmsRepo == nil { + if util.IsNil(kmsRepo) { return errors.New(ctx, errors.InvalidParameter, op, "missing kms repo") } if session == nil { diff --git a/internal/session/rewrapping.go b/internal/session/rewrapping.go index 9260c3afc..1e4b0e58a 100644 --- a/internal/session/rewrapping.go +++ b/internal/session/rewrapping.go @@ -14,7 +14,7 @@ func init() { kms.RegisterTableRewrapFn("session_credential", sessionCredentialRewrapFn) } -func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) string { +func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) string { if dataKeyVersionId == "" { return "missing data key version id" } @@ -33,7 +33,7 @@ func rewrapParameterChecks(ctx context.Context, dataKeyVersionId string, scopeId return "" } -func sessionCredentialRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func sessionCredentialRewrapFn(ctx context.Context, dataKeyVersionId, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "session.sessionCredentialRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr) @@ -84,7 +84,7 @@ func sessionCredentialRewrapFn(ctx context.Context, dataKeyVersionId, scopeId st return nil } -func sessionRewrapFn(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo *kms.Kms) error { +func sessionRewrapFn(ctx context.Context, dataKeyVersionId string, scopeId string, reader db.Reader, writer db.Writer, kmsRepo kms.GetWrapperer) error { const op = "session.sessionRewrapFn" if errStr := rewrapParameterChecks(ctx, dataKeyVersionId, scopeId, reader, writer, kmsRepo); errStr != "" { return errors.New(ctx, errors.InvalidParameter, op, errStr)