Multiple grant scope IDs (#4251)

Co-authored-by: Timothy Messier <tim.messier@gmail.com>
Co-authored-by: Todd <github@quaddi.com>
This commit is contained in:
authored and GitHub committed 2024-01-23 14:33:09 -05:00
1 parent 659df2797c
commit f5dd457b34
70 files changed
+5460 -1009

No files matched your search

+16 -5
View File
@@ -114,11 +114,19 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
return err
}
if _, err := b.CreateInitialLoginRole(ctx); err != nil {
if c != nil {
err = errors.Join(err, c())
if !opts.withSkipDefaultRoleCreation {
if _, err := b.CreateInitialLoginRole(ctx); err != nil {
if c != nil {
err = errors.Join(err, c())
}
return err
}
if _, err := b.CreateInitialAuthenticatedUserRole(ctx, WithAuthUserTargetAuthorizeSessionGrant(true)); err != nil {
if c != nil {
err = errors.Join(err, c())
}
return err
}
return err
}
if opts.withSkipAuthMethodCreation {
@@ -151,7 +159,10 @@ func (b *Server) CreateDevDatabase(ctx context.Context, opt ...Option) error {
return nil
}
if _, _, err := b.CreateInitialScopes(ctx); err != nil {
if _, _, err := b.CreateInitialScopes(ctx, WithIamOptions(
iam.WithSkipAdminRoleCreation(true),
iam.WithSkipDefaultRoleCreation(true),
)); err != nil {
return err
}
+89 -122
View File
@@ -45,26 +45,84 @@ func (b *Server) CreateInitialLoginRole(ctx context.Context) (*iam.Role, error)
pr, err := iam.NewRole(ctx,
scope.Global.String(),
iam.WithName("Login and Default Grants"),
iam.WithDescription(`Role created for login capability, account self-management, and other default grants for users of the global scope at its creation time`),
iam.WithName("Login Grants"),
iam.WithDescription(`Role created for login capability for unauthenticated users`),
)
if err != nil {
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
role, err := iamRepo.CreateRole(ctx, pr)
role, _, _, _, err := iamRepo.CreateRole(ctx, pr)
if err != nil {
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
}
if _, err := iamRepo.AddRoleGrants(ctx, role.PublicId, role.Version, []string{
"ids=*;type=scope;actions=list,no-op",
"ids=*;type=auth-method;actions=authenticate,list",
"ids={{.Account.Id}};actions=read,change-password",
"ids=*;type=auth-token;actions=list,read:self,delete:self",
"ids=*;type=auth-method;actions=list,authenticate",
"ids=*;type=auth-token;actions=read:self,delete:self",
}); err != nil {
return nil, fmt.Errorf("error creating grant for default generated grants: %w", err)
return nil, fmt.Errorf("error creating grant for initial login grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnonymousUserId}, nil); err != nil {
return nil, fmt.Errorf("error adding principal to role for default generated grants: %w", err)
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnonymousUserId}); err != nil {
return nil, fmt.Errorf("error adding principal to role for initial login grants: %w", err)
}
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, role.PublicId, role.Version+2, []string{"this", "descendants"}); err != nil {
return nil, fmt.Errorf("error adding scope grants to role for initial login grants: %w", err)
}
return role, nil
}
func (b *Server) CreateInitialAuthenticatedUserRole(ctx context.Context, opt ...Option) (*iam.Role, error) {
rw := db.New(b.Database)
kmsCache, err := kms.New(ctx, rw, rw)
if err != nil {
return nil, fmt.Errorf("error creating kms cache: %w", err)
}
if err := kmsCache.AddExternalWrappers(
b.Context,
kms.WithRootWrapper(b.RootKms),
); err != nil {
return nil, fmt.Errorf("error adding config keys to kms: %w", err)
}
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
if err != nil {
return nil, fmt.Errorf("unable to create repo for initial login role: %w", err)
}
pr, err := iam.NewRole(ctx,
scope.Global.String(),
iam.WithName("Authenticated User Grants"),
iam.WithDescription(`Role created for account self-management, and other initial authenticated user grants`),
)
if err != nil {
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
role, _, _, _, err := iamRepo.CreateRole(ctx, pr)
if err != nil {
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
}
grants := []string{
"ids=*;type=scope;actions=read",
"ids=*;type=auth-token;actions=list",
"ids={{.Account.Id}};actions=read,change-password",
"ids=*;type=session;actions=list,read:self,cancel:self",
}
opts := GetOpts(opt...)
if opts.withAuthUserTargetAuthorizeSessionGrant {
grants = append(grants, "ids=*;type=target;actions=list,read,authorize-session")
} else {
grants = append(grants, "ids=*;type=target;actions=list,read")
}
if _, err := iamRepo.AddRoleGrants(ctx, role.PublicId, role.Version, grants); err != nil {
return nil, fmt.Errorf("error creating grant for initial authenticated user grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(ctx, role.PublicId, role.Version+1, []string{globals.AnyAuthenticatedUserId}); err != nil {
return nil, fmt.Errorf("error adding principal to role for initial authenticated user grants: %w", err)
}
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, role.PublicId, role.Version+2, []string{"this", "descendants"}); err != nil {
return nil, fmt.Errorf("error adding scope grants to role for initial authenticated user grants: %w", err)
}
return role, nil
@@ -201,21 +259,24 @@ func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password
pr, err := iam.NewRole(ctx,
scope.Global.String(),
iam.WithName("Administration"),
iam.WithDescription(fmt.Sprintf(`Provides admin grants within the "%s" scope to the initial user`, scope.Global.String())),
iam.WithDescription("Provides admin grants within all scopes to the initial admin user"),
)
if err != nil {
return nil, fmt.Errorf("error creating in memory role for generated grants: %w", err)
}
defPermsRole, err := iamRepo.CreateRole(ctx, pr)
adminRole, _, _, _, err := iamRepo.CreateRole(ctx, pr)
if err != nil {
return nil, fmt.Errorf("error creating role for default generated grants: %w", err)
}
if _, err := iamRepo.AddRoleGrants(ctx, defPermsRole.PublicId, defPermsRole.Version, []string{"ids=*;type=*;actions=*"}); err != nil {
if _, err := iamRepo.AddRoleGrants(ctx, adminRole.PublicId, adminRole.Version, []string{"ids=*;type=*;actions=*"}); err != nil {
return nil, fmt.Errorf("error creating grant for default generated grants: %w", err)
}
if _, err := iamRepo.AddPrincipalRoles(ctx, defPermsRole.PublicId, defPermsRole.Version+1, []string{u.GetPublicId()}, nil); err != nil {
if _, err := iamRepo.AddPrincipalRoles(ctx, adminRole.PublicId, adminRole.Version+1, []string{u.GetPublicId()}, nil); err != nil {
return nil, fmt.Errorf("error adding principal to role for default generated grants: %w", err)
}
if _, _, err := iamRepo.SetRoleGrantScopes(ctx, adminRole.PublicId, adminRole.Version+2, []string{"this", "descendants"}); err != nil {
return nil, fmt.Errorf("error adding scope grants to role for default generated grants: %w", err)
}
return u, nil
}
@@ -256,7 +317,7 @@ func (b *Server) CreateInitialPasswordAuthMethod(ctx context.Context) (*password
return am, u, nil
}
func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scope, error) {
func (b *Server) CreateInitialScopes(ctx context.Context, opt ...Option) (*iam.Scope, *iam.Scope, error) {
rw := db.New(b.Database)
kmsCache, err := kms.New(ctx, rw, rw)
@@ -270,6 +331,8 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
return nil, nil, fmt.Errorf("error adding config keys to kms: %w", err)
}
opts := GetOpts(opt...)
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache)
if err != nil {
return nil, nil, fmt.Errorf("error creating scopes repository: %w", err)
@@ -282,17 +345,20 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
return nil, nil, fmt.Errorf("error generating initial org id: %w", err)
}
}
opts := []iam.Option{
iamOpts := []iam.Option{
iam.WithName("Generated org scope"),
iam.WithDescription("Provides an initial org scope in Boundary"),
iam.WithRandomReader(b.SecureRandomReader),
iam.WithPublicId(b.DevOrgId),
}
orgScope, err := iam.NewOrg(ctx, opts...)
if len(opts.withIamOptions) > 0 {
iamOpts = append(iamOpts, opts.withIamOptions...)
}
orgScope, err := iam.NewOrg(ctx, iamOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating new in memory org scope: %w", err)
}
orgScope, err = iamRepo.CreateScope(ctx, orgScope, b.DevUserId, opts...)
orgScope, err = iamRepo.CreateScope(ctx, orgScope, b.DevUserId, iamOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error saving org scope to the db: %w", err)
}
@@ -305,17 +371,20 @@ func (b *Server) CreateInitialScopes(ctx context.Context) (*iam.Scope, *iam.Scop
return nil, nil, fmt.Errorf("error generating initial project id: %w", err)
}
}
opts = []iam.Option{
iamOpts = []iam.Option{
iam.WithName("Generated project scope"),
iam.WithDescription("Provides an initial project scope in Boundary"),
iam.WithRandomReader(b.SecureRandomReader),
iam.WithPublicId(b.DevProjectId),
}
projScope, err := iam.NewProject(ctx, b.DevOrgId, opts...)
if len(opts.withIamOptions) > 0 {
iamOpts = append(iamOpts, opts.withIamOptions...)
}
projScope, err := iam.NewProject(ctx, b.DevOrgId, iamOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error creating new in memory project scope: %w", err)
}
projScope, err = iamRepo.CreateScope(ctx, projScope, b.DevUserId, opts...)
projScope, err = iamRepo.CreateScope(ctx, projScope, b.DevUserId, iamOpts...)
if err != nil {
return nil, nil, fmt.Errorf("error saving project scope to the db: %w", err)
}
@@ -472,17 +541,6 @@ func (b *Server) CreateInitialTargetWithAddress(ctx context.Context) (target.Tar
b.InfoKeys = append(b.InfoKeys, "generated target with address id")
b.Info["generated target with address id"] = b.DevTargetId
if b.DevUnprivilegedUserId != "" {
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
if err != nil {
return nil, fmt.Errorf("failed to create iam repository: %w", err)
}
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevTargetId)
if err != nil {
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
}
}
return tt, nil
}
@@ -540,17 +598,6 @@ func (b *Server) CreateInitialTargetWithHostSources(ctx context.Context) (target
b.InfoKeys = append(b.InfoKeys, "generated target with host source id")
b.Info["generated target with host source id"] = b.DevSecondaryTargetId
if b.DevUnprivilegedUserId != "" {
iamRepo, err := iam.NewRepository(ctx, rw, rw, kmsCache, iam.WithRandomReader(b.SecureRandomReader))
if err != nil {
return nil, fmt.Errorf("failed to create iam repository: %w", err)
}
err = unprivilegedDevUserRoleSetup(ctx, iamRepo, b.DevUnprivilegedUserId, b.DevProjectId, b.DevSecondaryTargetId)
if err != nil {
return nil, fmt.Errorf("failed to set up unprivileged dev user: %w", err)
}
}
return tt, nil
}
@@ -626,83 +673,3 @@ func (b *Server) RegisterPlugin(ctx context.Context, name string, hostClient plg
return plg, nil
}
// unprivilegedDevUserRoleSetup adds dev user to the role that grants
// list/read:self/cancel:self on sessions and read:self/delete:self/list on
// tokens. It also creates a role with an `authorize-session` grant for the
// provided targetId.
func unprivilegedDevUserRoleSetup(ctx context.Context, repo *iam.Repository, userId, projectId, targetId string) error {
noopFilter := func(ctx context.Context, item *iam.Role) (bool, error) {
return true, nil
}
roles, err := iam.ListRoles(ctx, []byte("dummy grant"), globals.DefaultMaxPageSize, noopFilter, repo, []string{projectId})
if err != nil {
return fmt.Errorf("failed to list existing roles for project id %q: %w", projectId, err)
}
// Look for default grants role to set unprivileged user as a principal.
defaultRoleIdx := -1
for i, r := range roles.Items {
// Hacky, I know, but saves a DB trip to look up other
// characteristics like "if any principals are currently attached".
// No matter what we pick here it's a bit heuristical.
if r.Name == "Default Grants" {
defaultRoleIdx = i
break
}
}
if defaultRoleIdx == -1 {
return fmt.Errorf("couldn't find default grants role for project id %q", projectId)
}
defaultRole := roles.Items[defaultRoleIdx]
// This function may be called more than once for the same boundary
// deployment (eg: if we're creating more than one target), so we need to
// check if the unprivileged user is not already a principal for the default
// role in this project, as attempting to add an existing principal is an
// error.
principals, err := repo.ListPrincipalRoles(ctx, defaultRole.GetPublicId())
if err != nil {
return fmt.Errorf("failed to list principals for default project role: %w", err)
}
found := false
for _, p := range principals {
if p.PrincipalId == userId {
found = true
}
}
if !found {
_, err = repo.AddPrincipalRoles(ctx, defaultRole.GetPublicId(), defaultRole.GetVersion(), []string{userId})
if err != nil {
return fmt.Errorf("failed to add %q as principal for role id %q", userId, defaultRole.GetPublicId())
}
defaultRole.Version++ // The above call increments the role version in the database, so we must also track that with our state.
}
// Create a new role for the "authorize-session" grant and add the
// unprivileged user as a principal.
asRole, err := iam.NewRole(ctx,
projectId,
iam.WithName(fmt.Sprintf("Session authorization for %s", targetId)),
iam.WithDescription(fmt.Sprintf("Provides grants within the dev project scope to allow the initial unprivileged user to authorize sessions against %s", targetId)),
)
if err != nil {
return fmt.Errorf("failed to create role object: %w", err)
}
asRole, err = repo.CreateRole(ctx, asRole)
if err != nil {
return fmt.Errorf("failed to create role for unprivileged user: %w", err)
}
if _, err := repo.AddPrincipalRoles(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{userId}, nil); err != nil {
return fmt.Errorf("failed to add unprivileged user as principal to new role: %w", err)
}
asRole.Version++
_, err = repo.AddRoleGrants(ctx, asRole.GetPublicId(), asRole.GetVersion(), []string{fmt.Sprintf("ids=%s;actions=authorize-session", targetId)})
if err != nil {
return fmt.Errorf("failed to add authorize-session grant for unprivileged user: %w", err)
}
return nil
}
+51 -22
View File
@@ -5,6 +5,7 @@ package base
import (
"github.com/hashicorp/boundary/internal/event"
"github.com/hashicorp/boundary/internal/iam"
"github.com/hashicorp/boundary/sdk/pbs/plugin"
wrapping "github.com/hashicorp/go-kms-wrapping/v2"
)
@@ -25,28 +26,31 @@ type Option func(*Options)
// Options - how Options are represented.
type Options struct {
withNoTokenScope bool
withNoTokenValue bool
withSkipDatabaseDestruction bool
withSkipAuthMethodCreation bool
withSkipOidcAuthMethodCreation bool
withSkipLdapAuthMethodCreation bool
withSkipScopesCreation bool
withSkipHostResourcesCreation bool
withSkipTargetCreation bool
withContainerImage string
withDialect string
withDatabaseTemplate string
withEventerConfig *event.EventerConfig
withEventFlags *EventFlags
withEventWrapper wrapping.Wrapper
withAttributeFieldPrefix string
withStatusCode int
withHostPlugin func() (string, plugin.HostPluginServiceClient)
withEventGating bool
withImplicitId string
WithSkipScopeIdFlag bool
WithInterceptedToken *string
withNoTokenScope bool
withNoTokenValue bool
withSkipDefaultRoleCreation bool
withSkipDatabaseDestruction bool
withSkipAuthMethodCreation bool
withSkipOidcAuthMethodCreation bool
withSkipLdapAuthMethodCreation bool
withSkipScopesCreation bool
withSkipHostResourcesCreation bool
withSkipTargetCreation bool
withContainerImage string
withDialect string
withDatabaseTemplate string
withEventerConfig *event.EventerConfig
withEventFlags *EventFlags
withEventWrapper wrapping.Wrapper
withAttributeFieldPrefix string
withStatusCode int
withHostPlugin func() (string, plugin.HostPluginServiceClient)
withEventGating bool
withImplicitId string
WithSkipScopeIdFlag bool
WithInterceptedToken *string
withAuthUserTargetAuthorizeSessionGrant bool
withIamOptions []iam.Option
}
func getDefaultOptions() Options {
@@ -81,6 +85,14 @@ func WithNoTokenValue() Option {
}
}
// WithSkipDefaultRoleCreation tells the command not to instantiate the default
// global role
func WithSkipDefaultRoleCreation() Option {
return func(o *Options) {
o.withSkipDefaultRoleCreation = true
}
}
// WithSkipAuthMethodCreation tells the command not to instantiate any auth
// method on first run.
func WithSkipAuthMethodCreation() Option {
@@ -227,3 +239,20 @@ func WithInterceptedToken(s *string) Option {
o.WithInterceptedToken = s
}
}
// WithAuthUserTargetAuthorizeSessionGrant indicates that we should add an
// authorize-session grant to the global authenticated user role. This is the
// default for dev mode.
func WithAuthUserTargetAuthorizeSessionGrant(with bool) Option {
return func(o *Options) {
o.withAuthUserTargetAuthorizeSessionGrant = with
}
}
// WithIamOptions provides options to pass through to the IAM package when
// creating initial resources
func WithIamOptions(with ...iam.Option) Option {
return func(o *Options) {
o.withIamOptions = with
}
}
+24
View File
@@ -7,6 +7,7 @@ import (
"testing"
"github.com/hashicorp/boundary/internal/event"
"github.com/hashicorp/boundary/internal/iam"
"github.com/stretchr/testify/assert"
)
@@ -71,6 +72,13 @@ func Test_GetOpts(t *testing.T) {
testOpts.withNoTokenValue = true
assert.Equal(opts, testOpts)
})
t.Run("WithSkipDefaultRoleCreation", func(t *testing.T) {
assert := assert.New(t)
opts := GetOpts(WithSkipDefaultRoleCreation())
testOpts := getDefaultOptions()
testOpts.withSkipDefaultRoleCreation = true
assert.Equal(opts, testOpts)
})
t.Run("WithSkipAuthMethodCreation", func(t *testing.T) {
assert := assert.New(t)
opts := GetOpts(WithSkipAuthMethodCreation())
@@ -151,4 +159,20 @@ func Test_GetOpts(t *testing.T) {
testOpts.WithInterceptedToken = &s
assert.Equal(opts, testOpts)
})
t.Run("WithAuthUserTargetAuthorizeSessionGrant", func(t *testing.T) {
assert := assert.New(t)
opts := getDefaultOptions()
assert.False(opts.withAuthUserTargetAuthorizeSessionGrant)
opts = GetOpts(WithAuthUserTargetAuthorizeSessionGrant(true))
assert.True(opts.withAuthUserTargetAuthorizeSessionGrant)
})
t.Run("WithIamOptions", func(t *testing.T) {
assert := assert.New(t)
testOpts := getDefaultOptions()
assert.Len(testOpts.withIamOptions, 0)
opts := GetOpts(WithIamOptions(iam.WithSkipAdminRoleCreation(true)))
assert.Len(opts.withIamOptions, 1)
})
}
+15
View File
@@ -895,6 +895,21 @@ func initCommands(ui, serverCmdUi cli.Ui, runOpts *RunOptions) {
Command: base.NewCommand(ui, opts...),
Func: "remove-grants",
}),
"roles add-grant-scopes": clientCacheWrapper(
&rolescmd.Command{
Command: base.NewCommand(ui, opts...),
Func: "add-grant-scopes",
}),
"roles set-grant-scopes": clientCacheWrapper(
&rolescmd.Command{
Command: base.NewCommand(ui, opts...),
Func: "set-grant-scopes",
}),
"roles remove-grant-scopes": clientCacheWrapper(
&rolescmd.Command{
Command: base.NewCommand(ui, opts...),
Func: "remove-grant-scopes",
}),
"scopes": func() (cli.Command, error) {
return &scopescmd.Command{
@@ -71,6 +71,13 @@ func (c *Command) Flags() *base.FlagSets {
}
func (c *Command) Run(args []string) int {
f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
client, err := c.Client(base.WithNoTokenScope(), base.WithNoTokenValue())
if c.WrapperCleanupFunc != nil {
defer func() {
@@ -84,13 +91,6 @@ func (c *Command) Run(args []string) int {
return base.CommandCliError
}
f := c.Flags()
if err := f.Parse(args); err != nil {
c.PrintCliError(err)
return base.CommandUserError
}
// Lookup the primary auth method ID in the global scope
aClient := authmethods.NewClient(client)
pri, err := getPrimaryAuthMethodId(c.Context, aClient, scope.Global.String(), "")
+23 -1
View File
@@ -107,7 +107,7 @@ type RoleInfo struct {
Name string `json:"name"`
}
func generateInitialRoleTableOutput(in *RoleInfo) string {
func generateInitialLoginRoleTableOutput(in *RoleInfo) string {
nonAttributeMap := map[string]any{
"Role ID": in.RoleId,
"Name": in.Name,
@@ -129,6 +129,28 @@ func generateInitialRoleTableOutput(in *RoleInfo) string {
return base.WrapForHelpText(ret)
}
func generateInitialAuthenticatedUserRoleOutput(in *RoleInfo) string {
nonAttributeMap := map[string]any{
"Role ID": in.RoleId,
"Name": in.Name,
}
maxLength := 0
for k := range nonAttributeMap {
if len(k) > maxLength {
maxLength = len(k)
}
}
ret := []string{
"",
"Initial authenticated user role information:",
base.WrapMap(2, maxLength+2, nonAttributeMap),
}
return base.WrapForHelpText(ret)
}
type AuthInfo struct {
AuthMethodId string `json:"auth_method_id"`
AuthMethodName string `json:"auth_method_name"`
+44 -16
View File
@@ -37,16 +37,17 @@ type InitCommand struct {
// deferred function on the Run method.
configWrapperCleanupFunc func() error
flagConfig []string
flagConfigKms string
flagLogLevel string
flagLogFormat string
flagMigrationUrl string
flagSkipInitialLoginRoleCreation bool
flagSkipAuthMethodCreation bool
flagSkipScopesCreation bool
flagSkipHostResourcesCreation bool
flagSkipTargetCreation bool
flagConfig []string
flagConfigKms string
flagLogLevel string
flagLogFormat string
flagMigrationUrl string
flagSkipInitialLoginRoleCreation bool
flagSkipInitialAuthenticatedUserRoleCreation bool
flagSkipAuthMethodCreation bool
flagSkipScopesCreation bool
flagSkipHostResourcesCreation bool
flagSkipTargetCreation bool
}
func (c *InitCommand) Synopsis() string {
@@ -124,31 +125,37 @@ func (c *InitCommand) Flags() *base.FlagSets {
f.BoolVar(&base.BoolVar{
Name: "skip-initial-login-role-creation",
Target: &c.flagSkipInitialLoginRoleCreation,
Usage: "If not set, a default role allowing necessary grants for logging in will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
Usage: "If set, a role providing necessary grants for logging in will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-initial-authenticated-user-role-creation",
Target: &c.flagSkipInitialAuthenticatedUserRoleCreation,
Usage: "If set, a role providing initial grants for any authenticated user will not be created as part of initialization.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-auth-method-creation",
Target: &c.flagSkipAuthMethodCreation,
Usage: "If not set, an auth method will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
Usage: "If set, an auth method will not be created as part of initialization. If set, the recovery KMS will be needed to perform any actions.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-scopes-creation",
Target: &c.flagSkipScopesCreation,
Usage: "If not set, scopes will not be created as part of initialization.",
Usage: "If set, scopes will not be created as part of initialization.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-host-resources-creation",
Target: &c.flagSkipHostResourcesCreation,
Usage: "If not set, host resources (host catalog, host set, host) will not be created as part of initialization.",
Usage: "If set, host resources (host catalog, host set, host) will not be created as part of initialization.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-target-creation",
Target: &c.flagSkipTargetCreation,
Usage: "If not set, a target will not be created as part of initialization.",
Usage: "If set, a target will not be created as part of initialization.",
})
f.StringVar(&base.StringVar{
@@ -330,11 +337,32 @@ func (c *InitCommand) Run(args []string) (retCode int) {
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialRoleTableOutput(roleInfo))
c.UI.Output(generateInitialLoginRoleTableOutput(roleInfo))
case "json":
jsonMap["login_role"] = roleInfo
}
if c.flagSkipInitialAuthenticatedUserRoleCreation {
return base.CommandSuccess
}
role, err = c.CreateInitialAuthenticatedUserRole(c.Context)
if err != nil {
c.UI.Error(fmt.Errorf("Error creating initial global-scoped authenticated user role: %w", err).Error())
return base.CommandCliError
}
roleInfo = &RoleInfo{
RoleId: role.PublicId,
Name: role.Name,
}
switch base.Format(c.UI) {
case "table":
c.UI.Output(generateInitialAuthenticatedUserRoleOutput(roleInfo))
case "json":
jsonMap["authenticated_user_role"] = roleInfo
}
if c.flagSkipAuthMethodCreation {
return base.CommandSuccess
}
+22 -4
View File
@@ -79,7 +79,7 @@ type Command struct {
flagTargetDefaultPort int
flagTargetSessionMaxSeconds int
flagTargetSessionConnectionLimit int
flagControllerAPIListenAddr string
flagControllerApiListenAddr string
flagControllerClusterListenAddr string
flagControllerPublicClusterAddr string
flagControllerOnly bool
@@ -102,6 +102,8 @@ type Command struct {
flagCreateLoopbackPlugin bool
flagPluginExecutionDir string
flagSkipPlugins bool
flagSkipOidcAuthMethodCreation bool
flagSkipLdapAuthMethodCreation bool
flagWorkerDnsServer string
flagWorkerAuthMethod string
flagWorkerAuthStorageDir string
@@ -202,7 +204,7 @@ func (c *Command) Flags() *base.FlagSets {
f.StringVar(&base.StringVar{
Name: "api-listen-address",
Target: &c.flagControllerAPIListenAddr,
Target: &c.flagControllerApiListenAddr,
EnvVar: "BOUNDARY_DEV_CONTROLLER_API_LISTEN_ADDRESS",
Usage: "Address to bind to for controller \"api\" purpose. If this begins with a forward slash, it will be assumed to be a Unix domain socket path.",
})
@@ -381,6 +383,16 @@ func (c *Command) Flags() *base.FlagSets {
Usage: "Skip loading compiled-in plugins. This does not prevent loopback plugins from being loaded if enabled.",
Hidden: true,
})
f.BoolVar(&base.BoolVar{
Name: "skip-oidc-auth-method-creation",
Target: &c.flagSkipOidcAuthMethodCreation,
Usage: "Skip creating a test OIDC auth method. This is useful if e.g. running a Unix API listener.",
})
f.BoolVar(&base.BoolVar{
Name: "skip-ldap-auth-method-creation",
Target: &c.flagSkipLdapAuthMethodCreation,
Usage: "Skip creating a test LDAP auth method. This is useful if e.g. running a Unix API listener.",
})
f.StringVar(&base.StringVar{
Name: "worker-dns-server",
Target: &c.flagWorkerDnsServer,
@@ -594,8 +606,8 @@ func (c *Command) Run(args []string) int {
}
switch l.Purpose[0] {
case "api":
if c.flagControllerAPIListenAddr != "" {
l.Address = c.flagControllerAPIListenAddr
if c.flagControllerApiListenAddr != "" {
l.Address = c.flagControllerApiListenAddr
}
if strings.HasPrefix(l.Address, "/") {
l.Type = "unix"
@@ -750,6 +762,12 @@ func (c *Command) Run(args []string) int {
}
var opts []base.Option
if c.flagSkipOidcAuthMethodCreation {
opts = append(opts, base.WithSkipOidcAuthMethodCreation())
}
if c.flagSkipLdapAuthMethodCreation {
opts = append(opts, base.WithSkipLdapAuthMethodCreation())
}
if c.flagCreateLoopbackPlugin {
c.DevLoopbackPluginId = "pl_1234567890"
c.EnabledPlugins = append(c.EnabledPlugins, base.EnabledPluginLoopback)
+115 -29
View File
@@ -26,41 +26,42 @@ func init() {
}
type extraCmdVars struct {
flagGrantScopeId string
flagPrincipals []string
flagGrants []string
flagGrantScopeIds []string
flagPrincipals []string
flagGrants []string
}
func extraActionsFlagsMapFuncImpl() map[string][]string {
return map[string][]string{
"create": {"grant-scope-id"},
"update": {"grant-scope-id"},
"add-principals": {"id", "principal", "version"},
"set-principals": {"id", "principal", "version"},
"remove-principals": {"id", "principal", "version"},
"add-grants": {"id", "grant", "version"},
"set-grants": {"id", "grant", "version"},
"remove-grants": {"id", "grant", "version"},
"create": {"grant-scope-id"},
"update": {"grant-scope-id"},
"add-principals": {"id", "principal", "version"},
"set-principals": {"id", "principal", "version"},
"remove-principals": {"id", "principal", "version"},
"add-grants": {"id", "grant", "version"},
"set-grants": {"id", "grant", "version"},
"remove-grants": {"id", "grant", "version"},
"add-grant-scopes": {"id", "grant-scope-id", "version"},
"set-grant-scopes": {"id", "grant-scope-id", "version"},
"remove-grant-scopes": {"id", "grant-scope-id", "version"},
}
}
func extraSynopsisFuncImpl(c *Command) string {
switch c.Func {
case "add-principals", "set-principals", "remove-principals":
return c.principalsGrantsSynopsisFunc(c.Func, true)
return c.principalsGrantsSynopsisFunc(c.Func, "principals (users, groups)")
case "add-grants", "set-grants", "remove-grants":
return c.principalsGrantsSynopsisFunc(c.Func, false)
return c.principalsGrantsSynopsisFunc(c.Func, "grants")
case "add-grant-scopes":
return c.principalsGrantsSynopsisFunc(c.Func, "grant scopes")
}
return ""
}
func (c *Command) principalsGrantsSynopsisFunc(inFunc string, principals bool) string {
func (c *Command) principalsGrantsSynopsisFunc(inFunc, switchStr string) string {
var in string
switchStr := "principals (users, groups)"
if !principals {
switchStr = "grants"
}
switch {
case strings.HasPrefix(inFunc, "add"):
in = fmt.Sprintf("Add %s to", switchStr)
@@ -141,6 +142,39 @@ func (c *Command) extraHelpFunc(helpMap map[string]func() string) string {
"",
})
case "add-grant-scopes":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles add-grant-scopes [options] [args]",
"",
` Adds grant scopes to a role given its ID. The "grant-scope-id" flag can be specified multiple times. Example:`,
"",
` $ boundary roles add-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
"",
"",
})
case "set-grant-scopes":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles set-grant-scopes [options] [args]",
"",
` Sets the complete set of grant scopes on a role given its ID. The "grant-scope-id" flag can be specified multiple times. Example:`,
"",
` $ boundary roles set-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
"",
"",
})
case "remove-grant-scopes":
helpStr = base.WrapForHelpText([]string{
"Usage: boundary roles remove-grant-scopes [options] [args]",
"",
` Removes grant scopes from a role given its ID. The "grant-scope-id" flags can be specified multiple times. Example:`,
"",
` $ boundary roles remove-grant-scopes -id o_1234567890 -grant-scope-id "this" -grant-scope-id "children"`,
"",
"",
})
default:
helpStr = helpMap["base"]()
}
@@ -151,10 +185,10 @@ func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
for _, name := range flagsMap[c.Func] {
switch name {
case "grant-scope-id":
f.StringVar(&base.StringVar{
f.StringSliceVar(&base.StringSliceVar{
Name: "grant-scope-id",
Target: &c.flagGrantScopeId,
Usage: "The scope ID for grants set on the role",
Target: &c.flagGrantScopeIds,
Usage: "The scope IDs to inherit grants set on the role",
})
case "principal":
f.StringSliceVar(&base.StringSliceVar{
@@ -173,15 +207,21 @@ func extraFlagsFuncImpl(c *Command, _ *base.FlagSets, f *base.FlagSet) {
}
func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Option) bool {
switch c.flagGrantScopeId {
case "":
case "null":
*opts = append(*opts, roles.DefaultGrantScopeId())
default:
*opts = append(*opts, roles.WithGrantScopeId(c.flagGrantScopeId))
}
switch c.Func {
case "create", "update":
switch len(c.flagGrantScopeIds) {
case 0:
case 1:
if c.flagGrantScopeIds[0] == "null" {
*opts = append(*opts, roles.DefaultGrantScopeId())
} else {
*opts = append(*opts, roles.WithGrantScopeId(c.flagGrantScopeIds[0]))
}
default:
c.UI.Error("-grant-scope-id cannot be specified multiple times when using the deprecated create/update grant_scope_id mechanism")
return false
}
case "add-principals", "remove-principals":
if len(c.flagPrincipals) == 0 {
c.UI.Error("No principals supplied via -principal")
@@ -194,6 +234,12 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Opti
return false
}
case "add-grant-scopes", "remove-grant-scopes":
if len(c.flagGrantScopeIds) == 0 {
c.UI.Error("No grant scope IDs supplied via -grant-scope-id")
return false
}
case "set-principals":
switch len(c.flagPrincipals) {
case 0:
@@ -215,6 +261,17 @@ func extraFlagsHandlingFuncImpl(c *Command, _ *base.FlagSets, opts *[]roles.Opti
c.flagGrants = nil
}
}
case "set-grant-scopes":
switch len(c.flagGrantScopeIds) {
case 0:
c.UI.Error("No grant scope IDs supplied via -grant-scope-id")
return false
case 1:
if c.flagGrantScopeIds[0] == "null" {
c.flagGrantScopeIds = nil
}
}
}
if len(c.flagGrants) > 0 {
@@ -277,6 +334,24 @@ func executeExtraActionsImpl(c *Command, origResp *api.Response, origItem *roles
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "add-grant-scopes":
result, err := roleClient.AddGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "set-grant-scopes":
result, err := roleClient.SetGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
case "remove-grant-scopes":
result, err := roleClient.RemoveGrantScopes(c.Context, c.FlagId, version, c.flagGrantScopeIds, opts...)
if err != nil {
return nil, nil, nil, err
}
return result.GetResponse(), result.GetItem(), nil, err
}
return origResp, origItem, origItems, origError
}
@@ -407,6 +482,17 @@ func printItemTable(item *roles.Role, resp *api.Response) string {
fmt.Sprintf(" %s", grant.Canonical),
)
}
if len(item.GrantScopeIds) > 0 {
ret = append(ret,
"",
fmt.Sprintf(" Grant Scope IDs: %s", ""),
)
}
for _, grantScope := range item.GrantScopeIds {
ret = append(ret,
fmt.Sprintf(" ID: %s", grantScope),
)
}
return base.WrapForHelpText(ret)
}
@@ -269,6 +269,30 @@ func (c *Command) Run(args []string) int {
version = uint32(c.FlagVersion)
}
case "add-grant-scopes":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "remove-grant-scopes":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
case "set-grant-scopes":
switch c.FlagVersion {
case 0:
opts = append(opts, roles.WithAutomaticVersioning(true))
default:
version = uint32(c.FlagVersion)
}
}
if ok := extraFlagsHandlingFunc(c, f, &opts); !ok {
+1 -1
View File
@@ -567,7 +567,7 @@ var inputStructs = map[string][]*cmdInfo{
Container: "Scope",
HasName: true,
HasDescription: true,
VersionedActions: []string{"update", "add-grants", "remove-grants", "set-grants", "add-principals", "remove-principals", "set-principals"},
VersionedActions: []string{"update", "add-grants", "remove-grants", "set-grants", "add-principals", "remove-principals", "set-principals", "add-grant-scopes", "remove-grant-scopes", "set-grant-scopes"},
},
},
"scopes": {