feat: add async fetch and retry support for remote JWKS#14211
Conversation
Signed-off-by: Lahiru De Silva <[email protected]>
Signed-off-by: Lahiru De Silva <[email protected]>
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
Adds support for configuring Envoy JWT remote JWKS async fetch and retry policy through GatewayExtension JWT config, plus translator outputs and end-to-end coverage.
Changes:
- Extend JWT
RemoteJWKSAPI/CRD withasyncFetchandretryPolicyfields. - Update JWT translation to emit Envoy
remoteJwks.asyncFetchandremoteJwks.retryPolicy. - Add unit/translator tests and new e2e manifest + test case for remote JWKS async behavior.
Reviewed changes
Copilot reviewed 9 out of 10 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
| test/e2e/features/jwt/testdata/jwt-remote-async.yaml | Adds e2e manifests to exercise remote JWKS async fetch + retries. |
| test/e2e/features/jwt/suite.go | Registers and implements a new e2e test that uses the new manifest. |
| pkg/kgateway/translator/gateway/testutils/inputs/jwt/remote-jwks-async.yaml | Adds translator test input for remote JWKS async/retry configuration. |
| pkg/kgateway/translator/gateway/testutils/outputs/jwt/remote-jwks-async.yaml | Adds expected translated output including Envoy asyncFetch/retryPolicy fields. |
| pkg/kgateway/translator/gateway/gateway_translator_test.go | Adds a translator golden test for remote JWKS async/retry. |
| pkg/kgateway/extensions2/plugins/trafficpolicy/jwt.go | Implements translation of asyncFetch and retryPolicy into Envoy JWT config. |
| pkg/kgateway/extensions2/plugins/trafficpolicy/jwt_test.go | Adds unit test coverage for translating async fetch + retry policy. |
| install/helm/kgateway-crds/templates/gateway.kgateway.dev_gatewayextensions.yaml | Exposes new fields in the Helm-rendered CRD schema. |
| api/v1alpha1/kgateway/jwt_types.go | Adds API types for async fetch and retry policy configuration. |
Files not reviewed (1)
- api/v1alpha1/kgateway/zz_generated.deepcopy.go: Language not supported
| s.TestInstallation.AssertionsT(s.T()).EventuallyHTTPRouteCondition( | ||
| s.Ctx, | ||
| "httpbin-route-get", | ||
| "kgateway-base", | ||
| gwv1.RouteConditionAccepted, | ||
| metav1.ConditionTrue, | ||
| ) |
There was a problem hiding this comment.
This mirrors the existing TestJwtAuthenticationRemote test, which uses the same single route readiness wait while asserting against both /get and /status/200. Both routes are created from the same manifest in the test setup, so by the time httpbin-route-get is Accepted, httpbin-route-status is effectively ready as well. Also the assertResponse/assertResponseWithoutAuth helpers send with retries, so a brief lag in route programming is absorbed rather than causing an immediate failure.
| // MaxInterval is the maximum interval between retries. If set, it must be greater than | ||
| // or equal to BaseInterval. Defaults to 10 times the BaseInterval. | ||
| // +optional | ||
| // +kubebuilder:validation:XValidation:rule="matches(self, '^([0-9]{1,5}(h|m|s|ms)){1,4}$')",message="invalid duration value" | ||
| MaxInterval *metav1.Duration `json:"maxInterval,omitempty"` |
| maxInterval: | ||
| description: |- | ||
| MaxInterval is the maximum interval between retries. If set, it must be greater than | ||
| or equal to BaseInterval. Defaults to 10 times the BaseInterval. | ||
| type: string | ||
| x-kubernetes-validations: | ||
| - message: invalid duration value | ||
| rule: matches(self, '^([0-9]{1,5}(h|m|s|ms)){1,4}$') |
| func translateJwksRetryPolicy(in *kgateway.JWKSRetryPolicy) *envoycorev3.RetryPolicy { | ||
| retryPolicy := &envoycorev3.RetryPolicy{} | ||
| if in.NumRetries != nil { | ||
| retryPolicy.NumRetries = wrapperspb.UInt32(uint32(*in.NumRetries)) //nolint:gosec // G115: kubebuilder validation ensures NumRetries is non-negative | ||
| } |
Signed-off-by: Lahiru De Silva <[email protected]>
Signed-off-by: Lahiru De Silva <[email protected]>
|
@andy-fong Updated the PR on main. |
Description
Currently kgateway fetches the remote JWKS synchronously during request time. If the cache expires and the JWKS server is unavailable when a request arrives, that request fails. This adds the option to fetch and cache the JWKS asynchronously, and a retry policy with exponential backoff, making JWT validation resilient to a slow or temporarily unavailable JWKS servers.
fixes #14054
Change Type
Changelog
Additional Notes
The E2E test (
TestJwtAuthenticationRemoteAsync) tests the full JWKS flow end to end withasyncFetchandretryPolicyconfigured. It does not assert the resilience behavior specific to async fetch/retry (e.g. serving from cache while the JWKS server is unavailable, or retrying a failed fetch), since reliably reproducing a JWKS outage and the timing dependent refetch/backoff windows in E2E is inherently flaky. The correctness of the translated Envoy config (asyncFetch,retryPolicy,cacheDuration) is covered by the translator golden test and unit tests.