Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow Token Create Requests To Be Replicated #18689

Merged
merged 4 commits into from
Jan 24, 2023
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 1 addition & 8 deletions http/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -828,16 +828,9 @@ func handleRequestForwarding(core *vault.Core, handler http.Handler) http.Handle
return
}
path := ns.TrimmedPath(r.URL.Path[len("/v1/"):])
switch {
case !perfStandbyAlwaysForwardPaths.HasPath(path) && !alwaysRedirectPaths.HasPath(path):
if !perfStandbyAlwaysForwardPaths.HasPath(path) && !alwaysRedirectPaths.HasPath(path) {
handler.ServeHTTP(w, r)
return
case strings.HasPrefix(path, "auth/token/create/"):
isBatch, err := core.IsBatchTokenCreationRequest(r.Context(), path)
if err == nil && isBatch {
handler.ServeHTTP(w, r)
return
}
}
}

Expand Down
694 changes: 352 additions & 342 deletions sdk/plugin/pb/backend.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions sdk/plugin/pb/backend.proto
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ message TokenEntry {
map<string, string> internal_meta = 19;
string inline_policy = 20;
bool no_identity_policies = 21;
string external_id = 22;
}

message LeaseOptions {
Expand Down
2 changes: 2 additions & 0 deletions sdk/plugin/pb/translation.go
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,7 @@ func LogicalTokenEntryToProtoTokenEntry(t *logical.TokenEntry) *TokenEntry {
NamespaceID: t.NamespaceID,
CubbyholeID: t.CubbyholeID,
Type: uint32(t.Type),
ExternalID: t.ExternalID,
}
}

Expand Down Expand Up @@ -660,6 +661,7 @@ func ProtoTokenEntryToLogicalTokenEntry(t *TokenEntry) (*logical.TokenEntry, err
NamespaceID: t.NamespaceID,
CubbyholeID: t.CubbyholeID,
Type: logical.TokenType(t.Type),
ExternalID: t.ExternalID,
}, nil
}

