In Alibaba Cloud Service Mesh (ASM), you can configure JSON Web Token (JWT) authorization
to authenticate the source of requests. This method is also called end-user authentication.
When an application in an ASM instance configured with a JWT authorization policy
receives a request, the system checks whether the request header contains a valid
JWT. Only requests with valid JWTs are allowed. This topic describes how to configure
a JWT authorization policy for an ASM instance.
Prerequisites
- An ASM instance is created, and a Container Service for Kubernetes (ACK) cluster is
added to the instance. For more information, see Add a cluster to an ASM instance.
- The Istio version of your ASM instance is 1.6 or later. Otherwise, the RequestAuthentication
feature is not supported.
Background information
ASM 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 parties. It is used to authenticate the source of requests. For more information
about JWT, see JWT official documentation.
Step 1: Deploy sample services
- Log on to the ASM console.
- In the left-side navigation pane, choose .
- On the Mesh Management page, find the ASM instance that you want to configure. Click the name of the ASM
instance or click Manage in the Actions column.
- On the details page of the ASM instance, choose in the left-side navigation pane. On the Global Namespace page, click Create.
- In the Create Namespace panel, set the Name and Labels parameters. In this example, set the Name parameter to
foo
and add the istio-injection:enabled
label. The settings are used to create a namespace named foo
with automatic sidecar injection
enabled.
- Click OK. The
foo
namespace is created.
- Run the following commands to deploy the official sample services
httpbin
and sleep
: kubectl \
--kubeconfig "$USER_CONFIG" \
-n foo \
apply -f "$ISTIO_HOME"/samples/httpbin/httpbin.yaml
kubectl \
--kubeconfig "$USER_CONFIG" \
-n foo \
apply -f "$ISTIO_HOME"/samples/sleep/sleep.yaml
- Run the following commands to keep the system waiting until the pods of the httpbin
and sleep services get ready:
kubectl --kubeconfig "$USER_CONFIG" -n foo get po
kubectl --kubeconfig "$USER_CONFIG" -n foo wait --for=condition=ready pod -l app=httpbin
kubectl --kubeconfig "$USER_CONFIG" -n foo wait --for=condition=ready pod -l app=sleep
Result:In the pod of the sleep
service, edit the YAML file of the ACK cluster to check whether requests can be sent
to the httpbin
service. If HTTP status code 200 is returned, requests can be sent to the httpbin
service.
sleep_pod=$(kubectl --kubeconfig "$USER_CONFIG" get pod -l app=sleep -n foo -o jsonpath={.items..metadata.name})
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" -c sleep -n foo -- curl http://httpbin.foo:8000/ip -s -o /dev/null -w "%{http_code}")
if [[ $RESULT != "200" ]]; then
echo "http_code($RESULT) should be 200"
exit
fi
Step 2: Create a request authentication policy
- On the details page of the ASM instance, choose in the left-side navigation pane. On the RequestAuthentication page, click Create from YAML.
- On the Create page, select foo from the Namespace drop-down list, and enter the following content in the code editor to edit a YAML
file for a request authentication policy.
The following code provides an example of the content for the jwt-example.yaml file:
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"}]}'
Note
The jwtRules
field in the preceding YAML code specifies a rule for the requests of the httpbin
service. If the request header contains an access token, the decoded value of the
iss
field must be testing@secure.istio.io
. The jwks
field specifies how to generate the access token. For more information, see JSON Web Key (JWK).
- Click Create.
Result:If the request header contains a valid access token, HTTP status code 200 is returned.
Otherwise, HTTP status code 401 is returned.
- Use the following code to determine when to return HTTP status code 200:
for ((i = 1; i <= 10; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-w "%{http_code}")
if [[ $RESULT != "200" ]]; then
echo "http_code($RESULT) should be 200"
exit
fi
done
- Use the following code to determine when to return HTTP status code 401:
for ((i = 1; i <= 5; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-H "Authorization: Bearer invalidToken" \
-w "%{http_code}")
if [[ $RESULT != "401" ]]; then
echo "http_code($RESULT) should be 401"
exit
fi
done
Step 3: Create a JWT authorization policy
- On the details page of the ASM instance, choose in the left-side navigation pane. On the AuthorizationPolicy page, click Create from YAML.
- On the Create page, select foo from the Namespace drop-down list, and enter the following content in the code editor to edit a YAML
file for a JWT authorization policy.
The following code provides an example of the content for the require-jwt.yaml file:
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"]
Note
The preceding 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 the iss
and sub
fields in the decoded access token are the same as those specified by the source.requestPrincipals
field. The source.requestPrincipals field is in the format of iss/sub
. In this example, the value of the source.requestPrincipals
field is testing@secure.istio.io/testing@secure.istio.io
.
- 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 access token:
echo $TOKEN | cut -d '.' -f2 - | base64 --decode -
- The following output shows the decoded value of the sample access token:
null
The JWT official website also provides a GUI for you to decode access tokens, as shown
in the following figure.

- Click Create.
Result:If the request header contains a valid access token, HTTP status code 200 is returned.
Otherwise, HTTP status code 403 is returned.
- Use the following code to determine when to return HTTP status code 200:
for ((i = 1; i <= 10; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-H "Authorization: Bearer $TOKEN" \
-w "%{http_code}")
if [[ $RESULT != "200" ]]; then
echo "http_code($RESULT) should be 200"
exit
fi
done
- Use the following code to determine when to return HTTP status code 403:
for ((i = 1; i <= 10; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-w "%{http_code}")
if [[ $RESULT != "403" ]]; then
echo "http_code($RESULT) should be 403"
exit
fi
done
Step 4: Update the JWT authorization policy
- On the details page of the ASM instance, choose in the left-side navigation pane.
- On the AuthorizationPolicy page, find the require-jwt policy and click YAML in the Actions column.
- In the Edit panel, add specified content in the code editor.
The following code provides an example of the content to be added to the require-jwt-group.yaml
file:
when:
- key: request.auth.claims[groups]
values: ["group1"]
The following code provides an example of the complete content for the require-jwt-group.yaml
file:
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"]
Note
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 the groups
field contains group1
.
- 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 access token:
echo "$TOKEN_GROUP" | cut -d '.' -f2 - | base64 --decode - | jq
- The following output shows the decoded value of the sample access token:
{
"exp": 3537391104,
"groups": [
"group1",
"group2"
],
"iat": 1537391104,
"iss": "testing@secure.istio.io",
"scope": [
"scope1",
"scope2"
],
"sub": "testing@secure.istio.io"
}
- Click OK.
Result:If the request header contains a valid access token, HTTP status code 200 is returned.
Otherwise, HTTP status code 403 is returned.
- Use the following code to determine when to return HTTP status code 200:
for ((i = 1; i <= 10; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-H "Authorization: Bearer $TOKEN_GROUP" \
-w "%{http_code}")
if [[ $RESULT != "200" ]]; then
echo "http_code($RESULT) should be 200"
exit
fi
done
- Use the following code to determine when to return HTTP status code 403:
for ((i = 1; i <= 10; i++)); do
RESULT=$(kubectl \
--kubeconfig "$USER_CONFIG" \
exec "$sleep_pod" \
-c sleep \
-n foo \
-- curl "http://httpbin.foo:8000/headers" \
-s \
-o /dev/null \
-H "Authorization: Bearer $TOKEN" \
-w "%{http_code}")
if [[ $RESULT != "403" ]]; then
echo "http_code($RESULT) should be 403"
exit
fi
done