Authenticate and authorize JWT in HTTP requests

更新时间:
复制 MD 格式

To verify and authorize the source of HTTP requests in a service mesh, configure JSON Web Token (JWT) request authentication to implement origin authentication (end-user authentication). This configuration validates the Access Token in the request header, allowing only trusted requests to access your service. It enhances service security and simplifies inter-service identity verification.

Prerequisites

You have added a cluster to the ASM instance, and the ASM instance version is 1.6 or later.

Background information

Service Mesh supports two authentication methods:

  • Transport authentication: Uses mutual TLS (mTLS) and is commonly used for inter-service communication.

  • Origin authentication: Uses JWT and is commonly used for request authentication between clients and services.

JWT is a standard for securely transmitting claims between parties. For more information, see the JWT official documentation.

Step 1: Create a namespace and deploy sample services

  1. Create a namespace named foo with the label istio-injection set to enabled. For details, see Manage global namespaces.

  2. Create httpbin.yaml and sleep.yaml using the following content.

    Expand to view httpbin.yaml

    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 sleep.yaml

    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. Connect to your cluster using kubectl and run the following commands to deploy the httpbin and sleep services in the foo namespace.

    For instructions on connecting to your cluster using kubectl, see Obtain the cluster KubeConfig and connect to the cluster using kubectl.

    kubectl apply -f httpbin.yaml -n foo
    kubectl apply -f sleep.yaml -n foo
  4. Access the httpbin service from the sleep service.

    1. Run the following command to enter the sleep pod and start a bash shell.

      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

      The response 200 OK indicates a successful request.

Step 2: Create request authentication

  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. Set the Namespaces to foo. Enter the following YAML content for request authentication in the text box, then click Create.

    This YAML configures the httpbin service to require requests to match the rules defined in jwtRules. Specifically, if the request header contains an Access Token, the decoded iss claim must be testing@secure.istio.io. The jwks field defines token generation details. For more information, see the JWT official documentation.

    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. Parse the token.

    This example uses the following token:

    TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'

    Run the following command to parse 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 website provides the same token parsing capability. The graphical output appears as follows.

    HEADER:
    {
      "alg": "RS256",
      "kid": "DHFbpoIUqrY8t2zpA2qXfCmr5VO5ZEr4RzHU_-envvQ",
      "typ": "JWT"
    }
    PAYLOAD:
    {
      "exp": 4685989700,
      "foo": "bar",
      "iat": 1532389700,
      "iss": "testing@secure.istio.io",
      "sub": "testing@secure.istio.io"
    }
    VERIFY SIGNATURE:
    RSASHA256(
      base64UrlEncode(header) + "." +
      base64UrlEncode(payload),
      Public Key in SPKI, PKCS #1
    )
  5. Access the httpbin service from the sleep service.

    1. Run the following command to enter the sleep pod and start a bash shell.

      kubectl exec -it deploy/sleep -- sh
    2. Run the following command to send a request to the httpbin service with a valid Access Token in the request header.

      Replace your_valid_access_token_here with an 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 with an invalid Access Token in the request header.

      Replace your_invalid_access_token_here with an actual invalid access token.

      INVALID_TOKEN=your_invalid_access_token_here
      curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000

      A response of 401 Unauthorized means the request was rejected by authentication and access failed.

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. Set the Namespaces to foo. Enter the following YAML content for the authorization policy in the text box, then click Create.

    This YAML configures the httpbin service to allow requests only when the decoded token’s iss value plus / plus the sub value (i.e., source.requestPrincipals) equals 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. Parse the token.

    This example uses the following token:

    TOKEN='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjQ2ODU5ODk3MDAsImZvbyI6ImJhciIsImlhdCI6MTUzMjM4OTcwMCwiaXNzIjoidGVzdGluZ0BzZWN1cmUuaXN0aW8uaW8iLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.CfNnxWP2tcnR9q0vxyxweaF3ovQYHYZl82hAUsn21bwQd9zP7c-LS9qd_vpdLG4Tn1A15NxfCjp5f7QNBUo-KC9PJqYpgGbaXhaGx7bEdFWjcwv3nZzvc7M__ZpaCERdwU7igUmJqYGBYQ51vr2njU9ZimyKkfDe3axcyiBZde7G6dabliUosJvvKOPcKIWPccCgefSj_GNfwIip3-SsFdlR7BtbVUcqR-yv-XOxJ3Uc1MI0tz3uMiiZcyPV7sNCU4KRnemRIMHVOfuvHsU60_GhGbiSFzgPTAa9WTltbnarTbxudb_YEOx12JiwYToeX0DCPb43W1tzIBxgm8NxUg'

    Run the following command to parse 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. Access the httpbin service from the sleep service.

    1. Run the following command to enter the sleep pod and start a bash shell.

      kubectl exec -it deploy/sleep -- sh
    2. Run the following command to send a request to the httpbin service with a valid Access Token in the request header.

      Replace your_valid_access_token_here with an 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 with an invalid Access Token in the request header.

      Replace your_invalid_access_token_here with an actual invalid access token.

      INVALID_TOKEN=your_invalid_access_token_here
      curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000

      A response of 403 Forbidden means the request was rejected by the authorization policy and access failed.

