feat(agentgateway-bootstrap): add optional JWT authentication#309
Merged
Andy Lo-A-Foe (loafoe) merged 2 commits intoJul 23, 2026
Conversation
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.
…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.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
jwt.enabled(defaultfalse) to gate a new Gateway-wideAgentgatewayPolicyrequiring a valid JWT (
mode: Strict) on every request once enabled, perhttps://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+ TLSsni) that the policy'sjwks.remote.backendRefpoints at, since the JWKS source is outside the cluster, nota
Service.New values:
jwt.issuer/jwt.audiences— standardiss/audclaim validationjwt.externalIssuer.{host,port,jwksPath,sni}— the issuer's JWKS endpoint (host/jwksPathcome from the issuer's own/.well-known/openid-configurationdocument,e.g. its
jwks_uri)jwt.cacheDuration— local JWKS cache TTL (CRD-enforced minimum5m)Test plan
jwt.enabled=false(default) renders neither new resourcejwt.enabled=truewith real values (issuerhttps://issuer.rpi.loafoe.com)renders both resources correctly —
AgentgatewayBackendwith the righthost/port/SNI,
AgentgatewayPolicywithmode: Strict, correctissuer/audiences/jwksPath, and a correctly cross-referenced
backendRefhelm lintpasses