Skip to content

feat(agentgateway-bootstrap): add optional JWT authentication#309

Merged
Andy Lo-A-Foe (loafoe) merged 2 commits into
mainfrom
feat/agentgateway-bootstrap-jwt-auth
Jul 23, 2026
Merged

feat(agentgateway-bootstrap): add optional JWT authentication#309
Andy Lo-A-Foe (loafoe) merged 2 commits into
mainfrom
feat/agentgateway-bootstrap-jwt-auth

Conversation

@loafoe

Copy link
Copy Markdown
Member

Summary

Adds jwt.enabled (default false) to gate a new Gateway-wide AgentgatewayPolicy
requiring a valid JWT (mode: Strict) on every request once enabled, per
https://agentgateway.dev/docs/kubernetes/latest/security/jwt/setup/.

Supports an external issuer reached over TLS
(https://agentgateway.dev/docs/kubernetes/latest/security/jwt/setup/#external-identity-provider-over-tls):
a new AgentgatewayBackend (host/port + TLS sni) that the policy's
jwks.remote.backendRef points at, since the JWKS source is outside the cluster, not
a Service.

New values:

  • jwt.issuer / jwt.audiences — standard iss/aud claim validation
  • jwt.externalIssuer.{host,port,jwksPath,sni} — the issuer's JWKS endpoint (host/
    jwksPath come from the issuer's own /.well-known/openid-configuration document,
    e.g. its jwks_uri)
  • jwt.cacheDuration — local JWKS cache TTL (CRD-enforced minimum 5m)

Test plan

  • jwt.enabled=false (default) renders neither new resource
  • jwt.enabled=true with real values (issuer https://issuer.rpi.loafoe.com)
    renders both resources correctly — AgentgatewayBackend with the right
    host/port/SNI, AgentgatewayPolicy with mode: Strict, correct
    issuer/audiences/jwksPath, and a correctly cross-referenced backendRef
  • helm lint passes

Adds jwt.enabled (default false) to gate a new Gateway-wide
AgentgatewayPolicy that requires a valid JWT (mode: Strict) on every
request once enabled. Supports an external issuer reached over TLS -
per https://agentgateway.dev/docs/kubernetes/latest/security/jwt/setup/,
this needs an AgentgatewayBackend (host/port + TLS SNI) that the
policy's jwks.remote.backendRef points at, rather than a Service.

New values:
- jwt.issuer / jwt.audiences - standard iss/aud claim validation
- jwt.externalIssuer.{host,port,jwksPath,sni} - the issuer's JWKS
  endpoint (jwksPath/host come from the issuer's own
  /.well-known/openid-configuration document, e.g. jwks_uri)
- jwt.cacheDuration - local JWKS cache TTL (CRD-enforced minimum 5m)

Both new resources are gated on jwt.enabled and gateway.enabled, and
skip dry-run on missing CRDs (SkipDryRunOnMissingResource), matching
every other agentgateway.dev-typed resource already in this chart.
@loafoe
Andy Lo-A-Foe (loafoe) requested a review from a team as a code owner July 23, 2026 15:15
…nces

Adversarial review caught two real gaps:

1. jwt.enabled: true with empty jwt.issuer or jwt.externalIssuer.host
   rendered a syntactically valid but semantically broken
   AgentgatewayPolicy/AgentgatewayBackend (issuer: "", static.host: "")
   that only failed at ArgoCD-apply time (kubectl dry-run rejects an
   empty issuer/host), not at helm template/CI-lint time. Extends the
   existing agentgateway-bootstrap.validateConfig helper (already used
   by agentgateway-crds-helm.yaml/agentgateway-helm.yaml for this exact
   failure mode) to also require these two fields, and calls it from
   both new JWT templates.

2. jwt.audiences defaulting to an empty list (-> the audiences field
   omitted entirely) means "accept any audience" per the CRD's own doc
   string. Since the issuer in this deployment (and most OIDC providers
   generally) is shared across multiple services, an unset audiences
   list would let a validly-signed JWT minted for a completely
   different service authenticate against this Gateway. Requiring
   jwt.audiences to be non-empty whenever jwt.enabled is true closes
   this gap outright rather than just documenting the risk.
@loafoe
Andy Lo-A-Foe (loafoe) merged commit 138203f into main Jul 23, 2026
5 checks passed
@loafoe
Andy Lo-A-Foe (loafoe) deleted the feat/agentgateway-bootstrap-jwt-auth branch July 23, 2026 15:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant