In Service Mesh (ASM), you can configure JWT-based authentication to authenticate the source of HTTP requests for authorization. JWT is short for JSON Web Token. The JWT-based authentication feature can accurately verify the validity of the access token in a request header and allow only requests from trusted sources to access services. This improves service security and simplifies inter-service authentication.
Prerequisites
A Container Service for Kubernetes (ACK) cluster is added to an ASM instance and the version of the ASM instance is 1.6 or later.
Background information
Service Mesh supports the following authentication methods:
Transmission authentication: This method is based on Mutual Transport Layer Security (mTLS) and used to authenticate communications among services.
Source authentication: This method is based on JWT and used to authenticate requests from the client to the server.
JWT is a standard that uses representative claims to secure information transmission between two parties. For more information about JWT, see JWT documentation.
Step 1: Create a namespace and deploy sample services
Create a namespace named foo and set the label name to istio-injection and the value to enabled. For more information, see Manage global namespaces.
Create httpbin.yaml and sleep.yaml files with the following content:
Use kubectl to connect to the cluster and run the following commands to deploy the httpbin and sleep services in the foo namespace.
For more information about how to use kubectl to connect to the cluster, see Obtain the kubeconfig file of a cluster and use kubectl to connect to the cluster.
kubectl apply -f httpbin.yaml -n foo kubectl apply -f sleep.yaml -n foo
Use the sleep service to access the httpbin service.
Run the following command to enable bash for the sleep service:
kubectl exec -it deploy/sleep -- sh
Run the following command to send a request to the httpbin service:
curl -I httpbin.foo.svc.cluster.local:8000
Expected output:
HTTP/1.1 200 OK server: envoy date: Thu, 21 Dec 2023 07:39:55 GMT content-type: text/html; charset=utf-8 content-length: 9593 access-control-allow-origin: * access-control-allow-credentials: true x-envoy-upstream-service-time: 14
200 OK
is returned, indicating that the request is successful.
Step 2: Create a request authentication policy
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose . On the page that appears, click Create from YAML.
On the Create page, select foo from the Namespace drop-down list, enter the following content in the code editor to edit a YAML file for request authentication, and then click Create.
The
jwtRules
field in the following YAML code specifies a rule for the requests of thehttpbin
service. If a request header contains an access token, the decoded value of theiss
field must betesting@secure.istio.io
. Thejwks
field specifies how to generate the access token. For more information, see JSON Web Key (JWK).apiVersion: "security.istio.io/v1beta1" kind: "RequestAuthentication" metadata: name: "jwt-example" namespace: foo spec: selector: matchLabels: app: httpbin jwtRules: - issuer: "testing@secure.istio.io" jwks: '{ "keys":[ {"e":"AQAB","kid":"DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ","kty":"RSA","n":"xAE7eB6qugXyCAG3yhh7pkDkT65pHymX-P7KfIupjf59vsdo91bSP9C8H07pSAGQO1MV_xFj9VswgsCg4R6otmg5PV2He95lZdHtOcU5DXIg_pbhLdKXbi66GlVeK6ABZOUW3WYtnNHD-91gVuoeJT_DwtGGcp4ignkgXfkiEm4sw-4sfb4qdt5oLbyVpmW6x9cfa7vs2WTfURiCrBoUqgBo_-4WTiULmmHSGZHOjzwa8WtrtOQGsAFjIbno85jp6MnGGGZPYZbDAa_b3y5u-YpW7ypZrvD8BgtKVjgtQgZhLAGezMt0ua3DRrWnKqTZ0BJ_EyxOGuHJrLsn00fnMQ"}]}'
Decode the token.
The following code provides an example of the access token:
TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'
Run the following command to decode the token:
echo $TOKEN | cut -d '.' -f2 - | base64 --decode -
Expected output:
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
The JWT official website also provides a GUI for you to decode access tokens, as shown in the following figure.
Use the sleep service to access the httpbin service.
Run the following command to enable bash for the sleep service:
kubectl exec -it deploy/sleep -- sh
Run the following command to send a request to the httpbin service. The request header contains a valid access token.
Replace
your_valid_access_token_here
with the actual valid access token.TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
Expected output:
HTTP/1.1 200 OK
Run the following command to send a request to the httpbin service. The request header contains an invalid access token.
Replace
your_invalid_access_token_here
with an invalid access token.INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
401 Unauthorized
is returned, indicating that the request is denied by identity authentication and the access fails.
Step 3: Create a JWT authorization policy
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose . On the page that appears, click Create from YAML.
On the Create page, select foo from the Namespace drop-down list, enter the following content in the code editor to edit a YAML file for a JWT authorization policy, and then click Create.
The authorization policy implements the following logic: When a request is sent to the
httpbin
service, the system checks the decoded access token in the request header. The request is allowed only if the values of theiss
andsub
fields in the decoded access token are the same as those specified by thesource.requestPrincipals
field. The source.requestPrincipals field is in the format ofiss/sub
. In this example, the value of thesource.requestPrincipals
field istesting@secure.istio.io/testing@secure.istio.io
.apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: require-jwt namespace: foo spec: selector: matchLabels: app: httpbin action: ALLOW rules: - from: - source: requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"]
Decode the token.
The following code provides an example of the access token:
TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'
Run the following command to decode the token:
echo $TOKEN | cut -d '.' -f2 - | base64 --decode -
Expected output:
{"exp":4685989700,"foo":"bar","iat":1532389700,"iss":"testing@secure.istio.io","sub":"testing@secure.istio.io"}
Use the sleep service to access the httpbin service.
Run the following command to enable bash for the sleep service:
kubectl exec -it deploy/sleep -- sh
Run the following command to send a request to the httpbin service. The request header contains a valid access token.
Replace
your_valid_access_token_here
with the actual valid access token.TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
Expected output:
HTTP/1.1 200 OK
Run the following command to send a request to the httpbin service. The request header contains an invalid access token.
Replace
your_invalid_access_token_here
with an invalid access token.INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
403 Forbidden
is returned, indicating that the request is denied by the authorization policy and the access fails.
Step 4: Update the JWT authorization policy
Log on to the ASM console. In the left-side navigation pane, choose .
On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose .
On the AuthorizationPolicy page, find the require-jwt policy and click YAML in the Actions column.
In the Edit dialog box, add the following content and click OK.
when: - key: request.auth.claims[groups] values: ["group1"]
The following code provides an example of a complete YAML file. When a request is sent to the
httpbin
service, the system checks the decoded access token in the request header. Then, the system applies the updated authorization policy to the request. The request is allowed only if the decoded access token meets the following conditions: The value of the iss field is testing@secure.istio.io, the value of the sub field is testing@secure.istio.io, and thegroups
field containsgroup1
.apiVersion: security.istio.io/v1beta1 kind: AuthorizationPolicy metadata: name: require-jwt namespace: foo spec: selector: matchLabels: app: httpbin action: ALLOW rules: - from: - source: requestPrincipals: ["testing@secure.istio.io/testing@secure.istio.io"] when: - key: request.auth.claims[groups] values: ["group1"]
Decode the token.
The following code provides an example of the access token:
TOKEN_GROUP='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjM1MzczOTExMDQsImdyb3VwcyI6WyJncm91cDEiLCJncm91cDIiXSwiaWF0IjoxNTM3MzkxMTA0LCJpc3MiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyIsInNjb3BlIjpbInNjb3BlMSIsInNjb3BlMiJdLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.EdJnEZSH6X8hcyEii7c8H5lnhgjB5dwo07M5oheC8Xz8mOllyg--AHCFWHybM48reunF--oGaG6IXVngCEpVF0_P5DwsUoBgpPmK1JOaKN6_pe9sh0ZwTtdgK_RP01PuI7kUdbOTlkuUi2AO-qUyOm7Art2POzo36DLQlUXv8Ad7NBOqfQaKjE9ndaPWT7aexUsBHxmgiGbz1SyLH879f7uHYPbPKlpHU6P9S-DaKnGLaEchnoKnov7ajhrEhGXAQRukhDPKUHO9L30oPIr5IJllEQfHYtt6IZvlNUGeLUcif3wpry1R5tBXRicx2sXMQ7LyuDremDbcNy_iE76Upg'
Run the following command to decode the token:
echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode - | jq
Expected output:
{ "exp": 3537391104, "groups": [ "group1", "group2" ], "iat": 1537391104, "iss": "testing@secure.istio.io", "scope": [ "scope1", "scope2" ], "sub": "testing@secure.istio.io" }
Use the sleep service to access the httpbin service.
Run the following command to enable bash for the sleep service:
kubectl exec -it deploy/sleep -- sh
Run the following command to send a request to the httpbin service. The request header contains a valid access token.
Replace
your_valid_access_token_here
with the actual valid access token.TOKEN=your_valid_access_token_here curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000
200 OK
is returned, indicating that the request passes the authentication required by the authorization policy and the access is successful.Run the following command to send a request to the httpbin service. The request header contains an invalid access token.
Replace
your_invalid_access_token_here
with an invalid access token.INVALID_TOKEN=your_invalid_access_token_here curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000
403 Forbidden
is returned, indicating that the request is denied by the authorization policy and the access fails.
References
For more information about the JWT algorithms supported by ASM, how to use JwksUri, and how to configure specific paths to bypass JWT authentication, see FAQ about JWT.