Expand Down
38 changes: 20 additions & 18 deletions vault/request_handling.go
Original file line number Diff line number Diff line change
Expand Up @@ -1191,26 +1191,28 @@ func (c *Core) handleRequest(ctx context.Context, req *logical.Request) (retResp
switch resp.Auth.TokenType {
case logical.TokenTypeBatch:
case logical.TokenTypeService:
registeredTokenEntry := &logical.TokenEntry{
TTL: auth.TTL,
Policies: auth.TokenPolicies,
Path: resp.Auth.CreationPath,
NamespaceID: ns.ID,
}
if err := c.expiration.RegisterAuth(ctx, registeredTokenEntry, resp.Auth, c.DetermineRoleFromLoginRequest(req.MountPoint, req.Data, ctx)); err != nil {
// Best-effort clean up on error, so we log the cleanup error as
// a warning but still return as internal error.
if err := c.tokenStore.revokeOrphan(ctx, resp.Auth.ClientToken); err != nil {
c.logger.Warn("failed to clean up token lease during auth/token/ request", "request_path", req.Path, "error", err)
if !c.perfStandby {
registeredTokenEntry := &logical.TokenEntry{
TTL: auth.TTL,
Policies: auth.TokenPolicies,
Path: resp.Auth.CreationPath,
NamespaceID: ns.ID,
}
c.logger.Error("failed to register token lease during auth/token/ request", "request_path", req.Path, "error", err)
retErr = multierror.Append(retErr, ErrInternalError)
return nil, auth, retErr
}
if registeredTokenEntry.ExternalID != "" {
resp.Auth.ClientToken = registeredTokenEntry.ExternalID
if err := c.expiration.RegisterAuth(ctx, registeredTokenEntry, resp.Auth, c.DetermineRoleFromLoginRequest(req.MountPoint, req.Data, ctx)); err != nil {
// Best-effort clean up on error, so we log the cleanup error as
// a warning but still return as internal error.
if err := c.tokenStore.revokeOrphan(ctx, resp.Auth.ClientToken); err != nil {
c.logger.Warn("failed to clean up token lease during auth/token/ request", "request_path", req.Path, "error", err)
}
c.logger.Error("failed to register token lease during auth/token/ request", "request_path", req.Path, "error", err)
retErr = multierror.Append(retErr, ErrInternalError)
return nil, auth, retErr
}
if registeredTokenEntry.ExternalID != "" {
resp.Auth.ClientToken = registeredTokenEntry.ExternalID
}
leaseGenerated = true
}
leaseGenerated = true
}
}

Expand Down
5 changes: 5 additions & 0 deletions vault/request_handling_util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ package vault
import (
"context"
"sync"
"time"

"github.com/hashicorp/vault/helper/identity"
"github.com/hashicorp/vault/sdk/logical"
Expand Down Expand Up @@ -80,3 +81,7 @@ func possiblyForwardSaveCachedAuthResponse(ctx context.Context, c *Core, respAut

return nil
}

func forwardCreateTokenRegisterAuth(ctx context.Context, c *Core, te *logical.TokenEntry, roleName string, renewable bool, periodToUse, explicitMaxTTLToUse time.Duration) (*logical.TokenEntry, error) {
return nil, nil
}
44 changes: 22 additions & 22 deletions vault/token_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -2067,25 +2067,6 @@ func (ts *TokenStore) revokeTreeInternal(ctx context.Context, id string) error {
return nil
}

func (c *Core) IsBatchTokenCreationRequest(ctx context.Context, path string) (bool, error) {
c.stateLock.RLock()
defer c.stateLock.RUnlock()

if c.tokenStore == nil {
return false, fmt.Errorf("no token store")
}

name := strings.TrimPrefix(path, "auth/token/create/")
roleEntry, err := c.tokenStore.tokenStoreRole(ctx, name)
if err != nil {
return false, err
}
if roleEntry == nil {
return false, fmt.Errorf("unknown role")
}
return roleEntry.TokenType == logical.TokenTypeBatch, nil
}

// handleCreateAgainstRole handles the auth/token/create path for a role
func (ts *TokenStore) handleCreateAgainstRole(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
name := d.Get("role_name").(string)
Expand Down Expand Up @@ -3171,9 +3152,22 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
resp.AddWarning("Supplying a custom ID for the token uses the weaker SHA1 hashing instead of the more secure SHA2-256 HMAC for token obfuscation. SHA1 hashed tokens on the wire leads to less secure lookups.")
}

// Create the token
if err := ts.create(ctx, &te); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
// check if we are perfStandby, and if so forward the service token
// creation to the active node
var roleName string
if role != nil {
roleName = role.Name
}
if te.Type == logical.TokenTypeService && ts.core.perfStandby {
forwardedTokenEntry, err := forwardCreateTokenRegisterAuth(ctx, ts.core, &te, roleName, renewable, periodToUse, explicitMaxTTLToUse)
if err != nil {
return logical.ErrorResponse(err.Error()), ErrInternalError
}
te = *forwardedTokenEntry
} else {
if err := ts.create(ctx, &te); err != nil {
return logical.ErrorResponse(err.Error()), logical.ErrInvalidRequest
}
}

// Count the successful token creation.
Expand Down Expand Up @@ -3211,6 +3205,12 @@ func (ts *TokenStore) handleCreateCommon(ctx context.Context, req *logical.Reque
Orphan: te.Parent == "",
}

// We have registered the auth at this point if the token is of service
// type and core is perfStandby.
if te.Type == logical.TokenTypeService && ts.core.perfStandby && te.ExternalID != "" {
resp.Auth.ClientToken = te.ExternalID
}

for _, p := range te.Policies {
policy, err := ts.core.policyStore.GetPolicy(ctx, p, PolicyTypeToken)
if err != nil {
Expand Down