Skip to content

egress policy: add an RFC 8693 token exchange source to CredentialHeader - #3334

Open
Max Thompson (thompsonmax) wants to merge 3 commits into
agent-substrate:mainfrom
thompsonmax:token-exchange-api
Open

Max Thompson (thompsonmax) wants to merge 3 commits into
agent-substrate:mainfrom
thompsonmax:token-exchange-api

Conversation

@thompsonmax

@thompsonmax Max Thompson (thompsonmax) commented Oct 27, 2026 •

Copy link
Copy Markdown
Collaborator

Part of #1661.

  • Adds CredentialHeader.token_exchange (TokenExchangeSource: token_url, audience, scopes) as a third union member, the same way egress policy: add an actor JWT value source to CredentialHeader #1960 added actor_jwt.
  • ateapi accepts only an https token_url with a DNS hostname and no userinfo, query, or fragment. It also rejects an EgressPolicy or golden egress policy unless one of its https rules allows the token_url's host and port, so the gateway reaches nothing the policy doesn't already allow. The check runs the gateway's own matcher, egresspolicy.Compile and EvaluateRequest.
  • Until the gateway can exchange tokens, it denies a request that carries a token_exchange header with a 500. Without that case, a gateway without --credential-provider-name would ask its provider for the entry's empty URI.

The policy names the endpoint inline, which replaces the per-install provider list #1661 first proposed. A policy can have at most 16 token_exchange entries, since each costs a pass over every rule at admission. Agentgateway already denies the unknown source with a 403. The user guide still lists two sources; it gets updated with the e2e PR, once the gateway injects the token.

Testing: unit tests for validation (policies and templates) and for the gateway's 500 on both legs. Each new case fails without its check. A module-wide go test -race ./... passes except cmd/ateworker-microvm/internal/child, which fails on main on macOS too, and an atelet registry test that timed out under load and passes alone. hack/verify-all.sh passes.

AI use: AI-assisted (Claude Code) for code, tests, and docs. I reviewed and tested it.

  • Tests pass
  • Docs updated (the proto comments are the API docs; the user guide comes with the e2e PR)

A replace_headers entry can now set token_exchange, naming an RFC 8693
token endpoint, an audience, and scopes. The egress gateway will exchange
the actor's JWT there and inject the returned access token.

ateapi requires token_url to be https with a DNS hostname and no
userinfo, query, or fragment. It also rejects a policy unless one of its
https rules allows the token_url's host and port, so the endpoint stays
within what the policy already allows. EgressPolicyTemplate gets the same
check.

The gateway does not exchange tokens yet and denies a request that
carries a token_exchange header with a 500. Without that case the entry
would reach the credential provider with an empty URI.

Signed-off-by: Max Thompson <maxthomp@google.com>
TestSecretLikeFieldsAreLabeled flags fields whose names look like
credentials. token_exchange holds an endpoint, an audience, and scopes,
and token_url can carry no userinfo or query, so neither holds a secret.

The token URL check now skips headers that use another source, and the
token_url doc names the DNS hostname rule. The http-rule test case now
fails on the protocol alone, and the scopes limits have test cases.

Signed-off-by: Max Thompson <maxthomp@google.com>
Each token_exchange entry costs a pass over every rule when ateapi
checks that an https rule allows its token URL. A policy with thousands
of entries could cost seconds of CPU. Reject more than 16, the same
bound as one rule's replace_headers, before running the check.

Signed-off-by: Max Thompson <maxthomp@google.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/api User-facing API changes area/api-machinery area/identity area/network area/security Security related issue/pr kind/feature An enhancement / feature request or implementation

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants