VAULT-5935 agent: redact renew-self if using auto auth (#15380)

Vault agent redacts the token and accessor for `/auth/token/lookup-self` (and `lookup`)
if the token is the auto auth token to prevent it from leaking.

Similarly, we need to redact the token and accessor from `renew-self`
and `renew`, which also leak the token and accessor.

I tested this locally by starting up a Vault agent and querying the
agent endpoints, and ensuring that the accessor and token were set to
the empty string in the response.
This commit is contained in:
Christopher Swenson 2022-05-12 09:25:55 -07:00 committed by GitHub
parent 8497010acd
commit 0af0543bbe
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 63 additions and 19 deletions

3
changelog/15380.txt Normal file
View File

@ -0,0 +1,3 @@
```release-note:bug
agent: Redact auto auth token from renew endpoints
```

View File

@ -2,6 +2,7 @@ package cache
import (
"context"
"encoding/json"
"fmt"
"io"
"math/rand"
@ -13,7 +14,7 @@ import (
"time"
"github.com/go-test/deep"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-hclog"
kv "github.com/hashicorp/vault-plugin-secrets-kv"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/builtin/credential/userpass"
@ -214,9 +215,13 @@ func tokenRevocationValidation(t *testing.T, sampleSpace map[string]string, expe
func TestCache_AutoAuthTokenStripping(t *testing.T) {
response1 := `{"data": {"id": "testid", "accessor": "testaccessor", "request": "lookup-self"}}`
response2 := `{"data": {"id": "testid", "accessor": "testaccessor", "request": "lookup"}}`
response3 := `{"auth": {"client_token": "testid", "accessor": "testaccessor"}}`
response4 := `{"auth": {"client_token": "testid", "accessor": "testaccessor"}}`
responses := []*SendResponse{
newTestSendResponse(http.StatusOK, response1),
newTestSendResponse(http.StatusOK, response2),
newTestSendResponse(http.StatusOK, response3),
newTestSendResponse(http.StatusOK, response4),
}
leaseCache := testNewLeaseCache(t, responses)
@ -279,6 +284,30 @@ func TestCache_AutoAuthTokenStripping(t *testing.T) {
if secret.Data["id"] != nil || secret.Data["accessor"] != nil || secret.Data["request"].(string) != "lookup" {
t.Fatalf("failed to strip off auto-auth token on lookup")
}
secret, err = testClient.Auth().Token().RenewSelf(1)
if err != nil {
t.Fatal(err)
}
if secret.Auth == nil {
secretJson, _ := json.Marshal(secret)
t.Fatalf("Expected secret to have Auth but was %s", secretJson)
}
if secret.Auth.ClientToken != "" || secret.Auth.Accessor != "" {
t.Fatalf("failed to strip off auto-auth token on renew-self")
}
secret, err = testClient.Auth().Token().Renew("testid", 1)
if err != nil {
t.Fatal(err)
}
if secret.Auth == nil {
secretJson, _ := json.Marshal(secret)
t.Fatalf("Expected secret to have Auth but was %s", secretJson)
}
if secret.Auth.ClientToken != "" || secret.Auth.Accessor != "" {
t.Fatalf("failed to strip off auto-auth token on renew")
}
}
func TestCache_AutoAuthClientTokenProxyStripping(t *testing.T) {

View File

@ -13,7 +13,7 @@ import (
"time"
"github.com/armon/go-metrics"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agent/sink"
"github.com/hashicorp/vault/sdk/helper/consts"
@ -67,7 +67,7 @@ func Handler(ctx context.Context, logger hclog.Logger, proxier Proxier, inmemSin
return
}
err = processTokenLookupResponse(ctx, logger, inmemSink, req, resp)
err = sanitizeAutoAuthTokenResponse(ctx, logger, inmemSink, req, resp)
if err != nil {
logical.RespondError(w, http.StatusInternalServerError, fmt.Errorf("failed to process token lookup response: %w", err))
return
@ -120,11 +120,10 @@ func setHeaders(w http.ResponseWriter, resp *SendResponse) {
w.WriteHeader(resp.Response.StatusCode)
}
// processTokenLookupResponse checks if the request was one of token
// lookup-self. If the auto-auth token was used to perform lookup-self, the
// identifier of the token and its accessor same will be stripped off of the
// response.
func processTokenLookupResponse(ctx context.Context, logger hclog.Logger, inmemSink sink.Sink, req *SendRequest, resp *SendResponse) error {
// sanitizeAutoAuthTokenResponse checks if the request was a lookup or renew
// and if the auto-auth token was used to perform lookup-self, the identifier
// of the token and its accessor same will be stripped off of the response.
func sanitizeAutoAuthTokenResponse(ctx context.Context, logger hclog.Logger, inmemSink sink.Sink, req *SendRequest, resp *SendResponse) error {
// If auto-auth token is not being used, there is nothing to do.
if inmemSink == nil {
return nil
@ -138,11 +137,11 @@ func processTokenLookupResponse(ctx context.Context, logger hclog.Logger, inmemS
_, path := deriveNamespaceAndRevocationPath(req)
switch path {
case vaultPathTokenLookupSelf:
case vaultPathTokenLookupSelf, vaultPathTokenRenewSelf:
if req.Token != autoAuthToken {
return nil
}
case vaultPathTokenLookup:
case vaultPathTokenLookup, vaultPathTokenRenew:
jsonBody := map[string]interface{}{}
if err := json.Unmarshal(req.RequestBody, &jsonBody); err != nil {
return err
@ -170,15 +169,26 @@ func processTokenLookupResponse(ctx context.Context, logger hclog.Logger, inmemS
if err != nil {
return fmt.Errorf("failed to parse token lookup response: %v", err)
}
if secret == nil || secret.Data == nil {
if secret == nil {
return nil
} else if secret.Data != nil {
// lookup endpoints
if secret.Data["id"] == nil && secret.Data["accessor"] == nil {
return nil
}
delete(secret.Data, "id")
delete(secret.Data, "accessor")
} else if secret.Auth != nil {
// renew endpoints
if secret.Auth.Accessor == "" && secret.Auth.ClientToken == "" {
return nil
}
secret.Auth.Accessor = ""
secret.Auth.ClientToken = ""
} else {
// nothing to redact
return nil
}
if secret.Data["id"] == nil && secret.Data["accessor"] == nil {
return nil
}
delete(secret.Data, "id")
delete(secret.Data, "accessor")
bodyBytes, err := json.Marshal(secret)
if err != nil {

View File

@ -16,12 +16,12 @@ import (
"sync"
"time"
hclog "github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-hclog"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/go-secure-stdlib/base62"
"github.com/hashicorp/vault/api"
"github.com/hashicorp/vault/command/agent/cache/cacheboltdb"
cachememdb "github.com/hashicorp/vault/command/agent/cache/cachememdb"
"github.com/hashicorp/vault/command/agent/cache/cachememdb"
"github.com/hashicorp/vault/helper/namespace"
nshelper "github.com/hashicorp/vault/helper/namespace"
vaulthttp "github.com/hashicorp/vault/http"
@ -42,6 +42,8 @@ const (
vaultPathTokenRevokeOrphan = "/v1/auth/token/revoke-orphan"
vaultPathTokenLookup = "/v1/auth/token/lookup"
vaultPathTokenLookupSelf = "/v1/auth/token/lookup-self"
vaultPathTokenRenew = "/v1/auth/token/renew"
vaultPathTokenRenewSelf = "/v1/auth/token/renew-self"
vaultPathLeaseRevoke = "/v1/sys/leases/revoke"
vaultPathLeaseRevokeForce = "/v1/sys/leases/revoke-force"
vaultPathLeaseRevokePrefix = "/v1/sys/leases/revoke-prefix"