Step 4: Append to 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, click the require-jwt policy's View YAML.

  4. In the Edit dialog box, add the following content, then click OK.

        when:
        - key: request.auth.claims[groups]
          values: ["group1"]

    The complete YAML example is as follows. The YAML specifies that when you request the httpbin service, the request permission is set to ALLOW only if, after decoding the Token in the request header, the value of groups includes 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. Parse the token.

    This example uses the following token:

    TOKEN_GROUP='eyJhbGciOiJSUzI1NiIsImtpZCI6IkRIRmJwb0lVcXJZOHQyenBBMnFYZkNtcjVWTzVaRXI0UnpIVV8tZW52dlEiLCJ0eXAiOiJKV1QifQ.eyJleHAiOjM1MzczOTExMDQsImdyb3VwcyI6WyJncm91cDEiLCJncm91cDIiXSwiaWF0IjoxNTM3MzkxMTA0LCJpc3MiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyIsInNjb3BlIjpbInNjb3BlMSIsInNjb3BlMiJdLCJzdWIiOiJ0ZXN0aW5nQHNlY3VyZS5pc3Rpby5pbyJ9.EdJnEZSH6X8hcyEii7c8H5lnhgjB5dwo07M5oheC8Xz8mOllyg--AHCFWHybM48reunF--oGaG6IXVngCEpVF0_P5DwsUoBgpPmK1JOaKN6_pe9sh0ZwTtdgK_RP01PuI7kUdbOTlkuUi2AO-qUyOm7Art2POzo36DLQlUXv8Ad7NBOqfQaKjE9ndaPWT7aexUsBHxmgiGbz1SyLH879f7uHYPbPKlpHU6P9S-DaKnGLaEchnoKnov7ajhrEhGXAQRukhDPKUHO9L30oPIr5IJllEQfHYtt6IZvlNUGeLUcif3wpry1R5tBXRicx2sXMQ7LyuDremDbcNy_iE76Upg'

    Run the following command to parse 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. Access the httpbin service from the sleep service.

    1. Run the following command to enter the sleep pod and start a bash shell.

      kubectl exec -it deploy/sleep -- sh
    2. Run the following command to send a request to the httpbin service with a valid Access Token in the request header.

      Replace your_valid_access_token_here with an actual valid access token.

      TOKEN=your_valid_access_token_here
      curl -I -H "Authorization: Bearer $TOKEN" httpbin.foo.svc.cluster.local:8000

      A response of 200 OK means the request passed the authorization policy and access succeeded.

    3. Run the following command to send a request to the httpbin service with an invalid Access Token in the request header.

      Replace your_invalid_access_token_here with an actual invalid access token.

      INVALID_TOKEN=your_invalid_access_token_here
      curl -I -H "Authorization: Bearer $INVALID_TOKEN" httpbin.foo.svc.cluster.local:8000

      A response of 403 Forbidden means the request was rejected by the authorization policy and access failed.

References

To learn about JWT algorithms supported by ASM, how to use JwksUri, and how to exclude specific paths from JWT authentication, see JWT FAQ.