Allow globbing dis/allowed_policies_glob in token roles (#7277)
* Add allowed_policies_glob and disallowed_policies_glob that are the same as allowed_policies and disallowed_policies but allow glob matching. * Update changelog, docs, tests, and comments for (dis)allowed_token_glob token role feature. * Improve docs and unit tests for auth/token role policy globbing.
This commit is contained in:
parent
8a0250d277
commit
a538936367
|
@ -0,0 +1,3 @@
|
||||||
|
```release-note:feature
|
||||||
|
auth/token: Add `allowed_policies_glob` and `disallowed_policies_glob` fields to token roles to allow glob matching of policies
|
||||||
|
```
|
|
@ -392,6 +392,16 @@ func (ts *TokenStore) paths() []*framework.Path {
|
||||||
Description: tokenDisallowedPoliciesHelp,
|
Description: tokenDisallowedPoliciesHelp,
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"allowed_policies_glob": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: tokenAllowedPoliciesGlobHelp,
|
||||||
|
},
|
||||||
|
|
||||||
|
"disallowed_policies_glob": {
|
||||||
|
Type: framework.TypeCommaStringSlice,
|
||||||
|
Description: tokenDisallowedPoliciesGlobHelp,
|
||||||
|
},
|
||||||
|
|
||||||
"orphan": {
|
"orphan": {
|
||||||
Type: framework.TypeBool,
|
Type: framework.TypeBool,
|
||||||
Description: tokenOrphanHelp,
|
Description: tokenOrphanHelp,
|
||||||
|
@ -623,6 +633,12 @@ type tsRoleEntry struct {
|
||||||
// List of policies to be not allowed during token creation using this role
|
// List of policies to be not allowed during token creation using this role
|
||||||
DisallowedPolicies []string `json:"disallowed_policies" mapstructure:"disallowed_policies" structs:"disallowed_policies"`
|
DisallowedPolicies []string `json:"disallowed_policies" mapstructure:"disallowed_policies" structs:"disallowed_policies"`
|
||||||
|
|
||||||
|
// An extension to AllowedPolicies that instead uses glob matching on policy names
|
||||||
|
AllowedPoliciesGlob []string `json:"allowed_policies_glob" mapstructure:"allowed_policies_glob" structs:"allowed_policies_glob"`
|
||||||
|
|
||||||
|
// An extension to DisallowedPolicies that instead uses glob matching on policy names
|
||||||
|
DisallowedPoliciesGlob []string `json:"disallowed_policies_glob" mapstructure:"disallowed_policies_glob" structs:"disallowed_policies_glob"`
|
||||||
|
|
||||||
// If true, tokens created using this role will be orphans
|
// If true, tokens created using this role will be orphans
|
||||||
Orphan bool `json:"orphan" mapstructure:"orphan" structs:"orphan"`
|
Orphan bool `json:"orphan" mapstructure:"orphan" structs:"orphan"`
|
||||||
|
|
||||||
|
@ -2475,7 +2491,8 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
// and shouldn't be added is kept because we want to do subset comparisons
|
// and shouldn't be added is kept because we want to do subset comparisons
|
||||||
// based on adding default when it's correct to do so.
|
// based on adding default when it's correct to do so.
|
||||||
switch {
|
switch {
|
||||||
case role != nil && (len(role.AllowedPolicies) > 0 || len(role.DisallowedPolicies) > 0):
|
case role != nil && (len(role.AllowedPolicies) > 0 || len(role.DisallowedPolicies) > 0 ||
|
||||||
|
len(role.AllowedPoliciesGlob) > 0 || len(role.DisallowedPoliciesGlob) > 0):
|
||||||
// Holds the final set of policies as they get munged
|
// Holds the final set of policies as they get munged
|
||||||
var finalPolicies []string
|
var finalPolicies []string
|
||||||
|
|
||||||
|
@ -2487,7 +2504,9 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
// isn't in the disallowed list, add it. This is in line with the idea
|
// isn't in the disallowed list, add it. This is in line with the idea
|
||||||
// that roles, when allowed/disallowed ar set, allow a subset of
|
// that roles, when allowed/disallowed ar set, allow a subset of
|
||||||
// policies to be set disjoint from the parent token's policies.
|
// policies to be set disjoint from the parent token's policies.
|
||||||
if !data.NoDefaultPolicy && !role.TokenNoDefaultPolicy && !strutil.StrListContains(role.DisallowedPolicies, "default") {
|
if !data.NoDefaultPolicy && !role.TokenNoDefaultPolicy &&
|
||||||
|
!strutil.StrListContains(role.DisallowedPolicies, "default") &&
|
||||||
|
!strutil.StrListContainsGlob(role.DisallowedPoliciesGlob, "default") {
|
||||||
localAddDefault = true
|
localAddDefault = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2496,12 +2515,12 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
finalPolicies = policyutil.SanitizePolicies(data.Policies, localAddDefault)
|
finalPolicies = policyutil.SanitizePolicies(data.Policies, localAddDefault)
|
||||||
}
|
}
|
||||||
|
|
||||||
var sanitizedRolePolicies []string
|
var sanitizedRolePolicies, sanitizedRolePoliciesGlob []string
|
||||||
|
|
||||||
// First check allowed policies; if policies are specified they will be
|
// First check allowed policies; if policies are specified they will be
|
||||||
// checked, otherwise if an allowed set exists that will be the set
|
// checked, otherwise if an allowed set exists that will be the set
|
||||||
// that is used
|
// that is used
|
||||||
if len(role.AllowedPolicies) > 0 {
|
if len(role.AllowedPolicies) > 0 || len(role.AllowedPoliciesGlob) > 0 {
|
||||||
// Note that if "default" is already in allowed, and also in
|
// Note that if "default" is already in allowed, and also in
|
||||||
// disallowed, this will still result in an error later since this
|
// disallowed, this will still result in an error later since this
|
||||||
// doesn't strip out default
|
// doesn't strip out default
|
||||||
|
@ -2510,8 +2529,13 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
if len(finalPolicies) == 0 {
|
if len(finalPolicies) == 0 {
|
||||||
finalPolicies = sanitizedRolePolicies
|
finalPolicies = sanitizedRolePolicies
|
||||||
} else {
|
} else {
|
||||||
if !strutil.StrListSubset(sanitizedRolePolicies, finalPolicies) {
|
sanitizedRolePoliciesGlob = policyutil.SanitizePolicies(role.AllowedPoliciesGlob, false)
|
||||||
return logical.ErrorResponse(fmt.Sprintf("token policies (%q) must be subset of the role's allowed policies (%q)", finalPolicies, sanitizedRolePolicies)), logical.ErrInvalidRequest
|
|
||||||
|
for _, finalPolicy := range finalPolicies {
|
||||||
|
if !strutil.StrListContains(sanitizedRolePolicies, finalPolicy) &&
|
||||||
|
!strutil.StrListContainsGlob(sanitizedRolePoliciesGlob, finalPolicy) {
|
||||||
|
return logical.ErrorResponse(fmt.Sprintf("token policies (%q) must be subset of the role's allowed policies (%q) or glob policies (%q)", finalPolicies, sanitizedRolePolicies, sanitizedRolePoliciesGlob)), logical.ErrInvalidRequest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -2522,12 +2546,14 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(role.DisallowedPolicies) > 0 {
|
if len(role.DisallowedPolicies) > 0 || len(role.DisallowedPoliciesGlob) > 0 {
|
||||||
// We don't add the default here because we only want to disallow it if it's explicitly set
|
// We don't add the default here because we only want to disallow it if it's explicitly set
|
||||||
sanitizedRolePolicies = strutil.RemoveDuplicates(role.DisallowedPolicies, true)
|
sanitizedRolePolicies = strutil.RemoveDuplicates(role.DisallowedPolicies, true)
|
||||||
|
sanitizedRolePoliciesGlob = strutil.RemoveDuplicates(role.DisallowedPoliciesGlob, true)
|
||||||
|
|
||||||
for _, finalPolicy := range finalPolicies {
|
for _, finalPolicy := range finalPolicies {
|
||||||
if strutil.StrListContains(sanitizedRolePolicies, finalPolicy) {
|
if strutil.StrListContains(sanitizedRolePolicies, finalPolicy) ||
|
||||||
|
strutil.StrListContainsGlob(sanitizedRolePoliciesGlob, finalPolicy) {
|
||||||
return logical.ErrorResponse(fmt.Sprintf("token policy %q is disallowed by this role", finalPolicy)), logical.ErrInvalidRequest
|
return logical.ErrorResponse(fmt.Sprintf("token policy %q is disallowed by this role", finalPolicy)), logical.ErrInvalidRequest
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3183,18 +3209,20 @@ func (ts *TokenStore) tokenStoreRoleRead(ctx context.Context, req *logical.Reque
|
||||||
// TODO (1.4): Remove "period" and "explicit_max_ttl" if they're zero
|
// TODO (1.4): Remove "period" and "explicit_max_ttl" if they're zero
|
||||||
resp := &logical.Response{
|
resp := &logical.Response{
|
||||||
Data: map[string]interface{}{
|
Data: map[string]interface{}{
|
||||||
"period": int64(role.Period.Seconds()),
|
"period": int64(role.Period.Seconds()),
|
||||||
"token_period": int64(role.TokenPeriod.Seconds()),
|
"token_period": int64(role.TokenPeriod.Seconds()),
|
||||||
"explicit_max_ttl": int64(role.ExplicitMaxTTL.Seconds()),
|
"explicit_max_ttl": int64(role.ExplicitMaxTTL.Seconds()),
|
||||||
"token_explicit_max_ttl": int64(role.TokenExplicitMaxTTL.Seconds()),
|
"token_explicit_max_ttl": int64(role.TokenExplicitMaxTTL.Seconds()),
|
||||||
"disallowed_policies": role.DisallowedPolicies,
|
"disallowed_policies": role.DisallowedPolicies,
|
||||||
"allowed_policies": role.AllowedPolicies,
|
"allowed_policies": role.AllowedPolicies,
|
||||||
"name": role.Name,
|
"disallowed_policies_glob": role.DisallowedPoliciesGlob,
|
||||||
"orphan": role.Orphan,
|
"allowed_policies_glob": role.AllowedPoliciesGlob,
|
||||||
"path_suffix": role.PathSuffix,
|
"name": role.Name,
|
||||||
"renewable": role.Renewable,
|
"orphan": role.Orphan,
|
||||||
"token_type": role.TokenType.String(),
|
"path_suffix": role.PathSuffix,
|
||||||
"allowed_entity_aliases": role.AllowedEntityAliases,
|
"renewable": role.Renewable,
|
||||||
|
"token_type": role.TokenType.String(),
|
||||||
|
"allowed_entity_aliases": role.AllowedEntityAliases,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3292,6 +3320,20 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate(ctx context.Context, req *logic
|
||||||
} else if req.Operation == logical.CreateOperation {
|
} else if req.Operation == logical.CreateOperation {
|
||||||
entry.DisallowedPolicies = strutil.RemoveDuplicates(data.Get("disallowed_policies").([]string), true)
|
entry.DisallowedPolicies = strutil.RemoveDuplicates(data.Get("disallowed_policies").([]string), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
allowedPoliciesGlobRaw, ok := data.GetOk("allowed_policies_glob")
|
||||||
|
if ok {
|
||||||
|
entry.AllowedPoliciesGlob = policyutil.SanitizePolicies(allowedPoliciesGlobRaw.([]string), policyutil.DoNotAddDefaultPolicy)
|
||||||
|
} else if req.Operation == logical.CreateOperation {
|
||||||
|
entry.AllowedPoliciesGlob = policyutil.SanitizePolicies(data.Get("allowed_policies_glob").([]string), policyutil.DoNotAddDefaultPolicy)
|
||||||
|
}
|
||||||
|
|
||||||
|
disallowedPoliciesGlobRaw, ok := data.GetOk("disallowed_policies_glob")
|
||||||
|
if ok {
|
||||||
|
entry.DisallowedPoliciesGlob = strutil.RemoveDuplicates(disallowedPoliciesGlobRaw.([]string), true)
|
||||||
|
} else if req.Operation == logical.CreateOperation {
|
||||||
|
entry.DisallowedPoliciesGlob = strutil.RemoveDuplicates(data.Get("disallowed_policies_glob").([]string), true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// We handle token type a bit differently than tokenutil does so we need to
|
// We handle token type a bit differently than tokenutil does so we need to
|
||||||
|
@ -3779,6 +3821,13 @@ calling token's policies. The parameter is a comma-delimited string of
|
||||||
policy names.`
|
policy names.`
|
||||||
tokenDisallowedPoliciesHelp = `If set, successful token creation via this role will require that
|
tokenDisallowedPoliciesHelp = `If set, successful token creation via this role will require that
|
||||||
no policies in the given list are requested. The parameter is a comma-delimited string of policy names.`
|
no policies in the given list are requested. The parameter is a comma-delimited string of policy names.`
|
||||||
|
tokenAllowedPoliciesGlobHelp = `If set, tokens can be created with any subset of glob matched policies in this
|
||||||
|
list, rather than the normal semantics of tokens being a subset of the
|
||||||
|
calling token's policies. The parameter is a comma-delimited string of
|
||||||
|
policy name globs.`
|
||||||
|
tokenDisallowedPoliciesGlobHelp = `If set, successful token creation via this role will require that
|
||||||
|
no requested policies glob match any of policies in this list.
|
||||||
|
The parameter is a comma-delimited string of policy name globs.`
|
||||||
tokenOrphanHelp = `If true, tokens created via this role
|
tokenOrphanHelp = `If true, tokens created via this role
|
||||||
will be orphan tokens (have no parent)`
|
will be orphan tokens (have no parent)`
|
||||||
tokenPeriodHelp = `If set, tokens created via this role
|
tokenPeriodHelp = `If set, tokens created via this role
|
||||||
|
|
|
@ -3179,19 +3179,21 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": true,
|
"orphan": true,
|
||||||
"token_period": int64(259200),
|
"token_period": int64(259200),
|
||||||
"period": int64(259200),
|
"period": int64(259200),
|
||||||
"allowed_policies": []string{"test1", "test2"},
|
"allowed_policies": []string{"test1", "test2"},
|
||||||
"disallowed_policies": []string{},
|
"disallowed_policies": []string{},
|
||||||
"path_suffix": "happenin",
|
"allowed_policies_glob": []string{},
|
||||||
"explicit_max_ttl": int64(7200),
|
"disallowed_policies_glob": []string{},
|
||||||
"token_explicit_max_ttl": int64(7200),
|
"path_suffix": "happenin",
|
||||||
"renewable": true,
|
"explicit_max_ttl": int64(7200),
|
||||||
"token_type": "default-service",
|
"token_explicit_max_ttl": int64(7200),
|
||||||
"token_num_uses": 123,
|
"renewable": true,
|
||||||
"allowed_entity_aliases": []string(nil),
|
"token_type": "default-service",
|
||||||
|
"token_num_uses": 123,
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
||||||
|
@ -3240,18 +3242,20 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = map[string]interface{}{
|
expected = map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": true,
|
"orphan": true,
|
||||||
"period": int64(284400),
|
"period": int64(284400),
|
||||||
"token_period": int64(284400),
|
"token_period": int64(284400),
|
||||||
"allowed_policies": []string{"test3"},
|
"allowed_policies": []string{"test3"},
|
||||||
"disallowed_policies": []string{},
|
"disallowed_policies": []string{},
|
||||||
"path_suffix": "happenin",
|
"allowed_policies_glob": []string{},
|
||||||
"token_explicit_max_ttl": int64(288000),
|
"disallowed_policies_glob": []string{},
|
||||||
"explicit_max_ttl": int64(288000),
|
"path_suffix": "happenin",
|
||||||
"renewable": false,
|
"token_explicit_max_ttl": int64(288000),
|
||||||
"token_type": "default-service",
|
"explicit_max_ttl": int64(288000),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "default-service",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
||||||
|
@ -3290,18 +3294,20 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = map[string]interface{}{
|
expected = map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": true,
|
"orphan": true,
|
||||||
"explicit_max_ttl": int64(5),
|
"explicit_max_ttl": int64(5),
|
||||||
"token_explicit_max_ttl": int64(5),
|
"token_explicit_max_ttl": int64(5),
|
||||||
"allowed_policies": []string{"test3"},
|
"allowed_policies": []string{"test3"},
|
||||||
"disallowed_policies": []string{},
|
"disallowed_policies": []string{},
|
||||||
"path_suffix": "happenin",
|
"allowed_policies_glob": []string{},
|
||||||
"period": int64(0),
|
"disallowed_policies_glob": []string{},
|
||||||
"token_period": int64(0),
|
"path_suffix": "happenin",
|
||||||
"renewable": false,
|
"period": int64(0),
|
||||||
"token_type": "default-service",
|
"token_period": int64(0),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "default-service",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "0.0.0.0/0" {
|
||||||
|
@ -3340,18 +3346,20 @@ func TestTokenStore_RoleCRUD(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected = map[string]interface{}{
|
expected = map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": true,
|
"orphan": true,
|
||||||
"token_explicit_max_ttl": int64(5),
|
"token_explicit_max_ttl": int64(5),
|
||||||
"explicit_max_ttl": int64(5),
|
"explicit_max_ttl": int64(5),
|
||||||
"allowed_policies": []string{"test3"},
|
"allowed_policies": []string{"test3"},
|
||||||
"disallowed_policies": []string{},
|
"disallowed_policies": []string{},
|
||||||
"path_suffix": "",
|
"allowed_policies_glob": []string{},
|
||||||
"period": int64(0),
|
"disallowed_policies_glob": []string{},
|
||||||
"token_period": int64(0),
|
"path_suffix": "",
|
||||||
"renewable": false,
|
"period": int64(0),
|
||||||
"token_type": "default-service",
|
"token_period": int64(0),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "default-service",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if diff := deep.Equal(expected, resp.Data); diff != nil {
|
if diff := deep.Equal(expected, resp.Data); diff != nil {
|
||||||
|
@ -3495,6 +3503,17 @@ func TestTokenStore_RoleDisallowedPolicies(t *testing.T) {
|
||||||
t.Fatalf("err:%v resp:%v", err, resp)
|
t.Fatalf("err:%v resp:%v", err, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// policy containing a glob character in the non-glob disallowed_policies field
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/testglobdisabled")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"disallowed_policies": "test*",
|
||||||
|
}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
// Create a token that has all the policies defined above
|
// Create a token that has all the policies defined above
|
||||||
req = logical.TestRequest(t, logical.UpdateOperation, "create")
|
req = logical.TestRequest(t, logical.UpdateOperation, "create")
|
||||||
req.ClientToken = root
|
req.ClientToken = root
|
||||||
|
@ -3508,6 +3527,7 @@ func TestTokenStore_RoleDisallowedPolicies(t *testing.T) {
|
||||||
}
|
}
|
||||||
parentToken := resp.Auth.ClientToken
|
parentToken := resp.Auth.ClientToken
|
||||||
|
|
||||||
|
// Test that the parent token's policies are rejected by disallowed_policies
|
||||||
req = logical.TestRequest(t, logical.UpdateOperation, "create/test1")
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/test1")
|
||||||
req.ClientToken = parentToken
|
req.ClientToken = parentToken
|
||||||
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
@ -3536,6 +3556,21 @@ func TestTokenStore_RoleDisallowedPolicies(t *testing.T) {
|
||||||
req.ClientToken = parentToken
|
req.ClientToken = parentToken
|
||||||
testMakeTokenViaRequest(t, ts, req)
|
testMakeTokenViaRequest(t, ts, req)
|
||||||
|
|
||||||
|
// Check to be sure 'test*' without globbing matches 'test*'
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testglobdisabled")
|
||||||
|
req.Data["policies"] = []string{"test*"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatalf("expected an error response, got %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to be sure 'test*' without globbing doesn't match 'test1' or 'test'
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testglobdisabled")
|
||||||
|
req.Data["policies"] = []string{"test1", "test"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
testMakeTokenViaRequest(t, ts, req)
|
||||||
|
|
||||||
// Create a role to have 'default' policy disallowed
|
// Create a role to have 'default' policy disallowed
|
||||||
req = logical.TestRequest(t, logical.UpdateOperation, "roles/default")
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/default")
|
||||||
req.ClientToken = root
|
req.ClientToken = root
|
||||||
|
@ -3588,6 +3623,40 @@ func TestTokenStore_RoleAllowedPolicies(t *testing.T) {
|
||||||
t.Fatalf("bad: %#v", resp)
|
t.Fatalf("bad: %#v", resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// test not glob matching when using allowed_policies instead of allowed_policies_glob
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/testnoglob")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"allowed_policies": "test*",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
if resp != nil {
|
||||||
|
t.Fatalf("expected a nil response")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Path = "create/testnoglob"
|
||||||
|
req.Data["policies"] = []string{"test"}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data["policies"] = []string{"testfoo"}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data["policies"] = []string{"test*"}
|
||||||
|
resp = testMakeTokenViaRequest(t, ts, req)
|
||||||
|
if resp.Auth.ClientToken == "" {
|
||||||
|
t.Fatalf("bad: %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
// When allowed_policies is blank, should fall back to a subset of the parent policies
|
// When allowed_policies is blank, should fall back to a subset of the parent policies
|
||||||
req = logical.TestRequest(t, logical.UpdateOperation, "roles/test")
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/test")
|
||||||
req.ClientToken = root
|
req.ClientToken = root
|
||||||
|
@ -3643,6 +3712,201 @@ func TestTokenStore_RoleAllowedPolicies(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTokenStore_RoleDisallowedPoliciesGlob(t *testing.T) {
|
||||||
|
var req *logical.Request
|
||||||
|
var resp *logical.Response
|
||||||
|
var err error
|
||||||
|
|
||||||
|
core, _, root := TestCoreUnsealed(t)
|
||||||
|
ts := core.tokenStore
|
||||||
|
ps := core.policyStore
|
||||||
|
|
||||||
|
// Create 4 different policies
|
||||||
|
policy, _ := ParseACLPolicy(namespace.RootNamespace, tokenCreationPolicy)
|
||||||
|
policy.Name = "test1"
|
||||||
|
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, _ = ParseACLPolicy(namespace.RootNamespace, tokenCreationPolicy)
|
||||||
|
policy.Name = "test2"
|
||||||
|
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, _ = ParseACLPolicy(namespace.RootNamespace, tokenCreationPolicy)
|
||||||
|
policy.Name = "test3"
|
||||||
|
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
policy, _ = ParseACLPolicy(namespace.RootNamespace, tokenCreationPolicy)
|
||||||
|
policy.Name = "test3b"
|
||||||
|
if err := ps.SetPolicy(namespace.RootContext(nil), policy); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create roles with different disallowed_policies configuration
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/test1")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"disallowed_policies_glob": "test1",
|
||||||
|
}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/testnot23")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"disallowed_policies_glob": "test2,test3*",
|
||||||
|
}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a token that has all the policies defined above
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data["policies"] = []string{"test1", "test2", "test3", "test3b"}
|
||||||
|
resp = testMakeTokenViaRequest(t, ts, req)
|
||||||
|
if resp == nil || resp.Auth == nil {
|
||||||
|
t.Fatal("got nil response")
|
||||||
|
}
|
||||||
|
if resp.Auth.ClientToken == "" {
|
||||||
|
t.Fatalf("bad: ClientToken; resp:%#v", resp)
|
||||||
|
}
|
||||||
|
parentToken := resp.Auth.ClientToken
|
||||||
|
|
||||||
|
// Test that the parent token's policies are rejected by disallowed_policies
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/test1")
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatalf("expected an error response, got %#v", resp)
|
||||||
|
}
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testnot23")
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatalf("expected an error response, got %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Disallowed should act as a blacklist so make sure we can still make
|
||||||
|
// something with other policies in the request
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/test1")
|
||||||
|
req.Data["policies"] = []string{"foo", "bar"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
testMakeTokenViaRequest(t, ts, req)
|
||||||
|
|
||||||
|
// Check to be sure 'test3*' matches 'test3'
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testnot23")
|
||||||
|
req.Data["policies"] = []string{"test3"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatalf("expected an error response, got %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check to be sure 'test3*' matches 'test3b'
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testnot23")
|
||||||
|
req.Data["policies"] = []string{"test3b"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatalf("expected an error response, got %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that non-blacklisted policies still work
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/testnot23")
|
||||||
|
req.Data["policies"] = []string{"test1"}
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
testMakeTokenViaRequest(t, ts, req)
|
||||||
|
|
||||||
|
// Create a role to have 'default' policy disallowed
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/default")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"disallowed_policies_glob": "default",
|
||||||
|
}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err:%v resp:%v", err, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "create/default")
|
||||||
|
req.ClientToken = parentToken
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil || resp != nil && !resp.IsError() {
|
||||||
|
t.Fatal("expected an error response")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTokenStore_RoleAllowedPoliciesGlob(t *testing.T) {
|
||||||
|
c, _, root := TestCoreUnsealed(t)
|
||||||
|
ts := c.tokenStore
|
||||||
|
|
||||||
|
// test literal matching works in allowed_policies_glob
|
||||||
|
req := logical.TestRequest(t, logical.UpdateOperation, "roles/test")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"allowed_policies_glob": "test1,test2",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
if resp != nil {
|
||||||
|
t.Fatalf("expected a nil response")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data = map[string]interface{}{}
|
||||||
|
|
||||||
|
req.Path = "create/test"
|
||||||
|
req.Data["policies"] = []string{"foo"}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data["policies"] = []string{"test2"}
|
||||||
|
resp = testMakeTokenViaRequest(t, ts, req)
|
||||||
|
if resp.Auth.ClientToken == "" {
|
||||||
|
t.Fatalf("bad: %#v", resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
// test glob matching in allowed_policies_glob
|
||||||
|
req = logical.TestRequest(t, logical.UpdateOperation, "roles/test")
|
||||||
|
req.ClientToken = root
|
||||||
|
req.Data = map[string]interface{}{
|
||||||
|
"allowed_policies_glob": "test*",
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err != nil || (resp != nil && resp.IsError()) {
|
||||||
|
t.Fatalf("err: %v\nresp: %#v", err, resp)
|
||||||
|
}
|
||||||
|
if resp != nil {
|
||||||
|
t.Fatalf("expected a nil response")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Path = "create/test"
|
||||||
|
req.Data["policies"] = []string{"footest"}
|
||||||
|
resp, err = ts.HandleRequest(namespace.RootContext(nil), req)
|
||||||
|
if err == nil {
|
||||||
|
t.Fatalf("expected error")
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Data["policies"] = []string{"testfoo", "test2", "test"}
|
||||||
|
resp = testMakeTokenViaRequest(t, ts, req)
|
||||||
|
if resp.Auth.ClientToken == "" {
|
||||||
|
t.Fatalf("bad: %#v", resp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestTokenStore_RoleOrphan(t *testing.T) {
|
func TestTokenStore_RoleOrphan(t *testing.T) {
|
||||||
c, _, root := TestCoreUnsealed(t)
|
c, _, root := TestCoreUnsealed(t)
|
||||||
ts := c.tokenStore
|
ts := c.tokenStore
|
||||||
|
@ -4150,18 +4414,20 @@ func TestTokenStore_RoleTokenFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": false,
|
"orphan": false,
|
||||||
"period": int64(1),
|
"period": int64(1),
|
||||||
"token_period": int64(1),
|
"token_period": int64(1),
|
||||||
"allowed_policies": []string(nil),
|
"allowed_policies": []string(nil),
|
||||||
"disallowed_policies": []string(nil),
|
"disallowed_policies": []string(nil),
|
||||||
"path_suffix": "",
|
"allowed_policies_glob": []string(nil),
|
||||||
"token_explicit_max_ttl": int64(3600),
|
"disallowed_policies_glob": []string(nil),
|
||||||
"explicit_max_ttl": int64(3600),
|
"path_suffix": "",
|
||||||
"renewable": false,
|
"token_explicit_max_ttl": int64(3600),
|
||||||
"token_type": "batch",
|
"explicit_max_ttl": int64(3600),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "batch",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
||||||
|
@ -4203,18 +4469,20 @@ func TestTokenStore_RoleTokenFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": false,
|
"orphan": false,
|
||||||
"period": int64(5),
|
"period": int64(5),
|
||||||
"token_period": int64(5),
|
"token_period": int64(5),
|
||||||
"allowed_policies": []string(nil),
|
"allowed_policies": []string(nil),
|
||||||
"disallowed_policies": []string(nil),
|
"disallowed_policies": []string(nil),
|
||||||
"path_suffix": "",
|
"allowed_policies_glob": []string(nil),
|
||||||
"token_explicit_max_ttl": int64(7200),
|
"disallowed_policies_glob": []string(nil),
|
||||||
"explicit_max_ttl": int64(7200),
|
"path_suffix": "",
|
||||||
"renewable": false,
|
"token_explicit_max_ttl": int64(7200),
|
||||||
"token_type": "default-service",
|
"explicit_max_ttl": int64(7200),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "default-service",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
if resp.Data["bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
||||||
|
@ -4255,18 +4523,20 @@ func TestTokenStore_RoleTokenFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": false,
|
"orphan": false,
|
||||||
"period": int64(0),
|
"period": int64(0),
|
||||||
"token_period": int64(7),
|
"token_period": int64(7),
|
||||||
"allowed_policies": []string(nil),
|
"allowed_policies": []string(nil),
|
||||||
"disallowed_policies": []string(nil),
|
"disallowed_policies": []string(nil),
|
||||||
"path_suffix": "",
|
"allowed_policies_glob": []string(nil),
|
||||||
"token_explicit_max_ttl": int64(5200),
|
"disallowed_policies_glob": []string(nil),
|
||||||
"explicit_max_ttl": int64(0),
|
"path_suffix": "",
|
||||||
"renewable": false,
|
"token_explicit_max_ttl": int64(5200),
|
||||||
"token_type": "default-service",
|
"explicit_max_ttl": int64(0),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"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" {
|
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
||||||
|
@ -4309,18 +4579,20 @@ func TestTokenStore_RoleTokenFields(t *testing.T) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expected := map[string]interface{}{
|
expected := map[string]interface{}{
|
||||||
"name": "test",
|
"name": "test",
|
||||||
"orphan": false,
|
"orphan": false,
|
||||||
"period": int64(0),
|
"period": int64(0),
|
||||||
"token_period": int64(5),
|
"token_period": int64(5),
|
||||||
"allowed_policies": []string(nil),
|
"allowed_policies": []string(nil),
|
||||||
"disallowed_policies": []string(nil),
|
"disallowed_policies": []string(nil),
|
||||||
"path_suffix": "",
|
"allowed_policies_glob": []string(nil),
|
||||||
"token_explicit_max_ttl": int64(7200),
|
"disallowed_policies_glob": []string(nil),
|
||||||
"explicit_max_ttl": int64(0),
|
"path_suffix": "",
|
||||||
"renewable": false,
|
"token_explicit_max_ttl": int64(7200),
|
||||||
"token_type": "service",
|
"explicit_max_ttl": int64(0),
|
||||||
"allowed_entity_aliases": []string(nil),
|
"renewable": false,
|
||||||
|
"token_type": "service",
|
||||||
|
"allowed_entity_aliases": []string(nil),
|
||||||
}
|
}
|
||||||
|
|
||||||
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
if resp.Data["token_bound_cidrs"].([]*sockaddr.SockAddrMarshaler)[0].String() != "127.0.0.1" {
|
||||||
|
|
|
@ -73,7 +73,7 @@ during this call.
|
||||||
|
|
||||||
- `role_name` `(string: "")` – The name of the token role.
|
- `role_name` `(string: "")` – The name of the token role.
|
||||||
- `policies` `(array: "")` – A list of policies for the token. This must be a
|
- `policies` `(array: "")` – A list of policies for the token. This must be a
|
||||||
subset of the policies belonging to the token making the request, unless
|
subset of the policies belonging to the token making the request, unless
|
||||||
the calling token is root or contains `sudo` capabilities to `auth/token/create`.
|
the calling token is root or contains `sudo` capabilities to `auth/token/create`.
|
||||||
If not specified, defaults to all the policies of the calling token.
|
If not specified, defaults to all the policies of the calling token.
|
||||||
- `meta` `(map: {})` – A map of string to string valued metadata. This is
|
- `meta` `(map: {})` – A map of string to string valued metadata. This is
|
||||||
|
@ -338,8 +338,8 @@ if there is a lease associated with it.
|
||||||
- `token` `(string: <required>)` - Token to renew. This can be part of the URL
|
- `token` `(string: <required>)` - Token to renew. This can be part of the URL
|
||||||
or the body.
|
or the body.
|
||||||
- `increment` `(string: "")` - An optional requested increment duration can be
|
- `increment` `(string: "")` - An optional requested increment duration can be
|
||||||
provided. This increment may not be honored, for instance in the case of periodic tokens.
|
provided. This increment may not be honored, for instance in the case of periodic tokens.
|
||||||
If not supplied, Vault will use the default TTL. This is specified as a numeric string
|
If not supplied, Vault will use the default TTL. This is specified as a numeric string
|
||||||
with suffix like "30s" or "5m".
|
with suffix like "30s" or "5m".
|
||||||
|
|
||||||
### Sample Payload
|
### Sample Payload
|
||||||
|
@ -389,8 +389,8 @@ possible only if there is a lease associated with it.
|
||||||
### Parameters
|
### Parameters
|
||||||
|
|
||||||
- `increment` `(string: "")` - An optional requested increment duration can be
|
- `increment` `(string: "")` - An optional requested increment duration can be
|
||||||
provided. This increment may not be honored, for instance in the case of periodic tokens.
|
provided. This increment may not be honored, for instance in the case of periodic tokens.
|
||||||
If not supplied, Vault will use the default TTL. This is specified as a numeric string
|
If not supplied, Vault will use the default TTL. This is specified as a numeric string
|
||||||
with suffix like "30s" or "5m".
|
with suffix like "30s" or "5m".
|
||||||
|
|
||||||
### Sample Payload
|
### Sample Payload
|
||||||
|
@ -627,6 +627,8 @@ $ curl \
|
||||||
],
|
],
|
||||||
"allowed_policies": [],
|
"allowed_policies": [],
|
||||||
"disallowed_policies": [],
|
"disallowed_policies": [],
|
||||||
|
"allowed_policies_glob": [],
|
||||||
|
"disallowed_policies_glob": [],
|
||||||
"explicit_max_ttl": 0,
|
"explicit_max_ttl": 0,
|
||||||
"name": "nomad",
|
"name": "nomad",
|
||||||
"orphan": false,
|
"orphan": false,
|
||||||
|
@ -690,13 +692,31 @@ tokens created against a role to be revoked using the
|
||||||
tokens being a subset of the calling token's policies. The parameter is a
|
tokens being a subset of the calling token's policies. The parameter is a
|
||||||
comma-delimited string of policy names. If at creation time
|
comma-delimited string of policy names. If at creation time
|
||||||
`no_default_policy` is not set and `"default"` is not contained in
|
`no_default_policy` is not set and `"default"` is not contained in
|
||||||
`disallowed_policies`, the `"default"` policy will be added to the created
|
`disallowed_policies` or glob matched in `disallowed_policies_glob`,
|
||||||
token automatically.
|
the `"default"` policy will be added to the created token automatically.
|
||||||
- `disallowed_policies` `(list: [])` – If set, successful token creation via
|
- `disallowed_policies` `(list: [])` – If set, successful token creation via
|
||||||
this role will require that no policies in the given list are requested. The
|
this role will require that no policies in the given list are requested. The
|
||||||
parameter is a comma-delimited string of policy names. Adding `"default"` to
|
parameter is a comma-delimited string of policy names. Adding `"default"` to
|
||||||
this list will prevent `"default"` from being added automatically to created
|
this list will prevent `"default"` from being added automatically to created
|
||||||
tokens.
|
tokens.
|
||||||
|
- `allowed_policies_glob` `(list: [])` – If set, tokens can be created with any
|
||||||
|
subset of glob matched policies in this list, rather than the normal semantics
|
||||||
|
of tokens being a subset of the calling token's policies. The parameter is a
|
||||||
|
comma-delimited string of policy name globs. If at creation time
|
||||||
|
`no_default_policy` is not set and `"default"` is not contained in
|
||||||
|
`disallowed_policies` or glob matched in `disallowed_policies_glob`,
|
||||||
|
the `"default"` policy will be added to the created token automatically.
|
||||||
|
If combined with `allowed_policies` policies need to only match one of the two
|
||||||
|
lists to be permitted. Note that unlike `allowed_policies` the policies listed
|
||||||
|
in `allowed_policies_glob` will not be added to the token when no policies are
|
||||||
|
specified in the call to `/auth/token/create/:role_name`.
|
||||||
|
- `disallowed_policies_glob` `(list: [])` – If set, successful token creation via
|
||||||
|
this role will require that no requested policies glob match any of policies in
|
||||||
|
this list. The parameter is a comma-delimited string of policy name globs.
|
||||||
|
Adding any glob that matches `"default"` to this list will prevent `"default"`
|
||||||
|
from being added automatically to created tokens.
|
||||||
|
If combined with `disallowed_policies` policies need to only match one of the
|
||||||
|
two lists to be blocked.
|
||||||
- `orphan` `(bool: false)` - If `true`, tokens created against this policy will
|
- `orphan` `(bool: false)` - If `true`, tokens created against this policy will
|
||||||
be orphan tokens (they will have no parent). As such, they will not be
|
be orphan tokens (they will have no parent). As such, they will not be
|
||||||
automatically revoked by the revocation of any other token.
|
automatically revoked by the revocation of any other token.
|
||||||
|
|
Loading…
Reference in New Issue