This topic answers frequently asked questions about JSON Web Token (JWT) authentication in Service Mesh (ASM).
How JWT authentication works in ASM
ASM uses two Istio resources to enforce JWT authentication:
| Resource | Role | Behavior when used alone |
|---|---|---|
| RequestAuthentication | Defines how to validate JWTs: issuer, JSON Web Key Set (JWKS) source, and algorithms | Rejects requests with invalid tokens, but allows requests with no token |
| AuthorizationPolicy | Defines where to enforce authentication and who must authenticate | Controls which requests require a valid JWT |
To require valid JWTs on every request, pair a RequestAuthentication with an AuthorizationPolicy. A RequestAuthentication alone does not block unauthenticated requests.
What JWT algorithms does ASM support?
Algorithm support depends on your ASM version:
| ASM version | Supported algorithms |
|---|---|
| Earlier than v1.13 | RSA only |
| v1.13 or later | ES256, ES384, ES512, HS256, HS384, HS512, RS256, RS384, RS512, PS256, PS384, PS512, EdDSA |
How do I use the jwksUri parameter?
The jwksUri parameter is available in ASM v1.13 or later. Configuration depends on where your JWKS endpoint is hosted:
| JWKS endpoint location | Configuration |
|---|---|
| In-cluster service (deployed in an ACK cluster managed by ASM) | Use jwksUri directly |
| External service (outside the managed ACK cluster) | Create a ServiceEntry first, then reference the endpoint in jwksUri |
The examples below use the sample JWT and sample JWKS from Istio.
JWKS endpoint in the managed ACK cluster
In this example, the nginx-proxy service serves JWKS public keys on port 80 at the /get_jwks path. The full jwksUri value is http://nginx-proxy.{Namespace}.svc.cluster.local:80/get_jwks.
-
Verify that the JWKS endpoint is reachable:
curl nginx-proxy/get_jwksExpected output:
{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65p****-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYt****-91gVuoeJT_DwtGGcp4ignkgXfkiE****-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]}A valid JWKS JSON response confirms the endpoint is reachable.
-
Create a RequestAuthentication policy.
-
Log on to the ASM console.
-
On the Mesh Management page, find the target ASM instance and click its name, or click Manage in the Actions column.
-
On the RequestAuthentication page, click Create from YAML. Select the target Namespace and a Template, paste the following YAML, and click Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: testing@secure.istio.io jwksUri: 'http://nginx-proxy/get_jwks' selector: matchLabels: app: httpbin
-
-
Verify the configuration by sending a request with a valid JWT.
Use kubectl with the kubeconfig file for the data plane cluster to run:
# Set the Token environment variable. TOKEN=$(curl https://raw.githubusercontent.com/istio/istio/release-1.14/security/tools/jwt/samples/demo.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode - # Send a request with the JWT from the sleep pod to the httpbin service. kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"A
200status code confirms that JWT authentication is working.
JWKS endpoint outside the managed ACK cluster
When the JWKS endpoint is external to your managed ACK cluster, create a ServiceEntry so that the mesh can reach it. This example uses HTTP. To use HTTPS, also create a DestinationRule for TLS origination.
-
Create a ServiceEntry for the external JWKS endpoint.
-
Create a file named service-entry.yaml with the following content:
apiVersion: networking.istio.io/v1beta1 kind: ServiceEntry metadata: name: external-svc-https namespace: foo spec: addresses: - 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. endpoints: - address: 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. hosts: - 11.11.XX.XX # Replace with the IP address of your JWKS endpoint. location: MESH_EXTERNAL ports: - name: http number: 80 protocol: HTTP - name: https number: 443 protocol: HTTPS resolution: STATIC -
Apply the ServiceEntry:
kubectl apply -f service-entry.yaml
-
-
(Optional) To fetch JWKS over HTTPS, create a DestinationRule for TLS origination:
apiVersion: networking.istio.io/v1beta1 kind: DestinationRule metadata: name: external-svc-https namespace: foo spec: host: <service-entry-host> trafficPolicy: loadBalancer: simple: ROUND_ROBIN portLevelSettings: - port: number: 443 tls: mode: SIMPLE -
Create a RequestAuthentication policy.
-
Log on to the ASM console.
-
On the Mesh Management page, find the target ASM instance and click its name, or click Manage in the Actions column.
-
On the RequestAuthentication page, click Create from YAML. Select the target Namespace and a Template, paste the following YAML, and click Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: foo spec: jwtRules: - issuer: tes****@secure.istio.io jwksUri: '<your-jwks-uri>' selector: matchLabels: app: httpbin
-
-
Verify the configuration by sending a request with a valid JWT from the sleep pod:
# Send a request with the JWT from the sleep pod to the httpbin service. kubectl exec "$(kubectl get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})" -c sleep -n foo -- curl "http://httpbin.foo:8000/headers" -sS -o /dev/null -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n"A
200status code confirms that JWT authentication is working.
How do I skip JWT authentication for specific paths?
Use an AuthorizationPolicy with action: DENY to block unauthenticated requests on most paths while allowing certain paths through without a token.
How the double-negation pattern works: The policy denies requests that have no valid JWT (notRequestPrincipals: '*') unless they target an excluded path (notPaths). In plain language: "Deny any request that lacks valid JWT credentials, except requests to the excluded path."
This combination of notRequestPrincipals and notPaths forms a double-negation:
| Condition | Request has valid JWT | Request has no JWT |
|---|---|---|
Path is /productpage (excluded) |
Allowed | Allowed (path is excluded from the DENY rule) |
| Path is anything else | Allowed | Denied (caught by the DENY rule) |
This example uses the Bookinfo sample application and excludes the /productpage path from JWT authentication while requiring valid JWTs for all other paths.
-
Deploy the sample application and verify access.
-
Deploy the Bookinfo application in the ACK cluster added to your ASM instance. For more information, see Deploy an application in an ACK cluster that is added to an ASM instance.
-
Verify that all paths are accessible:
curl "http://<ingress-gateway-ip>/productpage" -sS -o /dev/null -w "%{http_code}\n" curl "http://<ingress-gateway-ip>/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" curl "http://<ingress-gateway-ip>/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n"All three commands should return
200.
-
-
Create a RequestAuthentication policy on the ingress gateway.
This policy validates JWTs on all requests that pass through the gateway. Requests with valid JWTs or no JWT are allowed. Requests with invalid JWTs are rejected.
-
Log on to the ASM console.
-
On the Mesh Management page, find the target ASM instance and click its name, or click Manage in the Actions column.
-
On the RequestAuthentication page, click Create from YAML. Select the target Namespace and a Template, paste the following YAML, and click Create.
apiVersion: security.istio.io/v1beta1 kind: RequestAuthentication metadata: name: jwt-example namespace: istio-system spec: jwtRules: - issuer: testing@secure.istio.io jwks: >- { "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-e****","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQ****_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5****_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVu****_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoU****_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZ****_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqT****_EyxOGuHJrLsn00****"}]} selector: matchLabels: app: istio-ingressgateway
-
-
Create an AuthorizationPolicy to exempt /productpage from JWT authentication.
This policy denies requests that lack a valid JWT unless the request targets /productpage. Requests to all other paths must carry a valid JWT.
-
Log on to the ASM console.
-
On the Mesh Management page, find the target ASM instance and click its name, or click Manage in the Actions column.
-
On the AuthorizationPolicy page, click Create from YAML. Select the target Namespace and a Template, paste the following YAML, and click Create.
apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: test-exclude namespace: istio-system spec: action: DENY rules: - from: - source: notRequestPrincipals: - '*' to: - operation: notPaths: - /productpage selector: matchLabels: app: istio-ingressgateway
-
-
Test the results.
-
Set the JWT token:
export TOKEN=eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1****.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5p****.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9****-LS9qd_vpdLG4Tn1A15NxfCjp5f7Q****-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZz****__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCg****_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3UcMI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvH****_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8**** -
Send requests without a JWT:
curl "http://<ingress-gateway-ip>/productpage" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 curl "http://<ingress-gateway-ip>/api/v1/products/0" -sS -o /dev/null -w "%{http_code}\n" # Expected: 403 curl "http://<ingress-gateway-ip>/api/v1/products/1" -sS -o /dev/null -w "%{http_code}\n" # Expected: 403Only /productpage returns
200. The other paths return403because they require a valid JWT. -
Send requests with a valid JWT:
curl "http://<ingress-gateway-ip>/productpage" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 curl "http://<ingress-gateway-ip>/api/v1/products/0" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200 curl "http://<ingress-gateway-ip>/api/v1/products/1" -H "Authorization: Bearer $TOKEN" -sS -o /dev/null -w "%{http_code}\n" # Expected: 200All three paths return
200, confirming that valid JWTs grant access to every path.
-