diff --git a/vault/token_store.go b/vault/token_store.go index ee01573976..fd9cbf8cf9 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -156,6 +156,12 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error) Default: 0, Description: tokenExplicitMaxTTLHelp, }, + + "renewable": &framework.FieldSchema{ + Type: framework.TypeBool, + Default: true, + Description: tokenRenewableHelp, + }, }, Callbacks: map[logical.Operation]framework.OperationFunc{ @@ -444,6 +450,9 @@ type tsRoleEntry struct { // revoke using 'revoke-prefix' PathSuffix string `json:"path_suffix" mapstructure:"path_suffix" structs:"path_suffix"` + // If set, controls whether created tokens are marked as being renewable + Renewable bool `json:"renewable" mapstructure:"renewable" structs:"renewable"` + // If set, the token entry will have an explicit maximum TTL set, rather // than deferring to role/mount values ExplicitMaxTTL time.Duration `json:"explicit_max_ttl" mapstructure:"explicit_max_ttl" structs:"explicit_max_ttl"` @@ -978,6 +987,12 @@ func (ts *TokenStore) handleCreateCommon( if role != nil { te.Role = role.Name + // If renewable hasn't been disabled in the call and the role has + // renewability disabled, set renewable false + if renewable && !role.Renewable { + renewable = false + } + if role.PathSuffix != "" { te.Path = fmt.Sprintf("%s/%s", te.Path, role.PathSuffix) } @@ -1449,6 +1464,7 @@ func (ts *TokenStore) tokenStoreRoleRead( "name": role.Name, "orphan": role.Orphan, "path_suffix": role.PathSuffix, + "renewable": role.Renewable, }, } @@ -1505,6 +1521,13 @@ func (ts *TokenStore) tokenStoreRoleCreateUpdate( entry.Period = time.Second * time.Duration(data.Get("period").(int)) } + renewableInt, ok := data.GetOk("renewable") + if ok { + entry.Renewable = renewableInt.(bool) + } else if req.Operation == logical.CreateOperation { + entry.Renewable = data.Get("renewable").(bool) + } + var resp *logical.Response explicitMaxTTLInt, ok := data.GetOk("explicit_max_ttl") @@ -1610,4 +1633,7 @@ the current maximum TTL values of the role and the mount are not checked for changes, and any updates to these values will have no effect on the token being renewed.` + tokenRenewableHelp = `Tokens created via this role will be +renewable or not according to this value. +Defaults to "true".` ) diff --git a/vault/token_store_test.go b/vault/token_store_test.go index b37edefba2..aebd70d32a 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -1275,6 +1275,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "allowed_policies": []string{"default", "test1", "test2"}, "path_suffix": "happenin", "explicit_max_ttl": int64(0), + "renewable": true, } if !reflect.DeepEqual(expected, resp.Data) { @@ -1288,6 +1289,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "period": "79h", "allowed_policies": "test3", "path_suffix": "happenin", + "renewable": false, } resp, err = core.HandleRequest(req) @@ -1316,6 +1318,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "allowed_policies": []string{"default", "test3"}, "path_suffix": "happenin", "explicit_max_ttl": int64(0), + "renewable": false, } if !reflect.DeepEqual(expected, resp.Data) { @@ -1363,6 +1366,7 @@ func TestTokenStore_RoleCRUD(t *testing.T) { "allowed_policies": []string{"default", "test3"}, "path_suffix": "happenin", "period": int64(0), + "renewable": false, } if !reflect.DeepEqual(expected, resp.Data) { diff --git a/website/source/docs/auth/token.html.md b/website/source/docs/auth/token.html.md index 97e53aefdd..e57306e731 100644 --- a/website/source/docs/auth/token.html.md +++ b/website/source/docs/auth/token.html.md @@ -603,6 +603,13 @@ of the header should be "X-Vault-Token" and the value should be the token. track updates to the role value; the new period takes effect upon next renew. This cannot be used in conjunction with `explicit_max_ttl`. +