All Products
Search
Document Center

Alibaba Cloud Service Mesh:Authenticate a JWT in an HTTP request for authorization

Last Updated:Feb 22, 2024

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

  1. 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.

  2. Create httpbin.yaml and sleep.yaml files with the following content:

    Expand to view the httpbin.yaml file

    apiVersion: v1
    kind: ServiceAccount
    metadata:
     name: httpbin
    ---
    apiVersion: v1
    kind: Service
    metadata:
     name: httpbin
     labels:
     app: httpbin
     service: httpbin
    spec:
     ports:
     - name: http
     port: 8000
     targetPort: 80
     selector:
     app: httpbin
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
     name: httpbin
    spec:
     replicas: 1
     selector:
     matchLabels:
     app: httpbin
     version: v1
     template:
     metadata:
     labels:
     app: httpbin
     version: v1
     spec:
     serviceAccountName: httpbin
     containers:
     - image: docker.io/kennethreitz/httpbin
     imagePullPolicy: IfNotPresent
     name: httpbin
     ports:
     - containerPort: 80

    Expand to view the sleep.yaml file

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: sleep
    ---
    apiVersion: v1
    kind: Service
    metadata:
      name: sleep
      labels:
        app: sleep
        service: sleep
    spec:
      ports:
      - port: 80
        name: http
      selector:
        app: sleep
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: sleep
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: sleep
      template:
        metadata:
          labels:
            app: sleep
        spec:
          terminationGracePeriodSeconds: 0
          serviceAccountName: sleep
          containers:
          - name: sleep
            image: curlimages/curl
            command: ["/bin/sleep", "3650d"]
            imagePullPolicy: IfNotPresent
            volumeMounts:
            - mountPath: /etc/sleep/tls
              name: secret-volume
          volumes:
          - name: secret-volume
            secret:
              secretName: sleep-secret
              optional: true
    ---
  3. 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
  4. Use the sleep service to access the httpbin service.

    1. Run the following command to enable bash for the sleep service:

      kubectl exec -it deploy/sleep -- sh
    2. 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

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > RequestAuthentication. On the page that appears, click Create from YAML.

  3. 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 the httpbin service. If a 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).

    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"}]}'
  4. 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.

    JWT

  5. Use the sleep service to access the httpbin service.

    1. Run the following command to enable bash for the sleep service:

      kubectl exec -it deploy/sleep -- sh
    2. 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
    3. 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

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy. On the page that appears, click Create from YAML.

  3. 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 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.

    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"]
  4. 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"}
  5. Use the sleep service to access the httpbin service.

    1. Run the following command to enable bash for the sleep service:

      kubectl exec -it deploy/sleep -- sh
    2. 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
    3. 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

  1. Log on to the ASM console. In the left-side navigation pane, choose Service Mesh > Mesh Management.

  2. On the Mesh Management page, click the name of the ASM instance. In the left-side navigation pane, choose Mesh Security Center > AuthorizationPolicy.

  3. On the AuthorizationPolicy page, find the require-jwt policy and click YAML in the Actions column.

  4. 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 the groups field contains group1.

    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"]
  5. 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"
    }
  6. Use the sleep service to access the httpbin service.

    1. Run the following command to enable bash for the sleep service:

      kubectl exec -it deploy/sleep -- sh
    2. 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.

    3. 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.