diff --git a/api/v1alpha1/jwt_types.go b/api/v1alpha1/jwt_types.go index 2666d56d03e..823192ad4a1 100644 --- a/api/v1alpha1/jwt_types.go +++ b/api/v1alpha1/jwt_types.go @@ -5,7 +5,9 @@ package v1alpha1 -import gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" +import ( + gwapiv1 "sigs.k8s.io/gateway-api/apis/v1" +) // JWT defines the configuration for JSON Web Token (JWT) authentication. type JWT struct { @@ -108,6 +110,11 @@ type RemoteJWKS struct { // +kubebuilder:validation:MinLength=1 // +kubebuilder:validation:MaxLength=253 URI string `json:"uri"` + // Duration after which the cached JWKS should be expired. If not specified, default cache duration is 5 minutes. + + // +kubebuilder:default="300s" + // +optional + CacheDuration *gwapiv1.Duration `json:"cacheDuration,omitempty"` } // LocalJWKSType defines the types of values for Local JWKS. diff --git a/api/v1alpha1/zz_generated.deepcopy.go b/api/v1alpha1/zz_generated.deepcopy.go index 866269c9ac4..9884d1df791 100644 --- a/api/v1alpha1/zz_generated.deepcopy.go +++ b/api/v1alpha1/zz_generated.deepcopy.go @@ -6035,6 +6035,11 @@ func (in *RedisTLSSettings) DeepCopy() *RedisTLSSettings { func (in *RemoteJWKS) DeepCopyInto(out *RemoteJWKS) { *out = *in in.BackendCluster.DeepCopyInto(&out.BackendCluster) + if in.CacheDuration != nil { + in, out := &in.CacheDuration, &out.CacheDuration + *out = new(v1.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteJWKS. diff --git a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml index 75f89017c0f..ed62618c366 100644 --- a/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-crds-helm/templates/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3761,6 +3761,13 @@ spec: type: object type: object type: object + cacheDuration: + default: 300s + description: |- + Duration is a string value representing a duration in time. The format is as specified + in GEP-2257, a strict subset of the syntax parsed by Golang time.ParseDuration. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string uri: description: |- URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate. diff --git a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml index 5162de0c355..2a5654e444f 100644 --- a/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml +++ b/charts/gateway-helm/crds/generated/gateway.envoyproxy.io_securitypolicies.yaml @@ -3760,6 +3760,13 @@ spec: type: object type: object type: object + cacheDuration: + default: 300s + description: |- + Duration is a string value representing a duration in time. The format is as specified + in GEP-2257, a strict subset of the syntax parsed by Golang time.ParseDuration. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string uri: description: |- URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate. diff --git a/examples/kubernetes/jwt/jwt.yaml b/examples/kubernetes/jwt/jwt.yaml index 46381b13a2f..a5ba7f4c100 100644 --- a/examples/kubernetes/jwt/jwt.yaml +++ b/examples/kubernetes/jwt/jwt.yaml @@ -12,6 +12,7 @@ spec: - name: example remoteJWKS: uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/jwt/jwks.json + cacheDuration: 60s --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml b/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml index cef3ccc5383..c3555103dfb 100644 --- a/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml +++ b/internal/cmd/egctl/testdata/translate/in/jwt-single-route-single-match-to-xds.yaml @@ -84,6 +84,7 @@ spec: - name: example remoteJWKS: uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/jwt/jwks.json + cacheDuration: 300s --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/internal/gatewayapi/resource/testdata/all-resources.out.yaml b/internal/gatewayapi/resource/testdata/all-resources.out.yaml index b6295104056..f70580f5ddf 100644 --- a/internal/gatewayapi/resource/testdata/all-resources.out.yaml +++ b/internal/gatewayapi/resource/testdata/all-resources.out.yaml @@ -383,6 +383,7 @@ securityPolicies: providers: - name: example remoteJWKS: + cacheDuration: 300s uri: https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/jwt/jwks.json targetRef: group: gateway.networking.k8s.io diff --git a/internal/gatewayapi/securitypolicy.go b/internal/gatewayapi/securitypolicy.go index b2930b27016..f12709d57ce 100644 --- a/internal/gatewayapi/securitypolicy.go +++ b/internal/gatewayapi/securitypolicy.go @@ -1007,10 +1007,11 @@ func (t *Translator) buildRemoteJWKS( envoyProxy *egv1a1.EnvoyProxy, ) (*ir.RemoteJWKS, error) { var ( - protocol ir.AppProtocol - rd *ir.RouteDestination - traffic *ir.TrafficFeatures - err error + protocol ir.AppProtocol + rd *ir.RouteDestination + traffic *ir.TrafficFeatures + err error + cacheDuration *metav1.Duration ) u, err := url.Parse(remoteJWKS.URI) @@ -1037,10 +1038,19 @@ func (t *Translator) buildRemoteJWKS( } } + if remoteJWKS.CacheDuration != nil { + d, err := time.ParseDuration(string(*remoteJWKS.CacheDuration)) + if err != nil { + return nil, err + } + cacheDuration = ir.MetaV1DurationPtr(d) + } + return &ir.RemoteJWKS{ - Destination: rd, - Traffic: traffic, - URI: remoteJWKS.URI, + Destination: rd, + Traffic: traffic, + URI: remoteJWKS.URI, + CacheDuration: cacheDuration, }, nil } diff --git a/internal/ir/xds.go b/internal/ir/xds.go index da5b2510e0a..bd333839ea0 100644 --- a/internal/ir/xds.go +++ b/internal/ir/xds.go @@ -1077,6 +1077,9 @@ type RemoteJWKS struct { // URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate. // If a custom trust bundle is needed, it can be specified in a BackendTLSConfig resource and target the BackendRefs. URI string `json:"uri"` + + // Duration after which the cached JWKS should be expired. If not specified, default cache duration is 5 minutes. + CacheDuration *metav1.Duration `json:"cacheDuration,omitempty"` } // OIDC defines the schema for authenticating HTTP requests using diff --git a/internal/ir/zz_generated.deepcopy.go b/internal/ir/zz_generated.deepcopy.go index dadc7e7b7ee..5ae55046a97 100644 --- a/internal/ir/zz_generated.deepcopy.go +++ b/internal/ir/zz_generated.deepcopy.go @@ -3140,6 +3140,11 @@ func (in *RemoteJWKS) DeepCopyInto(out *RemoteJWKS) { *out = new(TrafficFeatures) (*in).DeepCopyInto(*out) } + if in.CacheDuration != nil { + in, out := &in.CacheDuration, &out.CacheDuration + *out = new(v1.Duration) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new RemoteJWKS. diff --git a/internal/xds/translator/jwt.go b/internal/xds/translator/jwt.go index 8803b052994..423e31f1d67 100644 --- a/internal/xds/translator/jwt.go +++ b/internal/xds/translator/jwt.go @@ -8,7 +8,6 @@ package translator import ( "errors" "fmt" - "time" corev3 "github.com/envoyproxy/go-control-plane/envoy/config/core/v3" routev3 "github.com/envoyproxy/go-control-plane/envoy/config/route/v3" @@ -159,11 +158,13 @@ func buildJWTAuthn(irListener *ir.HTTPListener) (*jwtauthnv3.JwtAuthentication, }, Timeout: durationpb.New(defaultExtServiceRequestTimeout), }, - CacheDuration: durationpb.New(5 * time.Minute), - AsyncFetch: &jwtauthnv3.JwksAsyncFetch{}, + + AsyncFetch: &jwtauthnv3.JwksAsyncFetch{}, }, } - + if jwks.CacheDuration != nil { + remote.RemoteJwks.CacheDuration = durationpb.New(jwks.CacheDuration.Duration) + } // Set the retry policy if it exists. if jwks.Traffic != nil && jwks.Traffic.Retry != nil { var rp *corev3.RetryPolicy diff --git a/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-claim.yaml b/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-claim.yaml index 321ad85efae..d2a6caf0233 100644 --- a/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-claim.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-claim.yaml @@ -55,6 +55,7 @@ http: name: example1 remoteJWKS: uri: https://two.example.com/jwt/public-key/jwks.json + cacheDuration: 300s - destination: name: httproute/default/httproute-2/rule/0 settings: @@ -99,3 +100,5 @@ http: name: example1 remoteJWKS: uri: https://one.example.com/jwt/public-key/jwks.json + cacheDuration: 300s + diff --git a/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-scope.yaml b/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-scope.yaml index 95ffc4a947f..df3d838fbd0 100644 --- a/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-scope.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/authorization-jwt-scope.yaml @@ -55,6 +55,7 @@ http: name: example1 remoteJWKS: uri: https://two.example.com/jwt/public-key/jwks.json + cacheDuration: 300s - destination: name: httproute/default/httproute-2/rule/0 settings: @@ -95,3 +96,5 @@ http: name: example1 remoteJWKS: uri: https://one.example.com/jwt/public-key/jwks.json + cacheDuration: 300s + diff --git a/internal/xds/translator/testdata/in/xds-ir/custom-filter-order.yaml b/internal/xds/translator/testdata/in/xds-ir/custom-filter-order.yaml index 4971328e8cb..7f224f4f1b9 100644 --- a/internal/xds/translator/testdata/in/xds-ir/custom-filter-order.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/custom-filter-order.yaml @@ -52,6 +52,7 @@ http: name: example1 remoteJWKS: uri: https://one.example.com/jwt/public-key/jwks.json + cacheDuration: 300s - audiences: - two.foo.com claimToHeaders: @@ -61,6 +62,7 @@ http: name: example2 remoteJWKS: uri: http://two.example.com/jwt/public-key/jwks.json + cacheDuration: 300s envoyExtensions: wasms: - config: diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-custom-extractor.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-custom-extractor.yaml index 66fc43f92c0..07e8fdd38da 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-custom-extractor.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-custom-extractor.yaml @@ -21,6 +21,7 @@ http: - foo.com remoteJWKS: uri: https://localhost/jwt/public-key/jwks.json + cacheDuration: 300s extractFrom: cookies: - session_access_token diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml index f2ebba7af4c..e1ae6a5670b 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-multi-provider.yaml @@ -21,6 +21,7 @@ http: - foo.com remoteJWKS: uri: http://localhost/jwt/public-key/jwks.json + cacheDuration: 300s claimToHeaders: - header: one-route-example-key1 claim: claim.neteased.key @@ -64,6 +65,7 @@ http: - foo.com remoteJWKS: uri: http://localhost/jwt/public-key/jwks.json + cacheDuration: 300s claimToHeaders: - header: second-route-example-key1 claim: claim.neteased.key @@ -74,6 +76,7 @@ http: - two.foo.com remoteJWKS: uri: https://192.168.1.250:8080/jwt/public-key/jwks.json + cacheDuration: 300s destination: name: "second-route-www.test.com-dest" settings: diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml index 4944995ad26..6e9de3de4eb 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-multi-route-single-provider.yaml @@ -26,6 +26,7 @@ http: - foo.com remoteJWKS: uri: https://localhost/jwt/public-key/jwks.json + cacheDuration: 300s claimToHeaders: - header: first-route-key claim: claim.neteased.key @@ -49,6 +50,7 @@ http: - foo.com remoteJWKS: uri: https://localhost/jwt/public-key/jwks.json + cacheDuration: 300s destination: name: "second-route-dest" settings: diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-optional.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-optional.yaml index 18baee23cf7..0eb580353c0 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-optional.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-optional.yaml @@ -21,6 +21,7 @@ http: - foo.com remoteJWKS: uri: https://localhost/jwt/public-key/jwks.json + cacheDuration: 300s extractFrom: cookies: - session_access_token diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml index b84df0fb045..3c69d1ac825 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-ratelimit.yaml @@ -43,6 +43,7 @@ http: - foo.com remoteJWKS: uri: https://192.168.1.250/jwt/public-key/jwks.json + cacheDuration: 300s - name: "second-route" hostname: "*" traffic: diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml index efa91fec853..2094b3ac5b5 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-single-route-single-match.yaml @@ -21,6 +21,7 @@ http: - foo.com remoteJWKS: uri: https://localhost/jwt/public-key/jwks.json + cacheDuration: 300s destination: name: "first-route-dest" settings: diff --git a/internal/xds/translator/testdata/in/xds-ir/jwt-with-backend-tls-retry.yaml b/internal/xds/translator/testdata/in/xds-ir/jwt-with-backend-tls-retry.yaml index f1ba24346d3..ca4e8e284e4 100644 --- a/internal/xds/translator/testdata/in/xds-ir/jwt-with-backend-tls-retry.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/jwt-with-backend-tls-retry.yaml @@ -75,3 +75,4 @@ http: - gateway-error - reset uri: https://foo.bar.com/jwt/public-key/jwks.json + cacheDuration: 300s diff --git a/internal/xds/translator/testdata/in/xds-ir/oidc-and-jwt-with-passthrough.yaml b/internal/xds/translator/testdata/in/xds-ir/oidc-and-jwt-with-passthrough.yaml index 4cddbaafd21..b93364c1002 100644 --- a/internal/xds/translator/testdata/in/xds-ir/oidc-and-jwt-with-passthrough.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/oidc-and-jwt-with-passthrough.yaml @@ -28,6 +28,7 @@ http: name: example1 remoteJWKS: uri: https://oauth.foo.com/jwt/public-key/jwks.json + cacheDuration: 300s - issuer: https://oauth.foo.com name: example2 extractFrom: @@ -37,6 +38,7 @@ http: - name: MyHeaderNoPrefix remoteJWKS: uri: https://oauth.foo.com/jwt/public-key/jwks.json + cacheDuration: 300s - issuer: https://oauth.foo.com name: example3 extractFrom: @@ -45,6 +47,7 @@ http: - Cookie1 remoteJWKS: uri: https://oauth.foo.com/jwt/public-key/jwks.json + cacheDuration: 300s - issuer: https://oauth.foo.com name: example4 extractFrom: @@ -53,6 +56,7 @@ http: - Param1 remoteJWKS: uri: https://oauth.foo.com/jwt/public-key/jwks.json + cacheDuration: 300s oidc: clientID: client.oauth.foo.com clientSecret: Y2xpZW50MTpzZWNyZXQK diff --git a/internal/xds/translator/testdata/in/xds-ir/securitypolicy-with-oidc-jwt-authz.yaml b/internal/xds/translator/testdata/in/xds-ir/securitypolicy-with-oidc-jwt-authz.yaml index f3e83993844..a9352668db6 100644 --- a/internal/xds/translator/testdata/in/xds-ir/securitypolicy-with-oidc-jwt-authz.yaml +++ b/internal/xds/translator/testdata/in/xds-ir/securitypolicy-with-oidc-jwt-authz.yaml @@ -61,6 +61,7 @@ http: name: exjwt remoteJWKS: uri: https://oidc.example.com/auth/realms/example/protocol/openid-connect/certs + cacheDuration: 300s oidc: clientID: prometheus clientSecret: '[redacted]' diff --git a/release-notes/current.yaml b/release-notes/current.yaml index b9134cd1276..aa9e22b35e0 100644 --- a/release-notes/current.yaml +++ b/release-notes/current.yaml @@ -13,6 +13,7 @@ new features: | Added support for RetryPolicy in gRPC ExtAuth callouts via SecurityPolicy backend settings fields. Added support for late response headers in ClientTrafficPolicy. Added max connection/stream duration and max requests per connection to ClientTrafficPolicy. + Added cacheDuration for remoteJWKS in SecurityPolicy. bug fixes: | Fixed %ROUTE_KIND% operator to be lower-cased when used by clusterStatName in EnvoyProxy API. diff --git a/site/content/en/latest/api/extension_types.md b/site/content/en/latest/api/extension_types.md index 070d62c4d77..113e45648a7 100644 --- a/site/content/en/latest/api/extension_types.md +++ b/site/content/en/latest/api/extension_types.md @@ -4370,6 +4370,7 @@ _Appears in:_ | `backendRefs` | _[BackendRef](#backendref) array_ | false | | BackendRefs references a Kubernetes object that represents the
backend server to which the authorization request will be sent. | | `backendSettings` | _[ClusterSettings](#clustersettings)_ | false | | BackendSettings holds configuration for managing the connection
to the backend. | | `uri` | _string_ | true | | URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate.
If a custom trust bundle is needed, it can be specified in a BackendTLSConfig resource and target the BackendRefs. | +| `cacheDuration` | _[Duration](https://gateway-api.sigs.k8s.io/reference/spec/#gateway.networking.k8s.io/v1.Duration)_ | false | 300s | | #### ReplaceRegexMatch diff --git a/test/e2e/testdata/jwt-backend-remote-jwks.yaml b/test/e2e/testdata/jwt-backend-remote-jwks.yaml index 17c335df424..816541ac28c 100644 --- a/test/e2e/testdata/jwt-backend-remote-jwks.yaml +++ b/test/e2e/testdata/jwt-backend-remote-jwks.yaml @@ -152,6 +152,7 @@ spec: retryOn: triggers: ["5xx", "gateway-error", "reset"] uri: https://remote-jwks-server.gateway-conformance-infra/jwt/jwks.json + cacheDuration: 300s --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/test/e2e/testdata/jwt.yaml b/test/e2e/testdata/jwt.yaml index 32b1d96dcc0..46e10602ea6 100644 --- a/test/e2e/testdata/jwt.yaml +++ b/test/e2e/testdata/jwt.yaml @@ -21,6 +21,7 @@ spec: header: x-name remoteJWKS: uri: http://static-file-server.gateway-conformance-infra/jwt/jwks.json + cacheDuration: 300s --- apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute diff --git a/test/e2e/testdata/oidc-securitypolicy.yaml b/test/e2e/testdata/oidc-securitypolicy.yaml index 37aaafcdd58..4477fd73997 100644 --- a/test/e2e/testdata/oidc-securitypolicy.yaml +++ b/test/e2e/testdata/oidc-securitypolicy.yaml @@ -85,6 +85,8 @@ spec: - name: "keycloak" # This is needed so JWTs generated through the OIDC flow can be validated remoteJWKS: uri: "http://keycloak.gateway-conformance-infra/realms/master/protocol/openid-connect/certs" + cacheDuration: 300s - name: "example" # This allows us to use the static JWTs in the test remoteJWKS: uri: "http://static-file-server.gateway-conformance-infra/jwt/jwks.json" + cacheDuration: 300s diff --git a/test/helm/gateway-crds-helm/all.out.yaml b/test/helm/gateway-crds-helm/all.out.yaml index 518673af369..4ec1931a61a 100644 --- a/test/helm/gateway-crds-helm/all.out.yaml +++ b/test/helm/gateway-crds-helm/all.out.yaml @@ -43575,6 +43575,13 @@ spec: type: object type: object type: object + cacheDuration: + default: 300s + description: |- + Duration is a string value representing a duration in time. The format is as specified + in GEP-2257, a strict subset of the syntax parsed by Golang time.ParseDuration. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string uri: description: |- URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate. diff --git a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml index a3477928410..8875240ca3e 100644 --- a/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml +++ b/test/helm/gateway-crds-helm/envoy-gateway-crds.out.yaml @@ -26263,6 +26263,13 @@ spec: type: object type: object type: object + cacheDuration: + default: 300s + description: |- + Duration is a string value representing a duration in time. The format is as specified + in GEP-2257, a strict subset of the syntax parsed by Golang time.ParseDuration. + pattern: ^([0-9]{1,5}(h|m|s|ms)){1,4}$ + type: string uri: description: |- URI is the HTTPS URI to fetch the JWKS. Envoy's system trust bundle is used to validate the server certificate.