diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ac496c92..ecb695fa8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,7 +25,9 @@ FEATURES: which allows a token to retrieve its own information, and `revoke-self` and `renew-self`, which are self-explanatory. If your existing Vault installation contains a policy called `default`, it will not be overridden, - but it will be added to each new token created. [GH-732] + but it will be added to each new token created. You can override this + behavior when using manual token creation (i.e. not via an authentication + backend) by setting the "no_default_policy" flag to true. [GH-732] IMPROVEMENTS: diff --git a/api/auth_token.go b/api/auth_token.go index 1e636f22b..791e81450 100644 --- a/api/auth_token.go +++ b/api/auth_token.go @@ -117,12 +117,13 @@ func (c *TokenAuth) RevokeTree(token string) error { // TokenCreateRequest is the options structure for creating a token. type TokenCreateRequest struct { - ID string `json:"id,omitempty"` - Policies []string `json:"policies,omitempty"` - Metadata map[string]string `json:"meta,omitempty"` - Lease string `json:"lease,omitempty"` - TTL string `json:"ttl,omitempty"` - NoParent bool `json:"no_parent,omitempty"` - DisplayName string `json:"display_name"` - NumUses int `json:"num_uses"` + ID string `json:"id,omitempty"` + Policies []string `json:"policies,omitempty"` + Metadata map[string]string `json:"meta,omitempty"` + Lease string `json:"lease,omitempty"` + TTL string `json:"ttl,omitempty"` + NoParent bool `json:"no_parent,omitempty"` + NoDefaultPolicy bool `json:"no_default_policy,omitempty"` + DisplayName string `json:"display_name"` + NumUses int `json:"num_uses"` } diff --git a/command/token_create.go b/command/token_create.go index 2256e2123..fb3ffcfc7 100644 --- a/command/token_create.go +++ b/command/token_create.go @@ -17,7 +17,7 @@ type TokenCreateCommand struct { func (c *TokenCreateCommand) Run(args []string) int { var format string var id, displayName, lease, ttl string - var orphan bool + var orphan, noDefaultPolicy bool var metadata map[string]string var numUses int var policies []string @@ -28,6 +28,7 @@ func (c *TokenCreateCommand) Run(args []string) int { flags.StringVar(&lease, "lease", "", "") flags.StringVar(&ttl, "ttl", "", "") flags.BoolVar(&orphan, "orphan", false, "") + flags.BoolVar(&noDefaultPolicy, "no-default-policy", false, "") flags.IntVar(&numUses, "use-limit", 0, "") flags.Var((*kvFlag.Flag)(&metadata), "metadata", "") flags.Var((*sliceflag.StringFlag)(&policies), "policy", "") @@ -55,13 +56,14 @@ func (c *TokenCreateCommand) Run(args []string) int { ttl = lease } secret, err := client.Auth().Token().Create(&api.TokenCreateRequest{ - ID: id, - Policies: policies, - Metadata: metadata, - TTL: ttl, - NoParent: orphan, - DisplayName: displayName, - NumUses: numUses, + ID: id, + Policies: policies, + Metadata: metadata, + TTL: ttl, + NoParent: orphan, + NoDefaultPolicy: noDefaultPolicy, + DisplayName: displayName, + NumUses: numUses, }) if err != nil { @@ -122,6 +124,9 @@ Token Options: root tokens can create orphan tokens. This prevents the new token from being revoked with your token. + -no-default-policy If specified, the token will not have the "default" + policy included in its policy set. + -policy="name" Policy to associate with this token. This can be specified multiple times. diff --git a/vault/core_test.go b/vault/core_test.go index e1b1e0f17..887b5c8ba 100644 --- a/vault/core_test.go +++ b/vault/core_test.go @@ -1036,6 +1036,45 @@ func TestCore_HandleRequest_CreateToken_Lease(t *testing.T) { } } +// Check that we handle excluding the default policy +func TestCore_HandleRequest_CreateToken_NoDefaultPolicy(t *testing.T) { + c, _, root := TestCoreUnsealed(t) + + // Create a new credential + req := logical.TestRequest(t, logical.WriteOperation, "auth/token/create") + req.ClientToken = root + req.Data["policies"] = []string{"foo"} + req.Data["no_default_policy"] = true + resp, err := c.HandleRequest(req) + if err != nil { + t.Fatalf("err: %v", err) + } + + // Ensure we got a new client token back + clientToken := resp.Auth.ClientToken + if clientToken == "" { + t.Fatalf("bad: %#v", resp) + } + + // Check the policy and metadata + te, err := c.tokenStore.Lookup(clientToken) + if err != nil { + t.Fatalf("err: %v", err) + } + expect := &TokenEntry{ + ID: clientToken, + Parent: root, + Policies: []string{"foo"}, + Path: "auth/token/create", + DisplayName: "token", + CreationTime: te.CreationTime, + TTL: time.Hour * 24 * 30, + } + if !reflect.DeepEqual(te, expect) { + t.Fatalf("Bad: %#v expect: %#v", te, expect) + } +} + func TestCore_LimitedUseToken(t *testing.T) { c, _, root := TestCoreUnsealed(t) diff --git a/vault/token_store.go b/vault/token_store.go index 50421db99..c43bf4580 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -547,14 +547,15 @@ func (ts *TokenStore) handleCreateCommon( // Read and parse the fields var data struct { - ID string - Policies []string - Metadata map[string]string `mapstructure:"meta"` - NoParent bool `mapstructure:"no_parent"` - Lease string - TTL string - DisplayName string `mapstructure:"display_name"` - NumUses int `mapstructure:"num_uses"` + ID string + Policies []string + Metadata map[string]string `mapstructure:"meta"` + NoParent bool `mapstructure:"no_parent"` + NoDefaultPolicy bool `mapstructure:"no_default_policy"` + Lease string + TTL string + DisplayName string `mapstructure:"display_name"` + NumUses int `mapstructure:"num_uses"` } if err := mapstructure.WeakDecode(req.Data, &data); err != nil { return logical.ErrorResponse(fmt.Sprintf( @@ -602,7 +603,7 @@ func (ts *TokenStore) handleCreateCommon( return logical.ErrorResponse("child policies must be subset of parent"), logical.ErrInvalidRequest } te.Policies = data.Policies - if !strListSubset(te.Policies, []string{"root"}) { + if !strListSubset(te.Policies, []string{"root"}) && !data.NoDefaultPolicy { te.Policies = append(te.Policies, "default") } diff --git a/vault/token_store_test.go b/vault/token_store_test.go index 8a47627ad..b44ca0160 100644 --- a/vault/token_store_test.go +++ b/vault/token_store_test.go @@ -888,7 +888,7 @@ func TestTokenStore_HandleRequest_Lookup(t *testing.T) { exp = map[string]interface{}{ "id": "client", - "policies": []string{"foo"}, + "policies": []string{"foo", "default"}, "path": "auth/token/create", "meta": map[string]string(nil), "display_name": "token", diff --git a/website/source/docs/auth/token.html.md b/website/source/docs/auth/token.html.md index 18743bf7a..f976b4d5c 100644 --- a/website/source/docs/auth/token.html.md +++ b/website/source/docs/auth/token.html.md @@ -87,6 +87,12 @@ of the header should be "X-Vault-Token" and the value should be the token. If true and set by a root caller, the token will not have the parent token of the caller. This creates a token with no parent. +