diff --git a/internal/cmd/base/option.go b/internal/cmd/base/option.go index 93603a05fb..ab8f29c27a 100644 --- a/internal/cmd/base/option.go +++ b/internal/cmd/base/option.go @@ -14,8 +14,9 @@ type Option func(*Options) // Options - how Options are represented. type Options struct { - withNoTokenScope bool - withNoTokenValue bool + withNoTokenScope bool + withNoTokenValue bool + withSkipAuthMethodCreation bool } func getDefaultOptions() Options { @@ -39,3 +40,11 @@ func WithNoTokenValue() Option { o.withNoTokenValue = true } } + +// WithSkipAuthMethodCreation tells the command not to instantiate an auth +// method on first run. +func WithSkipAuthMethodCreation() Option { + return func(o *Options) { + o.withSkipAuthMethodCreation = true + } +} diff --git a/internal/cmd/base/servers.go b/internal/cmd/base/servers.go index e9f505adc4..8b4792f161 100644 --- a/internal/cmd/base/servers.go +++ b/internal/cmd/base/servers.go @@ -421,7 +421,9 @@ func (b *Server) ConnectToDatabase(dialect string) error { return nil } -func (b *Server) CreateDevDatabase(dialect string) error { +func (b *Server) CreateDevDatabase(dialect string, opt ...Option) error { + opts := getOpts(opt...) + c, url, container, err := db.InitDbInDocker(dialect) // In case of an error, run the cleanup function. If we pass all errors, c should be set to a noop // function before returning from this method @@ -467,11 +469,6 @@ func (b *Server) CreateDevDatabase(dialect string) error { return fmt.Errorf("error adding config keys to kms: %w", err) } - repo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader)) - if err != nil { - return fmt.Errorf("unable to create repo for org id: %w", err) - } - ctx, cancel := context.WithCancel(context.Background()) go func() { <-b.ShutdownCh @@ -487,6 +484,13 @@ func (b *Server) CreateDevDatabase(dialect string) error { return fmt.Errorf("error saving global scope root key: %w", err) } + if opts.withSkipAuthMethodCreation { + // now that we have passed all the error cases, reset c to be a noop so the + // defer doesn't do anything. + c = func() error { return nil } + return nil + } + // Create the dev auth method pwRepo, err := password.NewRepository(rw, rw, kmsCache) if err != nil { @@ -504,6 +508,8 @@ func (b *Server) CreateDevDatabase(dialect string) error { if err != nil { return fmt.Errorf("error saving auth method to the db: %w", err) } + b.InfoKeys = append(b.InfoKeys, "dev auth method id") + b.Info["dev auth method id"] = amId // Create the dev user acctLoginName := b.DevLoginName @@ -521,6 +527,9 @@ func (b *Server) CreateDevDatabase(dialect string) error { return fmt.Errorf("unable to generate dev password: %w", err) } } + b.InfoKeys = append(b.InfoKeys, "dev password") + b.Info["dev password"] = pw + acct, err := password.NewAccount(amId, password.WithLoginName(acctLoginName)) if err != nil { return fmt.Errorf("error creating new in memory auth account: %w", err) @@ -529,30 +538,31 @@ func (b *Server) CreateDevDatabase(dialect string) error { if err != nil { return fmt.Errorf("error saving auth account to the db: %w", err) } + b.InfoKeys = append(b.InfoKeys, "dev login name") + b.Info["dev login name"] = acct.GetLoginName() // Create a role tying them together + iamRepo, err := iam.NewRepository(rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader)) + if err != nil { + return fmt.Errorf("unable to create repo for org id: %w", err) + } pr, err := iam.NewRole(scope.Global.String()) if err != nil { return fmt.Errorf("error creating in memory role for default dev grants: %w", err) } pr.Name = "Dev Mode Global Scope Admin Role" pr.Description = `Provides admin grants to all authenticated users within the "global" scope` - defPermsRole, err := repo.CreateRole(ctx, pr) + defPermsRole, err := iamRepo.CreateRole(ctx, pr) if err != nil { return fmt.Errorf("error creating role for default dev grants: %w", err) } - if _, err := repo.AddRoleGrants(ctx, defPermsRole.PublicId, defPermsRole.Version, []string{"id=*;actions=*"}); err != nil { + if _, err := iamRepo.AddRoleGrants(ctx, defPermsRole.PublicId, defPermsRole.Version, []string{"id=*;actions=*"}); err != nil { return fmt.Errorf("error creating grant for default dev grants: %w", err) } - if _, err := repo.AddPrincipalRoles(ctx, defPermsRole.PublicId, defPermsRole.Version+1, []string{"u_auth"}, nil); err != nil { + if _, err := iamRepo.AddPrincipalRoles(ctx, defPermsRole.PublicId, defPermsRole.Version+1, []string{"u_auth"}, nil); err != nil { return fmt.Errorf("error adding principal to role for default dev grants: %w", err) } - b.InfoKeys = append(b.InfoKeys, "dev auth method id", "dev login name", "dev password") - b.Info["dev auth method id"] = amId - b.Info["dev login name"] = acct.GetLoginName() - b.Info["dev password"] = pw - // now that we have passed all the error cases, reset c to be a noop so the // defer doesn't do anything. c = func() error { return nil } diff --git a/internal/cmd/commands/controller/controller.go b/internal/cmd/commands/controller/controller.go index ca51a75cb2..01c8eea7ed 100644 --- a/internal/cmd/commands/controller/controller.go +++ b/internal/cmd/commands/controller/controller.go @@ -44,8 +44,8 @@ type Command struct { flagDevPassword string flagDevControllerAPIListenAddr string flagDevControllerClusterListenAddr string - flagDevOrgId string flagDevAuthMethodId string + flagDevSkipAuthMethodCreation bool } func (c *Command) Synopsis() string { @@ -108,14 +108,6 @@ func (c *Command) Flags() *base.FlagSets { "production.", }) - f.StringVar(&base.StringVar{ - Name: "dev-org-id", - Target: &c.flagDevOrgId, - EnvVar: "WATCHTWER_DEV_ORG_ID", - Usage: "Auto-created org ID. This only applies when running in \"dev\" " + - "mode.", - }) - f.StringVar(&base.StringVar{ Name: "dev-auth-method-id", Target: &c.flagDevAuthMethodId, @@ -124,6 +116,12 @@ func (c *Command) Flags() *base.FlagSets { "mode.", }) + f.BoolVar(&base.BoolVar{ + Name: "dev-skip-auth-method-creation", + Target: &c.flagDevSkipAuthMethodCreation, + Usage: "If set, an auth method will not be created as part of the dev instance. The recovery KMS will be needed to perform any actions.", + }) + f.StringVar(&base.StringVar{ Name: "dev-password", Target: &c.flagDevPassword, @@ -275,7 +273,17 @@ func (c *Command) Run(args []string) int { } if c.flagDev { - if err := c.CreateDevDatabase("postgres"); err != nil { + var opts []base.Option + if c.flagDevSkipAuthMethodCreation { + opts = append(opts, base.WithSkipAuthMethodCreation()) + switch { + case c.flagDevAuthMethodId != "", + c.flagDevLoginName != "", + c.flagDevPassword != "": + c.UI.Warn("-dev-skip-auth-method-creation set, skipping any auth-method related flags") + } + } + if err := c.CreateDevDatabase("postgres", opts...); err != nil { c.UI.Error(fmt.Errorf("Error creating dev database container: %s", err.Error()).Error()) return 1 } diff --git a/internal/cmd/commands/dev/dev.go b/internal/cmd/commands/dev/dev.go index 8c1d70a1e3..77f7bbc53a 100644 --- a/internal/cmd/commands/dev/dev.go +++ b/internal/cmd/commands/dev/dev.go @@ -31,10 +31,10 @@ type Command struct { flagCombineLogs bool flagDevLoginName string flagDevPassword string - flagDevOrgId string flagDevAuthMethodId string flagDevControllerAPIListenAddr string flagDevControllerClusterListenAddr string + flagDevSkipAuthMethodCreation bool } func (c *Command) Synopsis() string { @@ -80,14 +80,6 @@ func (c *Command) Flags() *base.FlagSets { f = set.NewFlagSet("Dev Options") - f.StringVar(&base.StringVar{ - Name: "dev-org-id", - Target: &c.flagDevOrgId, - EnvVar: "WATCHTWER_DEV_ORG_ID", - Usage: "Auto-created org ID. This only applies when running in \"dev\" " + - "mode.", - }) - f.StringVar(&base.StringVar{ Name: "dev-auth-method-id", Target: &c.flagDevAuthMethodId, @@ -126,6 +118,12 @@ func (c *Command) Flags() *base.FlagSets { Usage: "Address to bind to for controller \"cluster\" purpose.", }) + f.BoolVar(&base.BoolVar{ + Name: "dev-skip-auth-method-creation", + Target: &c.flagDevSkipAuthMethodCreation, + Usage: "If set, an auth method will not be created as part of the dev instance. The recovery KMS will be needed to perform any actions.", + }) + f.BoolVar(&base.BoolVar{ Name: "combine-logs", Target: &c.flagCombineLogs, @@ -254,7 +252,17 @@ func (c *Command) Run(args []string) int { } }() - if err := c.CreateDevDatabase("postgres"); err != nil { + var opts []base.Option + if c.flagDevSkipAuthMethodCreation { + opts = append(opts, base.WithSkipAuthMethodCreation()) + switch { + case c.flagDevAuthMethodId != "", + c.flagDevLoginName != "", + c.flagDevPassword != "": + c.UI.Warn("-dev-skip-auth-method-creation set, skipping any auth-method related flags") + } + } + if err := c.CreateDevDatabase("postgres", opts...); err != nil { c.UI.Error(fmt.Errorf("Error creating dev database container: %w", err).Error()) return 1 } diff --git a/internal/servers/controller/testing.go b/internal/servers/controller/testing.go index 1ce6bb414e..246361e65d 100644 --- a/internal/servers/controller/testing.go +++ b/internal/servers/controller/testing.go @@ -180,6 +180,10 @@ type TestControllerOpts struct { // DefaultPassword is the password used when creating the default account. DefaultPassword string + // DisableAuthMethodCreation can be set true to disable creating an auth + // method automatically. + DisableAuthMethodCreation bool + // DisableDatabaseCreation can be set true to disable creating a dev // database DisableDatabaseCreation bool @@ -302,7 +306,11 @@ func NewTestController(t *testing.T, opts *TestControllerOpts) *TestController { t.Fatal(err) } } else if !opts.DisableDatabaseCreation { - if err := tc.b.CreateDevDatabase("postgres"); err != nil { + var createOpts []base.Option + if opts.DisableAuthMethodCreation { + createOpts = append(createOpts, base.WithSkipAuthMethodCreation()) + } + if err := tc.b.CreateDevDatabase("postgres", createOpts...); err != nil { t.Fatal(err) } } diff --git a/testing/controller/controller.go b/testing/controller/controller.go index 50c84774d2..f5295b3837 100644 --- a/testing/controller/controller.go +++ b/testing/controller/controller.go @@ -20,17 +20,32 @@ func getOpts(opt ...Option) (*controller.TestControllerOpts, error) { if opts.setWithConfigFile && opts.setWithConfigText { return nil, fmt.Errorf("Cannot provide both WithConfigFile and WithConfigText") } + var setDbParams bool + if opts.setDefaultAuthMethodId || opts.setDefaultLoginName || opts.setDefaultPassword { + setDbParams = true + } + if opts.setDisableAuthMethodCreation { + if setDbParams { + return nil, fmt.Errorf("Cannot both disable auth method creation and provide auth method parameters") + } + } + if opts.setDisableDatabaseCreation { + if setDbParams { + return nil, fmt.Errorf("Cannot both disable database creation and provide auth method parameters") + } + } return opts.tcOptions, nil } type option struct { - tcOptions *controller.TestControllerOpts - setWithConfigFile bool - setWithConfigText bool - setDisableDatabaseCreation bool - setDefaultAuthMethodId bool - setDefaultLoginName bool - setDefaultPassword bool + tcOptions *controller.TestControllerOpts + setWithConfigFile bool + setWithConfigText bool + setDisableAuthMethodCreation bool + setDisableDatabaseCreation bool + setDefaultAuthMethodId bool + setDefaultLoginName bool + setDefaultPassword bool } type Option func(*option) error @@ -69,13 +84,19 @@ func WithConfigText(ct string) Option { } } +// DisableAuthMethodCreation skips creating a default auth method +func DisableAuthMethodCreation() Option { + return func(c *option) error { + c.setDisableAuthMethodCreation = true + c.tcOptions.DisableAuthMethodCreation = true + return nil + } +} + // DisableDatabaseCreation skips creating a database in docker and allows one to // be provided through a tcOptions. func DisableDatabaseCreation() Option { return func(c *option) error { - if c.setDisableDatabaseCreation { - return fmt.Errorf("DisableDatabaseCreation provided more than once.") - } c.setDisableDatabaseCreation = true c.tcOptions.DisableDatabaseCreation = true return nil @@ -84,9 +105,6 @@ func DisableDatabaseCreation() Option { func WithDefaultAuthMethodId(id string) Option { return func(c *option) error { - if c.setDefaultAuthMethodId { - return fmt.Errorf("WithDefaultAuthMethodId provided more than once.") - } c.setDefaultAuthMethodId = true c.tcOptions.DefaultAuthMethodId = id return nil @@ -95,9 +113,6 @@ func WithDefaultAuthMethodId(id string) Option { func WithDefaultLoginName(ln string) Option { return func(c *option) error { - if c.setDefaultLoginName { - return fmt.Errorf("WithDefaultLoginName provided more than once.") - } c.setDefaultLoginName = true c.tcOptions.DefaultLoginName = ln return nil @@ -106,9 +121,6 @@ func WithDefaultLoginName(ln string) Option { func WithDefaultPassword(pw string) Option { return func(c *option) error { - if c.setDefaultPassword { - return fmt.Errorf("WithDefaultPassword provided more than once.") - } c.setDefaultPassword = true c.tcOptions.DefaultPassword = pw return nil