diff --git a/api/secret.go b/api/secret.go index bc52f78b72..5c77da2b74 100644 --- a/api/secret.go +++ b/api/secret.go @@ -28,6 +28,7 @@ type Secret struct { // SecretAuth is the structure containing auth information if we have it. type SecretAuth struct { ClientToken string `json:"client_token"` + AccessorID string `json:"accessor_id"` Policies []string `json:"policies"` Metadata map[string]string `json:"metadata"` diff --git a/command/format.go b/command/format.go index 0acac4b70a..800930b513 100644 --- a/command/format.go +++ b/command/format.go @@ -143,6 +143,7 @@ func (t TableFormatter) OutputSecret(ui cli.Ui, secret, s *api.Secret) error { if s.Auth != nil { input = append(input, fmt.Sprintf("token %s %s", config.Delim, s.Auth.ClientToken)) + input = append(input, fmt.Sprintf("token_accessor %s %s", config.Delim, s.Auth.AccessorID)) input = append(input, fmt.Sprintf("token_duration %s %d", config.Delim, s.Auth.LeaseDuration)) input = append(input, fmt.Sprintf("token_renewable %s %v", config.Delim, s.Auth.Renewable)) input = append(input, fmt.Sprintf("token_policies %s %v", config.Delim, s.Auth.Policies)) diff --git a/http/logical.go b/http/logical.go index eb07a8f640..1b30c0781a 100644 --- a/http/logical.go +++ b/http/logical.go @@ -124,6 +124,7 @@ func respondLogical(w http.ResponseWriter, r *http.Request, path string, dataOnl if resp.Auth != nil { logicalResp.Auth = &Auth{ ClientToken: resp.Auth.ClientToken, + AccessorID: resp.Auth.AccessorID, Policies: resp.Auth.Policies, Metadata: resp.Auth.Metadata, LeaseDuration: int(resp.Auth.TTL.Seconds()), @@ -218,6 +219,7 @@ type LogicalResponse struct { type Auth struct { ClientToken string `json:"client_token"` + AccessorID string `json:"accessor_id"` Policies []string `json:"policies"` Metadata map[string]string `json:"metadata"` LeaseDuration int `json:"lease_duration"` diff --git a/logical/auth.go b/logical/auth.go index e297e10eb3..fa887e3d29 100644 --- a/logical/auth.go +++ b/logical/auth.go @@ -33,6 +33,13 @@ type Auth struct { // This will be filled in by Vault core when an auth structure is // returned. Setting this manually will have no effect. ClientToken string + + // AccessorID is the identifier for the ClientToken. This can be used + // to perform management functionalities (especially revocation) when + // ClientToken in the audit logs are obfuscated. AccessorID can be used + // to revoke a ClientToken and to lookup the capabilities of the ClientToken, + // all without actually knowing the ClientToken. + AccessorID string } func (a *Auth) GoString() string { diff --git a/vault/token_store.go b/vault/token_store.go index b319e04a6e..b6afaf5732 100644 --- a/vault/token_store.go +++ b/vault/token_store.go @@ -264,6 +264,7 @@ func NewTokenStore(c *Core, config *logical.BackendConfig) (*TokenStore, error) // TokenEntry is used to represent a given token type TokenEntry struct { ID string // ID of this entry, generally a random UUID + AccessorID string // Accessor ID for this token, a random UUID Parent string // Parent token, used for revocation trees Policies []string // Which named policies should be used Path string // Used for audit trails, this is something like "auth/user/login" @@ -300,6 +301,19 @@ func (ts *TokenStore) rootToken() (*TokenEntry, error) { return te, nil } +// CreateAccessorID is used to create an identifier for the token ID. +func (ts *TokenStore) createAccessorID(entry *TokenEntry) error { + defer metrics.MeasureSince([]string{"token", "createAccessorID"}, time.Now()) + + // Create a random accessor ID + accessorUUID, err := uuid.GenerateUUID() + if err != nil { + return err + } + entry.AccessorID = accessorUUID + return nil +} + // Create is used to create a new token entry. The entry is assigned // a newly generated ID if not provided. func (ts *TokenStore) create(entry *TokenEntry) error { @@ -313,6 +327,11 @@ func (ts *TokenStore) create(entry *TokenEntry) error { entry.ID = entryUUID } + err := ts.createAccessorID(entry) + if err != nil { + return err + } + return ts.storeCommon(entry, true) } @@ -705,6 +724,7 @@ func (ts *TokenStore) handleCreateCommon( Renewable: true, }, ClientToken: te.ID, + AccessorID: te.AccessorID, }, }