diff --git a/globals/kms.go b/globals/kms.go index 3d01c8df2..2765751a3 100644 --- a/globals/kms.go +++ b/globals/kms.go @@ -11,4 +11,5 @@ const ( KmsPurposeRecovery = "recovery" KmsPurposeConfig = "config" KmsPurposeDownstreamWorkerAuth = "downstream-worker-auth" + KmsPurposeBsr = "bsr" ) diff --git a/internal/cmd/base/server_test.go b/internal/cmd/base/server_test.go index 727c886dc..300670966 100644 --- a/internal/cmd/base/server_test.go +++ b/internal/cmd/base/server_test.go @@ -64,7 +64,7 @@ func TestServer_SetupKMSes_Purposes(t *testing.T) { name: "multi purpose", purposes: []string{ globals.KmsPurposeRoot, globals.KmsPurposeRecovery, globals.KmsPurposeWorkerAuth, - globals.KmsPurposeWorkerAuthStorage, globals.KmsPurposeConfig, + globals.KmsPurposeWorkerAuthStorage, globals.KmsPurposeConfig, globals.KmsPurposeBsr, }, }, { @@ -97,6 +97,11 @@ func TestServer_SetupKMSes_Purposes(t *testing.T) { purposes: []string{globals.KmsPurposeWorkerAuthStorage, globals.KmsPurposeWorkerAuthStorage}, wantErrContains: fmt.Sprintf("Duplicate KMS block for purpose '%s'", globals.KmsPurposeWorkerAuthStorage), }, + { + name: "duplicate bsr kms purposes", + purposes: []string{globals.KmsPurposeBsr, globals.KmsPurposeBsr}, + wantErrContains: fmt.Sprintf("Duplicate KMS block for purpose '%s'", globals.KmsPurposeBsr), + }, { name: "duplicate recovery purposes", purposes: []string{globals.KmsPurposeRecovery, globals.KmsPurposeRecovery}, @@ -137,6 +142,8 @@ func TestServer_SetupKMSes_Purposes(t *testing.T) { assert.NotNil(s.WorkerAuthStorageKms) case globals.KmsPurposeRecovery: assert.NotNil(s.RecoveryKms) + case globals.KmsPurposeBsr: + assert.NotNil(s.BsrKms) } } }) diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index d17c6d029..d4f7ff3a4 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -85,6 +85,7 @@ type Server struct { WorkerAuthKms wrapping.Wrapper WorkerAuthStorageKms wrapping.Wrapper RecoveryKms wrapping.Wrapper + BsrKms wrapping.Wrapper Kms *kms.Kms SecureRandomReader io.Reader @@ -568,7 +569,8 @@ func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Confi globals.KmsPurposePreviousRoot, globals.KmsPurposeConfig, globals.KmsPurposeWorkerAuth, - globals.KmsPurposeWorkerAuthStorage: + globals.KmsPurposeWorkerAuthStorage, + globals.KmsPurposeBsr: case globals.KmsPurposeRecovery: if config.Controller != nil && config.DevRecoveryKey != "" { kms.Config["key"] = config.DevRecoveryKey @@ -664,6 +666,11 @@ func (b *Server) SetupKMSes(ctx context.Context, ui cli.Ui, config *config.Confi return fmt.Errorf("Duplicate KMS block for purpose '%s'. You may need to remove all but the last KMS block for this purpose.", purpose) } b.WorkerAuthStorageKms = wrapper + case globals.KmsPurposeBsr: + if b.BsrKms != nil { + return fmt.Errorf("Duplicate KMS block for purpose '%s'. You may need to remove all but the last KMS block for this purpose.", purpose) + } + b.BsrKms = wrapper case globals.KmsPurposeRecovery: if b.RecoveryKms != nil { return fmt.Errorf("Duplicate KMS block for purpose '%s'. You may need to remove all but the last KMS block for this purpose.", purpose) diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 4a2322cf4..eb75f6d39 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -106,6 +106,7 @@ type Command struct { flagWorkerAuthCaCertificateLifetime time.Duration flagWorkerAuthDebuggingEnabled bool flagWorkerRecordingStorageDir string + flagBsrKey string } func (c *Command) Synopsis() string { @@ -280,6 +281,13 @@ func (c *Command) Flags() *base.FlagSets { Usage: "If set, a valid base64-encoded AES key to be used for worker-auth purposes", }) + f.StringVar(&base.StringVar{ + Name: "bsr-key", + Target: &c.flagBsrKey, + EnvVar: "BOUNDARY_DEV_BSR_KEY", + Usage: "If set, a valid base64-encoded AES key to be used for bsr purposes", + }) + f.BoolVar(&base.BoolVar{ Name: "disable-database-destruction", Target: &c.flagDisableDatabaseDestruction, @@ -454,6 +462,15 @@ func (c *Command) Run(args []string) int { } } + if c.flagBsrKey != "" { + c.Config.DevBsrKey = c.flagBsrKey + for _, kms := range c.Config.Seals { + if strutil.StrListContains(kms.Purpose, globals.KmsPurposeBsr) { + kms.Config["key"] = c.flagBsrKey + } + } + } + c.WorkerAuthDebuggingEnabled.Store(c.flagWorkerAuthDebuggingEnabled) c.DevLoginName = c.flagLoginName @@ -669,6 +686,8 @@ func (c *Command) Run(args []string) int { c.Info["[Recovery] AEAD Key Bytes"] = c.Config.DevRecoveryKey c.InfoKeys = append(c.InfoKeys, "[Worker-Auth] AEAD Key Bytes") c.Info["[Worker-Auth] AEAD Key Bytes"] = c.Config.DevWorkerAuthKey + c.InfoKeys = append(c.InfoKeys, "[Bsr] AEAD Key Bytes") + c.Info["[Bsr] AEAD Key Bytes"] = c.Config.DevBsrKey // Initialize the listeners if err := c.SetupListeners(c.UI, c.Config.SharedConfig, []string{"api", "cluster", "proxy", "ops"}); err != nil { diff --git a/internal/cmd/config/config.go b/internal/cmd/config/config.go index a7b114a91..9e1d3e72d 100644 --- a/internal/cmd/config/config.go +++ b/internal/cmd/config/config.go @@ -71,6 +71,13 @@ kms "aead" { key_id = "global_worker-auth" } +kms "aead" { + purpose = "bsr" + aead_type = "aes-gcm" + key = "%s" + key_id = "global_bsr" +} + kms "aead" { purpose = "recovery" aead_type = "aes-gcm" @@ -131,6 +138,7 @@ type Config struct { DevControllerKey string `hcl:"-"` DevWorkerAuthKey string `hcl:"-"` DevWorkerAuthStorageKey string `hcl:"-"` + DevBsrKey string `hcl:"-"` DevRecoveryKey string `hcl:"-"` // Eventing configuration for the controller @@ -363,9 +371,10 @@ func DevKeyGeneration() string { func DevController(opt ...Option) (*Config, error) { controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() + bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() - hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, recoveryKey) + hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey) parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -373,6 +382,7 @@ func DevController(opt ...Option) (*Config, error) { parsed.DevController = true parsed.DevControllerKey = controllerKey parsed.DevWorkerAuthKey = workerAuthKey + parsed.DevBsrKey = bsrKey parsed.DevRecoveryKey = recoveryKey opts := getOpts(opt...) parsed.Eventing.AuditEnabled = opts.withAuditEventsEnabled @@ -386,8 +396,9 @@ func DevCombined() (*Config, error) { controllerKey := DevKeyGeneration() workerAuthKey := DevKeyGeneration() workerAuthStorageKey := DevKeyGeneration() + bsrKey := DevKeyGeneration() recoveryKey := DevKeyGeneration() - hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, recoveryKey, workerAuthStorageKey) + hclStr := fmt.Sprintf(devConfig+devControllerExtraConfig+devWorkerExtraConfig, controllerKey, workerAuthKey, bsrKey, recoveryKey, workerAuthStorageKey) parsed, err := Parse(hclStr) if err != nil { return nil, fmt.Errorf("error parsing dev config: %w", err) @@ -396,6 +407,7 @@ func DevCombined() (*Config, error) { parsed.DevControllerKey = controllerKey parsed.DevWorkerAuthKey = workerAuthKey parsed.DevWorkerAuthStorageKey = workerAuthStorageKey + parsed.DevBsrKey = bsrKey parsed.DevRecoveryKey = recoveryKey return parsed, nil } diff --git a/internal/cmd/config/config_load_test.go b/internal/cmd/config/config_load_test.go index b931efa52..d4ac9928a 100644 --- a/internal/cmd/config/config_load_test.go +++ b/internal/cmd/config/config_load_test.go @@ -419,6 +419,7 @@ func TestLoad(t *testing.T) { DevControllerKey: "", DevWorkerAuthKey: "", DevWorkerAuthStorageKey: "", + DevBsrKey: "", DevRecoveryKey: "", Eventing: &event.EventerConfig{ AuditEnabled: false, @@ -837,6 +838,7 @@ func TestLoad(t *testing.T) { DevUiPassthroughDir: "", DevControllerKey: "", DevWorkerAuthKey: "", + DevBsrKey: "", DevWorkerAuthStorageKey: "", DevRecoveryKey: "", Eventing: &event.EventerConfig{ @@ -1251,6 +1253,7 @@ func TestLoad(t *testing.T) { DevUiPassthroughDir: "", DevControllerKey: "", DevWorkerAuthKey: "", + DevBsrKey: "", DevWorkerAuthStorageKey: "", DevRecoveryKey: "", Eventing: &event.EventerConfig{ @@ -1665,6 +1668,7 @@ func TestLoad(t *testing.T) { DevUiPassthroughDir: "", DevControllerKey: "", DevWorkerAuthKey: "", + DevBsrKey: "", DevWorkerAuthStorageKey: "", DevRecoveryKey: "", Eventing: &event.EventerConfig{ @@ -1750,6 +1754,7 @@ func TestLoad(t *testing.T) { DevUiPassthroughDir: "", DevControllerKey: "", DevWorkerAuthKey: "", + DevBsrKey: "", DevWorkerAuthStorageKey: "", DevRecoveryKey: "", Eventing: &event.EventerConfig{ diff --git a/internal/cmd/config/config_test.go b/internal/cmd/config/config_test.go index bff37d476..a570b2b12 100644 --- a/internal/cmd/config/config_test.go +++ b/internal/cmd/config/config_test.go @@ -89,6 +89,14 @@ func TestDevController(t *testing.T) { "key_id": "global_worker-auth", }, }, + { + Type: "aead", + Purpose: []string{"bsr"}, + Config: map[string]string{ + "aead_type": "aes-gcm", + "key_id": "global_bsr", + }, + }, { Type: "aead", Purpose: []string{"recovery"}, @@ -115,9 +123,11 @@ func TestDevController(t *testing.T) { exp.Seals[0].Config["key"] = actual.Seals[0].Config["key"] exp.Seals[1].Config["key"] = actual.Seals[1].Config["key"] exp.Seals[2].Config["key"] = actual.Seals[2].Config["key"] + exp.Seals[3].Config["key"] = actual.Seals[3].Config["key"] exp.DevControllerKey = actual.Seals[0].Config["key"] exp.DevWorkerAuthKey = actual.Seals[1].Config["key"] - exp.DevRecoveryKey = actual.Seals[2].Config["key"] + exp.DevBsrKey = actual.Seals[2].Config["key"] + exp.DevRecoveryKey = actual.Seals[3].Config["key"] assert.Equal(t, exp, actual) @@ -444,6 +454,14 @@ func TestDevCombined(t *testing.T) { "key_id": "global_worker-auth", }, }, + { + Type: "aead", + Purpose: []string{"bsr"}, + Config: map[string]string{ + "aead_type": "aes-gcm", + "key_id": "global_bsr", + }, + }, { Type: "aead", Purpose: []string{"recovery"}, @@ -486,10 +504,12 @@ func TestDevCombined(t *testing.T) { exp.Seals[1].Config["key"] = actual.Seals[1].Config["key"] exp.Seals[2].Config["key"] = actual.Seals[2].Config["key"] exp.Seals[3].Config["key"] = actual.Seals[3].Config["key"] + exp.Seals[4].Config["key"] = actual.Seals[4].Config["key"] exp.DevControllerKey = actual.Seals[0].Config["key"] exp.DevWorkerAuthKey = actual.Seals[1].Config["key"] - exp.DevRecoveryKey = actual.Seals[2].Config["key"] - exp.DevWorkerAuthStorageKey = actual.Seals[3].Config["key"] + exp.DevBsrKey = actual.Seals[2].Config["key"] + exp.DevRecoveryKey = actual.Seals[3].Config["key"] + exp.DevWorkerAuthStorageKey = actual.Seals[4].Config["key"] exp.Worker.TagsRaw = actual.Worker.TagsRaw assert.Equal(t, exp, actual) } diff --git a/internal/daemon/controller/controller.go b/internal/daemon/controller/controller.go index ba73d9fb5..d58808892 100644 --- a/internal/daemon/controller/controller.go +++ b/internal/daemon/controller/controller.go @@ -290,6 +290,7 @@ func New(ctx context.Context, conf *Config) (*Controller, error) { kms.WithRootWrapper(c.conf.RootKms), kms.WithWorkerAuthWrapper(c.conf.WorkerAuthKms), kms.WithRecoveryWrapper(c.conf.RecoveryKms), + kms.WithBsrWrapper(c.conf.BsrKms), ); err != nil { return nil, fmt.Errorf("error adding config keys to kms: %w", err) } diff --git a/internal/daemon/controller/testing.go b/internal/daemon/controller/testing.go index c6fd591da..2aac1eccc 100644 --- a/internal/daemon/controller/testing.go +++ b/internal/daemon/controller/testing.go @@ -437,6 +437,9 @@ type TestControllerOpts struct { // The downstream worker auth KMS to use, or one will be created DownstreamWorkerAuthKms *multi.PooledWrapper + // The BSR wrapper to use, or one will be created + BsrKms wrapping.Wrapper + // The recovery KMS to use, or one will be created RecoveryKms wrapping.Wrapper @@ -692,6 +695,9 @@ func TestControllerConfig(t testing.TB, ctx context.Context, tc *TestController, if opts.DownstreamWorkerAuthKms != nil { tc.b.DownstreamWorkerAuthKms = opts.DownstreamWorkerAuthKms } + if opts.BsrKms != nil { + tc.b.BsrKms = opts.BsrKms + } if opts.RecoveryKms != nil { tc.b.RecoveryKms = opts.RecoveryKms } @@ -800,6 +806,7 @@ func (tc *TestController) AddClusterControllerMember(t testing.TB, opts *TestCon RootKms: tc.c.conf.RootKms, WorkerAuthKms: tc.c.conf.WorkerAuthKms, DownstreamWorkerAuthKms: tc.c.conf.DownstreamWorkerAuthKms, + BsrKms: tc.c.conf.BsrKms, RecoveryKms: tc.c.conf.RecoveryKms, Name: opts.Name, Logger: tc.c.conf.Logger, diff --git a/internal/daemon/controller/testing_test.go b/internal/daemon/controller/testing_test.go index 7a31e1c46..48ba1df43 100644 --- a/internal/daemon/controller/testing_test.go +++ b/internal/daemon/controller/testing_test.go @@ -85,4 +85,17 @@ func Test_TestController(t *testing.T) { require.NoError(err) assert.Equal(testLdapAuthMethodId, got.GetPublicId()) }) + t.Run("controller-external-wrappers", func(t *testing.T) { + testCtx := context.Background() + assert := assert.New(t) + tc := NewTestController(t, nil) + defer tc.Shutdown() + + ws := tc.Kms().GetExternalWrappers(testCtx) + + assert.NotNil(ws.Root()) + assert.NotNil(ws.WorkerAuth()) + assert.NotNil(ws.Recovery()) + assert.NotNil(ws.Bsr()) + }) }