From df0c92771652945b621947f3c1c169098f12a48b Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Fri, 5 Apr 2019 15:36:29 +0200 Subject: [PATCH 01/16] Implemented token backend support for identity --- api/auth_token.go | 1 + command/token_create.go | 12 ++ vault/token_store.go | 93 +++++++++++++-- vault/token_store_test.go | 243 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 340 insertions(+), 9 deletions(-) diff --git a/api/auth_token.go b/api/auth_token.go index ed594eee8528..6807c89c3878 100644 --- a/api/auth_token.go +++ b/api/auth_token.go @@ -272,4 +272,5 @@ type TokenCreateRequest struct { NumUses int `json:"num_uses"` Renewable *bool `json:"renewable,omitempty"` Type string `json:"type"` + EntityAlias string `json:"entity_alias"` } diff --git a/command/token_create.go b/command/token_create.go index 7c454ff9ba9c..e564a3375a8f 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -29,6 +29,7 @@ type TokenCreateCommand struct { flagType string flagMetadata map[string]string flagPolicies []string + flagEntityAlias string } func (c *TokenCreateCommand) Synopsis() string { @@ -176,6 +177,16 @@ func (c *TokenCreateCommand) Flags() *FlagSets { "specified multiple times to attach multiple policies.", }) + f.StringVar(&StringVar{ + Name: "entity-alias", + Target: &c.flagEntityAlias, + Default: "", + Usage: "Name of the entity alias to associate with during token creation. " + + "Only works in combination with -role argument and used entity alias " + + "must be listed in allowed entity aliases. If this has been specified, " + + "the entity will not be inherited from the parent.", + }) + return set } @@ -224,6 +235,7 @@ func (c *TokenCreateCommand) Run(args []string) int { ExplicitMaxTTL: c.flagExplicitMaxTTL.String(), Period: c.flagPeriod.String(), Type: c.flagType, + EntityAlias: c.flagEntityAlias, } var secret *api.Secret diff --git a/vault/token_store.go b/vault/token_store.go index 1eb14b0ee3a7..f6f142384906 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -14,10 +14,10 @@ import ( "strings" "time" - proto "github.com/golang/protobuf/proto" + "github.com/golang/protobuf/proto" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" - sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/go-sockaddr" metrics "github.com/armon/go-metrics" multierror "github.com/hashicorp/go-multierror" @@ -397,6 +397,11 @@ func (ts *TokenStore) paths() []*framework.Path { Description: "Use 'token_bound_cidrs' instead.", Deprecated: true, }, + + "allowed_entity_aliases": &framework.FieldSchema{ + Type: framework.TypeStringSlice, + Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation.", + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ @@ -611,6 +616,9 @@ type tsRoleEntry struct { // The set of CIDRs that tokens generated using this role will be bound to BoundCIDRs []*sockaddr.SockAddrMarshaler `json:"bound_cidrs"` + + // The set of allowed entity aliases used during token creation + AllowedEntityAliases []string `json:"allowed_entity_aliases" mapstructure:"allowed_entity_aliases" structs:"allowed_entity_aliases"` } type accessorEntry struct { @@ -1819,11 +1827,11 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data } var countAccessorList, - countCubbyholeKeys, - deletedCountAccessorEmptyToken, - deletedCountAccessorInvalidToken, - deletedCountInvalidTokenInAccessor, - deletedCountInvalidCubbyholeKey int64 + countCubbyholeKeys, + deletedCountAccessorEmptyToken, + deletedCountAccessorInvalidToken, + deletedCountInvalidTokenInAccessor, + deletedCountInvalidCubbyholeKey int64 validCubbyholeKeys := make(map[string]bool) @@ -2106,6 +2114,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque NumUses int `mapstructure:"num_uses"` Period string Type string `mapstructure:"type"` + EntityAlias string } if err := mapstructure.WeakDecode(req.Data, &data); err != nil { return logical.ErrorResponse(fmt.Sprintf( @@ -2202,6 +2211,60 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque logical.ErrInvalidRequest } + // Verify the entity alias + overwriteEntityID := "" + if data.EntityAlias != "" { + // Parameter is only allowed in combination with token role + if role == nil { + return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest + } + + // Get mount accessor which is required to lookup entity alias + mountValidationResp := ts.core.router.validateMountByAccessor("auth_token_") + if mountValidationResp == nil { + return logical.ErrorResponse("auth token mount accessor not found"), nil + } + + // Verify that the alias exist + aliasByFactors, err := ts.core.identityStore.MemDBAliasByFactors(mountValidationResp.MountAccessor, data.EntityAlias, false, false) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + + switch { + case aliasByFactors == nil: + // Entity alias does not exist. Create a new entity and entity alias + newAlias := &logical.Alias{ + Name: data.EntityAlias, + MountAccessor: mountValidationResp.MountAccessor, + MountType: mountValidationResp.MountType, + } + + newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, newAlias) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + + // Set new entity id + overwriteEntityID = newEntity.ID + default: + // Verify that the specified entity alias is included in the allowed entity alias list + foundEntityAlias := false + for _, entityAlias := range role.AllowedEntityAliases { + if strings.Compare(entityAlias, data.EntityAlias) == 0 { + foundEntityAlias = true + } + } + + if !foundEntityAlias { + return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest + } + + // Set new entity id + overwriteEntityID = aliasByFactors.CanonicalID + } + } + // Setup the token entry te := logical.TokenEntry{ Parent: req.ClientToken, @@ -2434,9 +2497,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque } // At this point, it is clear whether the token is going to be an orphan or - // not. If the token is not going to be an orphan, inherit the parent's + // not. If setEntityID is set, the entity identifier will be overwritten. + // Otherwise, if the token is not going to be an orphan, inherit the parent's // entity identifier into the child token. - if te.Parent != "" { + switch { + case overwriteEntityID != "": + // Overwrite the entity identifier + te.EntityID = overwriteEntityID + case te.Parent != "": te.EntityID = parent.EntityID // If the parent has bound CIDRs, copy those into the child. We don't @@ -3183,6 +3251,13 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic } } + allowedEntityAliasesRaw, ok := data.GetOk("allowed_entity_aliases") + if ok { + entry.AllowedEntityAliases = strutil.RemoveDuplicates(allowedEntityAliasesRaw.([]string), true) + } else if req.Operation == logical.CreateOperation { + entry.AllowedEntityAliases = strutil.RemoveDuplicates(data.Get("allowed_entity_aliases").([]string), true) + } + ns, err := namespace.FromContext(ctx) if err != nil { return nil, err diff --git a/vault/token_store_test.go b/vault/token_store_test.go index b6df807af278..ce0f99b511d5 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -2614,6 +2614,249 @@ func TestTokenStore_HandleRequest_Renew(t *testing.T) { } } +func TestTokenStore_HandleRequest_CreateToken_ExistingEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + testPolicyName := "testpolicy" + entityAliasName := "testentityalias" + testRoleName := "test" + + // Create manually an entity + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "entity", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": "testentity", + "policies": []string{testPolicyName}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + entityID := resp.Data["id"].(string) + + // Find mount accessor + resp, err = core.systemBackend.HandleRequest(namespace.RootContext(nil), &logical.Request{ + Path: "auth", + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + tokenMountAccessor := resp.Data["token/"].(map[string]interface{})["accessor"].(string) + + // Create manually an entity alias + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": entityAliasName, + "canonical_id": entityID, + "mount_accessor": tokenMountAccessor, + }, + }) + + // Create token role + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "orphan": true, + "period": "72h", + "path_suffix": "happenin", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliasName}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create", + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "role_name": testRoleName, + "entity_alias": entityAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } + if resp.Auth.EntityID != entityID { + t.Fatalf("expected '%s' got '%s'", entityID, resp.Auth.EntityID) + } + + policyFound := false + for _, policy := range resp.Auth.IdentityPolicies { + if policy == testPolicyName { + policyFound = true + } + } + if !policyFound { + t.Fatalf("Policy '%s' not derived by entity but should be. Auth %#v", testPolicyName, resp.Auth) + } +} + +func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + entityAliasName := "testentityalias" + testRoleName := "test" + + // Create token role + resp, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "path_suffix": "happenin", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2"}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + // Create token with non existing entity alias + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create", + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "role_name": testRoleName, + "entity_alias": entityAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } + + // Read the new entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + resp.Auth.EntityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + + // Get the attached alias information + aliases, ok := resp.Data["aliases"].([]identity.Alias) + if !ok { + t.Fatalf("failed to parse attached aliases. Resp: %#v", resp.Data) + } + if len(aliases) != 1 { + t.Fatalf("expected one attached alias but got %d", len(aliases)) + } + if aliases[0].Name != entityAliasName { + t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, aliases[0].Name) + } +} + +func TestTokenStore_HandleRequest_CreateToken_NotAllowedEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + testPolicyName := "testpolicy" + entityAliasName := "testentityalias" + testRoleName := "test" + + // Create manually an entity + resp, err := i.HandleRequest(ctx, &logical.Request{ + Path: "entity", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": "testentity", + "policies": []string{testPolicyName}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + entityID := resp.Data["id"].(string) + + // Find mount accessor + resp, err = core.systemBackend.HandleRequest(namespace.RootContext(nil), &logical.Request{ + Path: "auth", + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + tokenMountAccessor := resp.Data["token/"].(map[string]interface{})["accessor"].(string) + + // Create manually an entity alias + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity-alias", + Operation: logical.UpdateOperation, + Data: map[string]interface{}{ + "name": entityAliasName, + "canonical_id": entityID, + "mount_accessor": tokenMountAccessor, + }, + }) + + // Create token role + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "allowed_entity_aliases": []string{"test1", "test2", "testentityaliasn"}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + resp, _ = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create", + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasName, + }, + }) + if resp == nil || resp.Data == nil { + t.Fatal("expected a response") + } + if resp.Data["error"] != "invalid 'entity_alias' value" { + t.Fatalf("wrong error returned. Err: %s", resp.Data["error"]) + } +} + +func TestTokenStore_HandleRequest_CreateToken_NoRoleEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + ctx := namespace.RootContext(nil) + entityAliasName := "testentityalias" + + resp, _ := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create", + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasName, + }, + }) + if resp == nil || resp.Data == nil { + t.Fatal("expected a response") + } + if resp.Data["error"] != "'entity_alias' is only allowed in combination with token role" { + t.Fatalf("wrong error returned. Err: %s", resp.Data["error"]) + } +} + func TestTokenStore_HandleRequest_RenewSelf(t *testing.T) { exp := mockExpiration(t) ts := exp.tokenStore From 926d7e9e4bcfc6c380ffb258206dc72e19f866b0 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Mon, 8 Apr 2019 16:57:21 +0200 Subject: [PATCH 02/16] Fixed tests --- vault/token_store.go | 10 +++---- vault/token_store_test.go | 57 ++++++++++++++++++++------------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index f6f142384906..a6399631092e 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2114,7 +2114,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque NumUses int `mapstructure:"num_uses"` Period string Type string `mapstructure:"type"` - EntityAlias string + EntityAlias string `mapstructure:"entity_alias"` } if err := mapstructure.WeakDecode(req.Data, &data); err != nil { return logical.ErrorResponse(fmt.Sprintf( @@ -2220,13 +2220,13 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque } // Get mount accessor which is required to lookup entity alias - mountValidationResp := ts.core.router.validateMountByAccessor("auth_token_") + mountValidationResp := ts.core.router.MatchingMountByAccessor(req.MountAccessor) if mountValidationResp == nil { return logical.ErrorResponse("auth token mount accessor not found"), nil } // Verify that the alias exist - aliasByFactors, err := ts.core.identityStore.MemDBAliasByFactors(mountValidationResp.MountAccessor, data.EntityAlias, false, false) + aliasByFactors, err := ts.core.identityStore.MemDBAliasByFactors(mountValidationResp.Accessor, data.EntityAlias, false, false) if err != nil { return logical.ErrorResponse(err.Error()), nil } @@ -2236,8 +2236,8 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque // Entity alias does not exist. Create a new entity and entity alias newAlias := &logical.Alias{ Name: data.EntityAlias, - MountAccessor: mountValidationResp.MountAccessor, - MountType: mountValidationResp.MountType, + MountAccessor: mountValidationResp.Accessor, + MountType: mountValidationResp.Type, } newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, newAlias) diff --git a/vault/token_store_test.go b/vault/token_store_test.go index ce0f99b511d5..7f20d153e44e 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "fmt" + "github.com/mitchellh/mapstructure" "path" "reflect" "sort" @@ -2659,13 +2660,14 @@ func TestTokenStore_HandleRequest_CreateToken_ExistingEntityAlias(t *testing.T) // Create token role resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - Operation: logical.CreateOperation, + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, Data: map[string]interface{}{ - "orphan": true, - "period": "72h", - "path_suffix": "happenin", - "bound_cidrs": []string{"0.0.0.0/0"}, + "orphan": true, + "period": "72h", + "path_suffix": "happenin", + "bound_cidrs": []string{"0.0.0.0/0"}, "allowed_entity_aliases": []string{"test1", "test2", entityAliasName}, }, }) @@ -2674,11 +2676,10 @@ func TestTokenStore_HandleRequest_CreateToken_ExistingEntityAlias(t *testing.T) } resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create", + Path: "auth/token/create/" + testRoleName, Operation: logical.UpdateOperation, ClientToken: root, Data: map[string]interface{}{ - "role_name": testRoleName, "entity_alias": entityAliasName, }, }) @@ -2712,12 +2713,13 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. // Create token role resp, err := core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - Operation: logical.CreateOperation, + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, Data: map[string]interface{}{ - "period": "72h", - "path_suffix": "happenin", - "bound_cidrs": []string{"0.0.0.0/0"}, + "period": "72h", + "path_suffix": "happenin", + "bound_cidrs": []string{"0.0.0.0/0"}, "allowed_entity_aliases": []string{"test1", "test2"}, }, }) @@ -2727,11 +2729,10 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. // Create token with non existing entity alias resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create", + Path: "auth/token/create/" + testRoleName, Operation: logical.UpdateOperation, ClientToken: root, Data: map[string]interface{}{ - "role_name": testRoleName, "entity_alias": entityAliasName, }, }) @@ -2752,15 +2753,16 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. } // Get the attached alias information - aliases, ok := resp.Data["aliases"].([]identity.Alias) - if !ok { - t.Fatalf("failed to parse attached aliases. Resp: %#v", resp.Data) - } + aliases := resp.Data["aliases"].([]interface{}) if len(aliases) != 1 { - t.Fatalf("expected one attached alias but got %d", len(aliases)) + t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) } - if aliases[0].Name != entityAliasName { - t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, aliases[0].Name) + alias := &identity.Alias{} + mapstructure.Decode(aliases[0], alias) + + // Validate + if alias.Name != entityAliasName { + t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) } } @@ -2787,7 +2789,7 @@ func TestTokenStore_HandleRequest_CreateToken_NotAllowedEntityAlias(t *testing.T entityID := resp.Data["id"].(string) // Find mount accessor - resp, err = core.systemBackend.HandleRequest(namespace.RootContext(nil), &logical.Request{ + resp, err = core.systemBackend.HandleRequest(ctx, &logical.Request{ Path: "auth", Operation: logical.ReadOperation, }) @@ -2809,10 +2811,11 @@ func TestTokenStore_HandleRequest_CreateToken_NotAllowedEntityAlias(t *testing.T // Create token role resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - Operation: logical.CreateOperation, + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, Data: map[string]interface{}{ - "period": "72h", + "period": "72h", "allowed_entity_aliases": []string{"test1", "test2", "testentityaliasn"}, }, }) @@ -2821,7 +2824,7 @@ func TestTokenStore_HandleRequest_CreateToken_NotAllowedEntityAlias(t *testing.T } resp, _ = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create", + Path: "auth/token/create/" + testRoleName, Operation: logical.UpdateOperation, ClientToken: root, Data: map[string]interface{}{ From 62fb46532a5904383e91e92b58d5c2316497693a Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 25 Apr 2019 17:19:59 +0200 Subject: [PATCH 03/16] Refactored a few checks for the token entity overwrite. Fixed tests. --- vault/token_store.go | 47 ++++++++++++++++++++++++--------------- vault/token_store_test.go | 7 +++--- 2 files changed, 33 insertions(+), 21 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index a6399631092e..868d597949e8 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -19,8 +19,8 @@ import ( log "github.com/hashicorp/go-hclog" "github.com/hashicorp/go-sockaddr" - metrics "github.com/armon/go-metrics" - multierror "github.com/hashicorp/go-multierror" + "github.com/armon/go-metrics" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/framework" @@ -2231,37 +2231,48 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse(err.Error()), nil } + // Create alias for later processing + alias := &logical.Alias{ + Name: data.EntityAlias, + MountAccessor: mountValidationResp.Accessor, + MountType: mountValidationResp.Type, + } + switch { case aliasByFactors == nil: // Entity alias does not exist. Create a new entity and entity alias - newAlias := &logical.Alias{ - Name: data.EntityAlias, - MountAccessor: mountValidationResp.Accessor, - MountType: mountValidationResp.Type, - } - - newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, newAlias) + newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) if err != nil { return logical.ErrorResponse(err.Error()), nil } + if newEntity == nil { + return logical.ErrorResponse("failed to create new entity for given entity alias"), nil + } // Set new entity id overwriteEntityID = newEntity.ID default: - // Verify that the specified entity alias is included in the allowed entity alias list - foundEntityAlias := false - for _, entityAlias := range role.AllowedEntityAliases { - if strings.Compare(entityAlias, data.EntityAlias) == 0 { - foundEntityAlias = true - } + // Check if provided entity alias name is in the allowed entity aliases list + if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { + return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest } - if !foundEntityAlias { - return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest + // Lookup entity + entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + if entity == nil { + return logical.ErrorResponse("failed to lookup entity from given entity alias"), nil + } + + // Validate that the entity is not disabled + if entity.Disabled { + return logical.ErrorResponse("entity from given entity alias is disabled"), logical.ErrPermissionDenied } // Set new entity id - overwriteEntityID = aliasByFactors.CanonicalID + overwriteEntityID = entity.ID } } diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 7f20d153e44e..075d4df77d21 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -4,7 +4,6 @@ import ( "context" "encoding/json" "fmt" - "github.com/mitchellh/mapstructure" "path" "reflect" "sort" @@ -18,13 +17,15 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/errwrap" - hclog "github.com/hashicorp/go-hclog" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-uuid" + "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/locksutil" "github.com/hashicorp/vault/sdk/helper/parseutil" "github.com/hashicorp/vault/sdk/helper/tokenutil" "github.com/hashicorp/vault/sdk/logical" + "github.com/mitchellh/mapstructure" ) func TestTokenStore_CreateOrphanResponse(t *testing.T) { From 4cf698be05a00a2482a8999300994cab1759298d Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Mon, 13 May 2019 19:22:54 +0200 Subject: [PATCH 04/16] Moved entity alias check up so that the entity and entity alias is only created when it has been specified in allowed_entity_aliases list --- vault/token_store.go | 26 +++++++++++++------------- vault/token_store_test.go | 9 ++++----- 2 files changed, 17 insertions(+), 18 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index 868d597949e8..d09f9ec02931 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -17,10 +17,10 @@ import ( "github.com/golang/protobuf/proto" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-sockaddr" + sockaddr "github.com/hashicorp/go-sockaddr" - "github.com/armon/go-metrics" - "github.com/hashicorp/go-multierror" + metrics "github.com/armon/go-metrics" + multierror "github.com/hashicorp/go-multierror" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/framework" @@ -1827,11 +1827,11 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data } var countAccessorList, - countCubbyholeKeys, - deletedCountAccessorEmptyToken, - deletedCountAccessorInvalidToken, - deletedCountInvalidTokenInAccessor, - deletedCountInvalidCubbyholeKey int64 + countCubbyholeKeys, + deletedCountAccessorEmptyToken, + deletedCountAccessorInvalidToken, + deletedCountInvalidTokenInAccessor, + deletedCountInvalidCubbyholeKey int64 validCubbyholeKeys := make(map[string]bool) @@ -2219,6 +2219,11 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest } + // Check if provided entity alias name is in the allowed entity aliases list + if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { + return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest + } + // Get mount accessor which is required to lookup entity alias mountValidationResp := ts.core.router.MatchingMountByAccessor(req.MountAccessor) if mountValidationResp == nil { @@ -2252,11 +2257,6 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque // Set new entity id overwriteEntityID = newEntity.ID default: - // Check if provided entity alias name is in the allowed entity aliases list - if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { - return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest - } - // Lookup entity entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) if err != nil { diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 075d4df77d21..58349120bf30 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -13,12 +13,11 @@ import ( "testing" "time" - "github.com/hashicorp/go-sockaddr" - "github.com/go-test/deep" "github.com/hashicorp/errwrap" - "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-uuid" + hclog "github.com/hashicorp/go-hclog" + sockaddr "github.com/hashicorp/go-sockaddr" + uuid "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/locksutil" @@ -2721,7 +2720,7 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. "period": "72h", "path_suffix": "happenin", "bound_cidrs": []string{"0.0.0.0/0"}, - "allowed_entity_aliases": []string{"test1", "test2"}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliasName}, }, }) if err != nil || (resp != nil && resp.IsError()) { From cdd47f77fcd4533374cb2c16ae8559c7076b7195 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Tue, 14 May 2019 08:35:21 +0200 Subject: [PATCH 05/16] go mod vendor --- vendor/github.com/hashicorp/vault/api/auth_token.go | 1 + 1 file changed, 1 insertion(+) diff --git a/vendor/github.com/hashicorp/vault/api/auth_token.go b/vendor/github.com/hashicorp/vault/api/auth_token.go index ed594eee8528..6807c89c3878 100644 --- a/vendor/github.com/hashicorp/vault/api/auth_token.go +++ b/vendor/github.com/hashicorp/vault/api/auth_token.go @@ -272,4 +272,5 @@ type TokenCreateRequest struct { NumUses int `json:"num_uses"` Renewable *bool `json:"renewable,omitempty"` Type string `json:"type"` + EntityAlias string `json:"entity_alias"` } From 672041b3dfb7539adb51aef5590812698a249d1a Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Tue, 28 May 2019 13:45:39 -0500 Subject: [PATCH 06/16] Added glob pattern --- vault/token_store.go | 19 ++++++++++- vault/token_store_test.go | 69 ++++++++++++++++++++++++++++++++++++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index d09f9ec02931..cd7b69f0d398 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2219,8 +2219,25 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest } + // Check if the allowed entity aliases list contains a matching glob pattern + matchByGlob := false + for _, allowedAlias := range role.AllowedEntityAliases { + if !strings.Contains(allowedAlias, "*") { + continue + } + + // Remove asterisk + allowedAlias = strings.ReplaceAll(allowedAlias, "*", "") + + // Check if it matches + if strings.HasPrefix(data.EntityAlias, allowedAlias) { + matchByGlob = true + break + } + } + // Check if provided entity alias name is in the allowed entity aliases list - if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { + if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) && !matchByGlob { return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest } diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 58349120bf30..9be1ea7e2226 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -2758,7 +2758,74 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) } alias := &identity.Alias{} - mapstructure.Decode(aliases[0], alias) + if err := mapstructure.Decode(aliases[0], alias); err != nil { + t.Fatal(err) + } + + // Validate + if alias.Name != entityAliasName { + t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + } +} + +func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + entityAliaGlobPattern := "testentity*" + entityAliasName := "testentity12345" + testRoleName := "test" + + // Create token role + resp, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "path_suffix": "happening", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliaGlobPattern}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + // Create token with non existing entity alias + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } + + // Read the new entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + resp.Auth.EntityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + + // Get the attached alias information + aliases := resp.Data["aliases"].([]interface{}) + if len(aliases) != 1 { + t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) + } + alias := &identity.Alias{} + if err := mapstructure.Decode(aliases[0], alias); err != nil { + t.Fatal(err) + } // Validate if alias.Name != entityAliasName { From 88d9fe22f5c48d0c51326618b62804cb91c60072 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 6 Jun 2019 16:07:25 +0200 Subject: [PATCH 07/16] Optimized allowed entity alias check --- vault/token_store.go | 84 ++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 49 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index cd7b69f0d398..f6289b2f0f40 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -17,10 +17,10 @@ import ( "github.com/golang/protobuf/proto" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" - sockaddr "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/go-sockaddr" - metrics "github.com/armon/go-metrics" - multierror "github.com/hashicorp/go-multierror" + "github.com/armon/go-metrics" + "github.com/hashicorp/go-multierror" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/framework" @@ -1827,11 +1827,11 @@ func (ts *TokenStore) handleTidy(ctx context.Context, req *logical.Request, data } var countAccessorList, - countCubbyholeKeys, - deletedCountAccessorEmptyToken, - deletedCountAccessorInvalidToken, - deletedCountInvalidTokenInAccessor, - deletedCountInvalidCubbyholeKey int64 + countCubbyholeKeys, + deletedCountAccessorEmptyToken, + deletedCountAccessorInvalidToken, + deletedCountInvalidTokenInAccessor, + deletedCountInvalidCubbyholeKey int64 validCubbyholeKeys := make(map[string]bool) @@ -2219,9 +2219,16 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest } - // Check if the allowed entity aliases list contains a matching glob pattern - matchByGlob := false + // Check if provided entity alias name is in the allowed entity aliases list + match := false for _, allowedAlias := range role.AllowedEntityAliases { + // Check if there is a match + if strings.EqualFold(allowedAlias, data.EntityAlias) { + match = true + break + } + + // Only continue when this allowed alias is a glob pattern if !strings.Contains(allowedAlias, "*") { continue } @@ -2230,14 +2237,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque allowedAlias = strings.ReplaceAll(allowedAlias, "*", "") // Check if it matches - if strings.HasPrefix(data.EntityAlias, allowedAlias) { - matchByGlob = true + if strings.HasPrefix(strings.ToLower(data.EntityAlias), strings.ToLower(allowedAlias)) { + match = true break } } - // Check if provided entity alias name is in the allowed entity aliases list - if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) && !matchByGlob { + // Throw an error if it does not match + if !match { return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest } @@ -2247,12 +2254,6 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("auth token mount accessor not found"), nil } - // Verify that the alias exist - aliasByFactors, err := ts.core.identityStore.MemDBAliasByFactors(mountValidationResp.Accessor, data.EntityAlias, false, false) - if err != nil { - return logical.ErrorResponse(err.Error()), nil - } - // Create alias for later processing alias := &logical.Alias{ Name: data.EntityAlias, @@ -2260,37 +2261,22 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque MountType: mountValidationResp.Type, } - switch { - case aliasByFactors == nil: - // Entity alias does not exist. Create a new entity and entity alias - newEntity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) - if err != nil { - return logical.ErrorResponse(err.Error()), nil - } - if newEntity == nil { - return logical.ErrorResponse("failed to create new entity for given entity alias"), nil - } - - // Set new entity id - overwriteEntityID = newEntity.ID - default: - // Lookup entity - entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) - if err != nil { - return logical.ErrorResponse(err.Error()), nil - } - if entity == nil { - return logical.ErrorResponse("failed to lookup entity from given entity alias"), nil - } - - // Validate that the entity is not disabled - if entity.Disabled { - return logical.ErrorResponse("entity from given entity alias is disabled"), logical.ErrPermissionDenied - } + // Create or fetch entity from entity alias + entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) + if err != nil { + return logical.ErrorResponse(err.Error()), nil + } + if entity == nil { + return logical.ErrorResponse("failed to create or fetch entity from given entity alias"), nil + } - // Set new entity id - overwriteEntityID = entity.ID + // Validate that the entity is not disabled + if entity.Disabled { + return logical.ErrorResponse("entity from given entity alias is disabled"), logical.ErrPermissionDenied } + + // Set new entity id + overwriteEntityID = entity.ID } // Setup the token entry From a764e15c4864ec72b6192dff301a9e5a9b7b34d1 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 6 Jun 2019 16:28:35 +0200 Subject: [PATCH 08/16] Added test for asterisk only --- vault/token_store_test.go | 69 +++++++++++++++++++++++++++++++++++++-- 1 file changed, 67 insertions(+), 2 deletions(-) diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 9be1ea7e2226..f57cc84d1a2a 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -2772,7 +2772,7 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing. core, _, root := TestCoreUnsealed(t) i := core.identityStore ctx := namespace.RootContext(nil) - entityAliaGlobPattern := "testentity*" + entityAliasGlobPattern := "testentity*" entityAliasName := "testentity12345" testRoleName := "test" @@ -2785,7 +2785,72 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing. "period": "72h", "path_suffix": "happening", "bound_cidrs": []string{"0.0.0.0/0"}, - "allowed_entity_aliases": []string{"test1", "test2", entityAliaGlobPattern}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliasGlobPattern}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } + + // Create token with non existing entity alias + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": entityAliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } + + // Read the new entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + resp.Auth.EntityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + + // Get the attached alias information + aliases := resp.Data["aliases"].([]interface{}) + if len(aliases) != 1 { + t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) + } + alias := &identity.Alias{} + if err := mapstructure.Decode(aliases[0], alias); err != nil { + t.Fatal(err) + } + + // Validate + if alias.Name != entityAliasName { + t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + } +} + +func TestTokenStore_HandleRequest_CreateToken_GlobPatternWildcardEntityAlias(t *testing.T) { + core, _, root := TestCoreUnsealed(t) + i := core.identityStore + ctx := namespace.RootContext(nil) + entityAliasGlobPattern := "*" + entityAliasName := "testentity12345" + testRoleName := "test" + + // Create token role + resp, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "path_suffix": "happening", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", entityAliasGlobPattern}, }, }) if err != nil || (resp != nil && resp.IsError()) { From 5d90e0500fb6bf452debcec18919a4c3aa430f94 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Fri, 7 Jun 2019 16:14:11 +0200 Subject: [PATCH 09/16] Changed to glob pattern anywhere --- vault/token_store.go | 25 ++++-- vault/token_store_test.go | 167 +++++++++++++++++++------------------- 2 files changed, 102 insertions(+), 90 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index f6289b2f0f40..ab70e013ee71 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2233,14 +2233,27 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque continue } - // Remove asterisk - allowedAlias = strings.ReplaceAll(allowedAlias, "*", "") + // Split by asterisk to get prefix and suffix + split := strings.Split(allowedAlias, "*") - // Check if it matches - if strings.HasPrefix(strings.ToLower(data.EntityAlias), strings.ToLower(allowedAlias)) { - match = true - break + // Multiple asterisks are not allowed. Skip this invalid glob pattern. + if len(split) != 2 { + continue + } + + // Check if prefix matches + if !strings.HasPrefix(data.EntityAlias, split[0]) { + continue } + + // Check if suffix matches + if !strings.HasSuffix(data.EntityAlias, split[1]) { + continue + } + + // Found a match + match = true + break } // Throw an error if it does not match diff --git a/vault/token_store_test.go b/vault/token_store_test.go index f57cc84d1a2a..cf19c8d6f014 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -15,9 +15,9 @@ import ( "github.com/go-test/deep" "github.com/hashicorp/errwrap" - hclog "github.com/hashicorp/go-hclog" - sockaddr "github.com/hashicorp/go-sockaddr" - uuid "github.com/hashicorp/go-uuid" + "github.com/hashicorp/go-hclog" + "github.com/hashicorp/go-sockaddr" + "github.com/hashicorp/go-uuid" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/helper/locksutil" @@ -2768,11 +2768,10 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. } } -func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing.T) { +func TestTokenStore_HandleRequest_CreateToken_GlobPattern_MultipleAsterisk_EntityAlias(t *testing.T) { core, _, root := TestCoreUnsealed(t) - i := core.identityStore ctx := namespace.RootContext(nil) - entityAliasGlobPattern := "testentity*" + entityAliasGlobPattern := "*testentity*" entityAliasName := "testentity12345" testRoleName := "test" @@ -2801,35 +2800,11 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternEntityAlias(t *testing. "entity_alias": entityAliasName, }, }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - if resp == nil { - t.Fatal("expected a response") - } - - // Read the new entity - resp, err = i.HandleRequest(ctx, &logical.Request{ - Path: "entity/id/" + resp.Auth.EntityID, - Operation: logical.ReadOperation, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - - // Get the attached alias information - aliases := resp.Data["aliases"].([]interface{}) - if len(aliases) != 1 { - t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) - } - alias := &identity.Alias{} - if err := mapstructure.Decode(aliases[0], alias); err != nil { - t.Fatal(err) + if err == nil { + t.Fatal("err is nil but should be 'invalid request'") } - - // Validate - if alias.Name != entityAliasName { - t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + if !strings.Contains(err.Error(), "invalid request") { + t.Fatalf("err should contain 'invalid request' but is '%s'", err.Error()) } } @@ -2837,64 +2812,88 @@ func TestTokenStore_HandleRequest_CreateToken_GlobPatternWildcardEntityAlias(t * core, _, root := TestCoreUnsealed(t) i := core.identityStore ctx := namespace.RootContext(nil) - entityAliasGlobPattern := "*" - entityAliasName := "testentity12345" testRoleName := "test" - // Create token role - resp, err := core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - ClientToken: root, - Operation: logical.CreateOperation, - Data: map[string]interface{}{ - "period": "72h", - "path_suffix": "happening", - "bound_cidrs": []string{"0.0.0.0/0"}, - "allowed_entity_aliases": []string{"test1", "test2", entityAliasGlobPattern}, + tests := []struct { + name string + globPattern string + aliasName string + }{ + { + name: "prefix-asterisk", + globPattern: "*-web", + aliasName: "department-web", }, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err: %v\nresp: %#v", err, resp) - } - - // Create token with non existing entity alias - resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create/" + testRoleName, - Operation: logical.UpdateOperation, - ClientToken: root, - Data: map[string]interface{}{ - "entity_alias": entityAliasName, + { + name: "suffix-asterisk", + globPattern: "web-*", + aliasName: "web-department", + }, + { + name: "middle-asterisk", + globPattern: "web-*-web", + aliasName: "web-department-web", }, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } - if resp == nil { - t.Fatal("expected a response") } - // Read the new entity - resp, err = i.HandleRequest(ctx, &logical.Request{ - Path: "entity/id/" + resp.Auth.EntityID, - Operation: logical.ReadOperation, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) - } + for _, test := range tests { + t.Run(test.name, func(t *testing.T) { + // Create token role + resp, err := core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/roles/" + testRoleName, + ClientToken: root, + Operation: logical.CreateOperation, + Data: map[string]interface{}{ + "period": "72h", + "path_suffix": "happening", + "bound_cidrs": []string{"0.0.0.0/0"}, + "allowed_entity_aliases": []string{"test1", "test2", test.globPattern}, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("err: %v\nresp: %#v", err, resp) + } - // Get the attached alias information - aliases := resp.Data["aliases"].([]interface{}) - if len(aliases) != 1 { - t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) - } - alias := &identity.Alias{} - if err := mapstructure.Decode(aliases[0], alias); err != nil { - t.Fatal(err) - } + // Create token with non existing entity alias + resp, err = core.HandleRequest(ctx, &logical.Request{ + Path: "auth/token/create/" + testRoleName, + Operation: logical.UpdateOperation, + ClientToken: root, + Data: map[string]interface{}{ + "entity_alias": test.aliasName, + }, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + if resp == nil { + t.Fatal("expected a response") + } - // Validate - if alias.Name != entityAliasName { - t.Fatalf("alias name should be '%s' but is '%s'", entityAliasName, alias.Name) + // Read the new entity + resp, err = i.HandleRequest(ctx, &logical.Request{ + Path: "entity/id/" + resp.Auth.EntityID, + Operation: logical.ReadOperation, + }) + if err != nil || (resp != nil && resp.IsError()) { + t.Fatalf("bad: resp: %#v\nerr: %v", resp, err) + } + + // Get the attached alias information + aliases := resp.Data["aliases"].([]interface{}) + if len(aliases) != 1 { + t.Fatalf("expected only one alias but got %d; Aliases: %#v", len(aliases), aliases) + } + alias := &identity.Alias{} + if err := mapstructure.Decode(aliases[0], alias); err != nil { + t.Fatal(err) + } + + // Validate + if alias.Name != test.aliasName { + t.Fatalf("alias name should be '%s' but is '%s'", test.aliasName, alias.Name) + } + }) } } From 9fe9ad0eb975268ba3ea4178aabee4f215cb9855 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Mon, 24 Jun 2019 11:27:55 +0200 Subject: [PATCH 10/16] Changed response code in case of failure. Changed globbing pattern check. Added docs. --- command/token_create.go | 2 +- vault/token_store.go | 44 ++++--------------- vault/token_store_test.go | 40 ----------------- .../hashicorp/vault/api/auth_token.go | 1 - website/source/api/auth/token/index.html.md | 7 +++ 5 files changed, 17 insertions(+), 77 deletions(-) diff --git a/command/token_create.go b/command/token_create.go index e564a3375a8f..3192cd9f282a 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -183,7 +183,7 @@ func (c *TokenCreateCommand) Flags() *FlagSets { Default: "", Usage: "Name of the entity alias to associate with during token creation. " + "Only works in combination with -role argument and used entity alias " + - "must be listed in allowed entity aliases. If this has been specified, " + + "must be listed in allowed_entity_aliases. If this has been specified, " + "the entity will not be inherited from the parent.", }) diff --git a/vault/token_store.go b/vault/token_store.go index ab70e013ee71..f519e2471f8e 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -400,7 +400,7 @@ func (ts *TokenStore) paths() []*framework.Path { "allowed_entity_aliases": &framework.FieldSchema{ Type: framework.TypeStringSlice, - Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation.", + Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation. This field supports globbing.", }, }, @@ -2219,41 +2219,15 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque return logical.ErrorResponse("'entity_alias' is only allowed in combination with token role"), logical.ErrInvalidRequest } - // Check if provided entity alias name is in the allowed entity aliases list + // Check if there is a concrete match match := false - for _, allowedAlias := range role.AllowedEntityAliases { - // Check if there is a match - if strings.EqualFold(allowedAlias, data.EntityAlias) { - match = true - break - } - - // Only continue when this allowed alias is a glob pattern - if !strings.Contains(allowedAlias, "*") { - continue - } - - // Split by asterisk to get prefix and suffix - split := strings.Split(allowedAlias, "*") - - // Multiple asterisks are not allowed. Skip this invalid glob pattern. - if len(split) != 2 { - continue - } - - // Check if prefix matches - if !strings.HasPrefix(data.EntityAlias, split[0]) { - continue - } - - // Check if suffix matches - if !strings.HasSuffix(data.EntityAlias, split[1]) { - continue - } + if strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { + match = true + } - // Found a match + // Check if there is a matching globbing pattern + if !match && strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) { match = true - break } // Throw an error if it does not match @@ -2277,10 +2251,10 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque // Create or fetch entity from entity alias entity, err := ts.core.identityStore.CreateOrFetchEntity(ctx, alias) if err != nil { - return logical.ErrorResponse(err.Error()), nil + return nil, err } if entity == nil { - return logical.ErrorResponse("failed to create or fetch entity from given entity alias"), nil + return nil, errors.New("failed to create or fetch entity from given entity alias") } // Validate that the entity is not disabled diff --git a/vault/token_store_test.go b/vault/token_store_test.go index cf19c8d6f014..4386177fec36 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -2768,46 +2768,6 @@ func TestTokenStore_HandleRequest_CreateToken_NonExistingEntityAlias(t *testing. } } -func TestTokenStore_HandleRequest_CreateToken_GlobPattern_MultipleAsterisk_EntityAlias(t *testing.T) { - core, _, root := TestCoreUnsealed(t) - ctx := namespace.RootContext(nil) - entityAliasGlobPattern := "*testentity*" - entityAliasName := "testentity12345" - testRoleName := "test" - - // Create token role - resp, err := core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/roles/" + testRoleName, - ClientToken: root, - Operation: logical.CreateOperation, - Data: map[string]interface{}{ - "period": "72h", - "path_suffix": "happening", - "bound_cidrs": []string{"0.0.0.0/0"}, - "allowed_entity_aliases": []string{"test1", "test2", entityAliasGlobPattern}, - }, - }) - if err != nil || (resp != nil && resp.IsError()) { - t.Fatalf("err: %v\nresp: %#v", err, resp) - } - - // Create token with non existing entity alias - resp, err = core.HandleRequest(ctx, &logical.Request{ - Path: "auth/token/create/" + testRoleName, - Operation: logical.UpdateOperation, - ClientToken: root, - Data: map[string]interface{}{ - "entity_alias": entityAliasName, - }, - }) - if err == nil { - t.Fatal("err is nil but should be 'invalid request'") - } - if !strings.Contains(err.Error(), "invalid request") { - t.Fatalf("err should contain 'invalid request' but is '%s'", err.Error()) - } -} - func TestTokenStore_HandleRequest_CreateToken_GlobPatternWildcardEntityAlias(t *testing.T) { core, _, root := TestCoreUnsealed(t) i := core.identityStore diff --git a/vendor/github.com/hashicorp/vault/api/auth_token.go b/vendor/github.com/hashicorp/vault/api/auth_token.go index 6807c89c3878..ed594eee8528 100644 --- a/vendor/github.com/hashicorp/vault/api/auth_token.go +++ b/vendor/github.com/hashicorp/vault/api/auth_token.go @@ -272,5 +272,4 @@ type TokenCreateRequest struct { NumUses int `json:"num_uses"` Renewable *bool `json:"renewable,omitempty"` Type string `json:"type"` - EntityAlias string `json:"entity_alias"` } diff --git a/website/source/api/auth/token/index.html.md b/website/source/api/auth/token/index.html.md index 05d18328a259..00b58500f4e0 100644 --- a/website/source/api/auth/token/index.html.md +++ b/website/source/api/auth/token/index.html.md @@ -102,6 +102,10 @@ during this call. - `period` `(string: "")` - If specified, the token will be periodic; it will have no maximum TTL (unless an "explicit-max-ttl" is also set) but every renewal will use the given period. Requires a root/sudo token to use. +- `entity_alias` `string: "")` - Name of the entity alias to associate with + during token creation. Only works in combination with `role_name` argument + and used entity alias must be listed in `allowed_entity_aliases`. If this has + been specified, the entity will not be inherited from the parent. ### Sample Payload @@ -682,6 +686,9 @@ tokens created against a role to be revoked using the be returned unless the client requests a `batch` type token at token creation time. If `default-batch`, `batch` tokens will be returned unless the client requests a `service` type token at token creation time. +- `allowed_entity_aliases` `(string: "", or list: [])` - String or JSON list + of allowed entity aliases. If set, specifies the entity aliases which are + allowed to be used during token generation. This field supports globbing. ### Sample Payload From 6be27885758e9d4964453faf7e006f5469126f76 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Tue, 25 Jun 2019 09:30:49 +0200 Subject: [PATCH 11/16] Added missing token role get parameter. Added more samples --- vault/token_store.go | 1 + website/source/api/auth/token/index.html.md | 13 +++++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index f519e2471f8e..4dcffb802c4a 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -3047,6 +3047,7 @@ func (ts *TokenStore) tokenStoreRoleRead(ctx context.Context, req *logical.Reque "path_suffix": role.PathSuffix, "renewable": role.Renewable, "token_type": role.TokenType.String(), + "allowed_entity_aliases": role.AllowedEntityAliases, }, } diff --git a/website/source/api/auth/token/index.html.md b/website/source/api/auth/token/index.html.md index 00b58500f4e0..55b0acb62584 100644 --- a/website/source/api/auth/token/index.html.md +++ b/website/source/api/auth/token/index.html.md @@ -577,16 +577,20 @@ $ curl \ "lease_duration": 0, "renewable": false, "data": { - "allowed_policies": [ - "dev" + "allowed_entity_aliases": [ + "my-entity-alias" ], + "allowed_policies": [], "disallowed_policies": [], "explicit_max_ttl": 0, "name": "nomad", "orphan": false, "path_suffix": "", "period": 0, - "renewable": true + "renewable": true, + "token_explicit_max_ttl": 0, + "token_period": 0, + "token_type": "default-service" }, "warnings": null } @@ -699,7 +703,8 @@ tokens created against a role to be revoked using the "name": "nomad", "orphan": false, "bound_cidrs": ["127.0.0.1/32", "128.252.0.0/16"], - "renewable": true + "renewable": true, + "allowed_entity_aliases": ["web-entity-alias", "app-entity-*"] ``` ### Sample Request From 02253a1999fff52c5845538d1927af2b0b722f9f Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Tue, 25 Jun 2019 10:41:20 +0200 Subject: [PATCH 12/16] Fixed failing tests --- vault/token_store_test.go | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 4386177fec36..613688c1d739 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -3056,6 +3056,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "renewable": true, "token_type": "default-service", "token_num_uses": 123, + "allowed_entity_aliases": []string{}, } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3115,6 +3116,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "explicit_max_ttl": int64(288000), "renewable": false, "token_type": "default-service", + "allowed_entity_aliases": []string{}, } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3164,6 +3166,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "token_period": int64(0), "renewable": false, "token_type": "default-service", + "allowed_entity_aliases": []string{}, } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3213,6 +3216,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "token_period": int64(0), "renewable": false, "token_type": "default-service", + "allowed_entity_aliases": []string{}, } if diff := deep.Equal(expected, resp.Data); diff != nil { @@ -4022,6 +4026,7 @@ func TestTokenStore_RoleTokenFields(t *testing.T) { "explicit_max_ttl": int64(3600), "renewable": false, "token_type": "batch", + "allowed_entity_aliases": []string(nil), } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" { @@ -4074,6 +4079,7 @@ func TestTokenStore_RoleTokenFields(t *testing.T) { "explicit_max_ttl": int64(7200), "renewable": false, "token_type": "default-service", + "allowed_entity_aliases": []string(nil), } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" { @@ -4125,6 +4131,7 @@ func TestTokenStore_RoleTokenFields(t *testing.T) { "explicit_max_ttl": int64(0), "renewable": false, "token_type": "default-service", + "allowed_entity_aliases": []string(nil), } if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" { @@ -4178,6 +4185,7 @@ func TestTokenStore_RoleTokenFields(t *testing.T) { "explicit_max_ttl": int64(0), "renewable": false, "token_type": "service", + "allowed_entity_aliases": []string(nil), } if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" { From 836a7ff26a9ab25a9275c9733c748a7af83b173a Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 27 Jun 2019 11:55:31 +0200 Subject: [PATCH 13/16] Corrected some cosmetical review points --- vault/token_store.go | 36 ++++++++++++------------------------ 1 file changed, 12 insertions(+), 24 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index 4dcffb802c4a..538bd69e3a6f 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -7,20 +7,18 @@ import ( "errors" "fmt" "net/http" - "sync" - "sync/atomic" - "regexp" "strings" + "sync" + "sync/atomic" "time" + "github.com/armon/go-metrics" "github.com/golang/protobuf/proto" "github.com/hashicorp/errwrap" log "github.com/hashicorp/go-hclog" - "github.com/hashicorp/go-sockaddr" - - "github.com/armon/go-metrics" "github.com/hashicorp/go-multierror" + "github.com/hashicorp/go-sockaddr" "github.com/hashicorp/vault/helper/identity" "github.com/hashicorp/vault/helper/namespace" "github.com/hashicorp/vault/sdk/framework" @@ -399,7 +397,7 @@ func (ts *TokenStore) paths() []*framework.Path { }, "allowed_entity_aliases": &framework.FieldSchema{ - Type: framework.TypeStringSlice, + Type: framework.TypeCommaStringSlice, Description: "String or JSON list of allowed entity aliases. If set, specifies the entity aliases which are allowed to be used during token generation. This field supports globbing.", }, }, @@ -2212,7 +2210,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque } // Verify the entity alias - overwriteEntityID := "" + var explicitEntityID string if data.EntityAlias != "" { // Parameter is only allowed in combination with token role if role == nil { @@ -2220,19 +2218,9 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque } // Check if there is a concrete match - match := false - if strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) { - match = true - } - - // Check if there is a matching globbing pattern - if !match && strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) { - match = true - } - - // Throw an error if it does not match - if !match { - return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest + if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) && + !strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) { + return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrPermissionDenied } // Get mount accessor which is required to lookup entity alias @@ -2263,7 +2251,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque } // Set new entity id - overwriteEntityID = entity.ID + explicitEntityID = entity.ID } // Setup the token entry @@ -2502,9 +2490,9 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque // Otherwise, if the token is not going to be an orphan, inherit the parent's // entity identifier into the child token. switch { - case overwriteEntityID != "": + case explicitEntityID != "": // Overwrite the entity identifier - te.EntityID = overwriteEntityID + te.EntityID = explicitEntityID case te.Parent != "": te.EntityID = parent.EntityID From 49e845578c53a3e2f1ea408dd1a2e0466b6c0ee7 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 27 Jun 2019 14:08:25 +0200 Subject: [PATCH 14/16] Changed response code for invalid provided entity alias --- vault/token_store.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vault/token_store.go b/vault/token_store.go index 538bd69e3a6f..3faaacf60330 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -2220,7 +2220,7 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque // Check if there is a concrete match if !strutil.StrListContains(role.AllowedEntityAliases, data.EntityAlias) && !strutil.StrListContainsGlob(role.AllowedEntityAliases, data.EntityAlias) { - return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrPermissionDenied + return logical.ErrorResponse("invalid 'entity_alias' value"), logical.ErrInvalidRequest } // Get mount accessor which is required to lookup entity alias From d6743d7953d1ff0cc67df8f6376d50e288215b07 Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Thu, 27 Jun 2019 18:42:43 +0200 Subject: [PATCH 15/16] Fixed minor things --- vault/token_store.go | 2 -- website/source/api/auth/token/index.html.md | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/vault/token_store.go b/vault/token_store.go index 3faaacf60330..0cd0500018af 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -3244,8 +3244,6 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic allowedEntityAliasesRaw, ok := data.GetOk("allowed_entity_aliases") if ok { entry.AllowedEntityAliases = strutil.RemoveDuplicates(allowedEntityAliasesRaw.([]string), true) - } else if req.Operation == logical.CreateOperation { - entry.AllowedEntityAliases = strutil.RemoveDuplicates(data.Get("allowed_entity_aliases").([]string), true) } ns, err := namespace.FromContext(ctx) diff --git a/website/source/api/auth/token/index.html.md b/website/source/api/auth/token/index.html.md index 55b0acb62584..309d4749b7d7 100644 --- a/website/source/api/auth/token/index.html.md +++ b/website/source/api/auth/token/index.html.md @@ -102,7 +102,7 @@ during this call. - `period` `(string: "")` - If specified, the token will be periodic; it will have no maximum TTL (unless an "explicit-max-ttl" is also set) but every renewal will use the given period. Requires a root/sudo token to use. -- `entity_alias` `string: "")` - Name of the entity alias to associate with +- `entity_alias` `(string: "")` - Name of the entity alias to associate with during token creation. Only works in combination with `role_name` argument and used entity alias must be listed in `allowed_entity_aliases`. If this has been specified, the entity will not be inherited from the parent. From 9e9ef84390b256327c06b735597853d38af28f0f Mon Sep 17 00:00:00 2001 From: Michel Vocks Date: Mon, 1 Jul 2019 11:17:46 +0200 Subject: [PATCH 16/16] Fixed failing test --- vault/token_store_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 613688c1d739..d03975d30b5d 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -3056,7 +3056,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "renewable": true, "token_type": "default-service", "token_num_uses": 123, - "allowed_entity_aliases": []string{}, + "allowed_entity_aliases": []string(nil), } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3116,7 +3116,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "explicit_max_ttl": int64(288000), "renewable": false, "token_type": "default-service", - "allowed_entity_aliases": []string{}, + "allowed_entity_aliases": []string(nil), } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3166,7 +3166,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "token_period": int64(0), "renewable": false, "token_type": "default-service", - "allowed_entity_aliases": []string{}, + "allowed_entity_aliases": []string(nil), } if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" { @@ -3216,7 +3216,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "token_period": int64(0), "renewable": false, "token_type": "default-service", - "allowed_entity_aliases": []string{}, + "allowed_entity_aliases": []string(nil), } if diff := deep.Equal(expected, resp.Data); diff != nil {