For more information about JWTs, see the JWT overview and API docs. For an example that selects your destinations, instead of the routes to the destinations, see JWT for destinations.

Before you begin

  1. Complete the multicluster getting started guide to set up the following testing environment.

    • Three clusters along with environment variables for the clusters and their Kubernetes contexts.
    • The Gloo meshctl CLI, along with other CLI tools such as kubectl and istioctl.
    • The Gloo management server in the management cluster, and the Gloo agents in the workload clusters.
    • Istio installed in the workload clusters.
    • A simple Gloo workspace setup.
  2. Install Bookinfo and other sample apps.
  3. 2.5 only: Upgrade your Gloo Helm release to set the EnableJWTPolicyEastWestRoute feature gate to true. For more information the impact of enabling this feature gate, see the release notes.

Configure JWT policies

You can apply a JWT policy at the destination or route level, but you cannot apply multiple JWT policies to the same destination or to the same route in a route table. If you try to apply multiple policies, only the policy that you created first takes effect. In general, you apply policies to routes to protect ingress traffic through the gateway, and to destinations to protect traffic within the service mesh. For more information, see Applying policies.

The following example is for a basic JWT policy with a local JWT issuer and inline public key. The policy does the following:

  • Enables JWT authentication for the selected destinations.
  • Adds the value of an org claim from the JWT payload to an X-Org header in the request, if present.
  • Adds the value of an email claim from the JWT payload to an X-Email header in the request, if present.
  • Checks requests by using the token found in the X-Auth header with the prefix Bearer <token>, or in a query parameter auth_token=<token>. Note that if a request has both the header and query parameter, both tokens must be valid for Gloo Mesh Enterprise to accept the request.

Review the following table to understand this configuration. For more information, see the API docs.

SettingDescription
applyToRoutesUse labels to configure which routes to apply the policy to. This example label matches the app and route from the example route table that you apply separately. If omitted and you do not have another selector such as applyToDestinations, the policy applies to all routes in the workspace.
phaseSet when to apply the JWT filter in the request chain, either before (preAuthz) or after (postAuthz) authorization to have access to the JWT token. You can also set the priority if you have multiple policies in the same phase. The lowest numbered priority is run first. For more information, see Phase considerations. This example sets no priority, so the default value of zero is used.
providersSet up the JWT providers for the policy. You can name the providers to help you map the provider when viewing logs to debug. However, the provider name does not affect the policy’s behavior and cannot be used by other resources to select the policy. In this example, only one provider is set up, with the name dev-example. For an example with more than one provider, see Multiple JWT providers.
claimsToHeadersOptionally set the claims from the JWT payload that you want to extract and add as headers to the request before the request is forwarded to the upstream destination. This example extracts one claim and adds it as a header.
claimsToHeaders.appendEnter a boolean value to add a claim’s value if the header exists in the request. Use true to append the claim’s value to the header, and false to overwrite any existing value in the header.
claimsToHeaders.claimEnter the name of the claim in the JWT payload to get the value for the header. In this example, the claim is org.
claimsToHeaders.headerEnter the request header that the value of the claim is copied to. In this example, the header is x-org.
issuerOptionally set the JWT issuer, usually as a URL or email address. If set, the iss field in the JWT token must match this field, or else the request is denied. If unset, the iss field in the JWT token is not checked. In this example, the issuer is an internal developer portal, https://dev-example.com.
localProvide the PEM-formatted public key to verify the JWT token. In this example, the public key is written inline to the policy for testing purposes. For production scenarios, you can set a remote reference to your JSON Web Key Set (JWKS) server instead of this local setting.
tokenSourceSpecify where Gloo Mesh Enterprise looks for the token to use for JWT authentication. If unset, the default locations are tried in the following order:
  1. The authorization header X-Auth with the value Bearer <token>.
  2. The query parameter for access_token, such as https://<path>?access_token=<token>.
You can set up multiple JWT tokens to verify per request. If a request has multiple header and query parameters, all tokens must be valid for Gloo Mesh Enterprise to accept the request.
tokenSource.headersSpecify the header to get the JWT from. By default, Gloo Mesh Enterprise uses the authorization header X-Auth and expects a value with a prefix of Bearer <token>. In this example, the header and prefix are explicitly set to the default values, X-Auth and 'Bearer '.
tokenSource.queryParametersSpecify a query parameter to get the token from. The default value is access_token. This example uses a different query parameter, auth_token.

Try out JWT policies

To verify that the JWT policy protects your destination, you must have a JWT and a set of keys to validate the JWT. The following example uses a sample provided for you in GitHub. For more details about the sample JWT, see the GitHub readme. You can adapt other guides to create your own keys and JWT or use a remote JWKS with keys from an OIDC provider.

  1. Create a route table that defines the east-west service mesh routes to your backing destinations.

      kubectl apply --context $REMOTE_CONTEXT1 -f - <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      annotations:
        cluster.solo.io/cluster: ""
      name: www-example-com
      namespace: httpbin
      labels:
        route: httpbin
    spec:
      hosts:
      - www.example.com
      workloadSelectors:
      - {}
      http:
      - name: httpbin-mesh
        labels:
          route: httpbin
        matchers:
        - headers:
          - name: X-httpbin-mesh
        forwardTo:
          destinations:
          - port:
              number: 8000
            ref:
              name: httpbin
              namespace: httpbin
    EOF
      

    Review the following table to understand this configuration. For more information, see the API docs.

    SettingDescription
    hostsThe host domain that requests are routed for. For example, workloads within your service mesh can send a request to this http://www.example.com host instead of directly to the other destination, such as http://httpbin.httpbin:8000/.
    workloadSelectorsThe workloads within your service mesh that can have their requests routed through this route table. By selecting all workloads ({}), any workload in the service mesh can use these routes.
    httpThe HTTP route that this route table sets up. In this example:
    • name: The route has the name httpbin-mesh so that you can easily identify this route as an east-west route within the service mesh.
    • labels: The route has the label route: httpbin that you can use in your JWT policy to select this route.
    • matchers: The route matches requests on the host that include the X-httpbin-mesh header.
    • forwardTo: Requests along the matching path are sent to the httpbin Kubernetes service destination.
    virtualGatewayThis value is omitted. This way, the route table does not select a virtual gateway, which you only need for ingress traffic. For more information about using route selectors in JWT policies for both east-west and ingress routes, see Routes for ingress or service mesh traffic.
  2. Apply the JWT policy to the east-west routes that you just defined. For more information about this policy, see the configuration example.

      kubectl apply -f https://gist.githubusercontent.com/artberger/674bab05350c9a048303cc7daaffe730/raw/daf7d9b64e5e9ecf309f17123e01f5a6cbb6c7eb/jwt-policy-basic.yaml
      
  3. Send a request to the httpbin app without any authentication. Notice that your request is denied with a 401 error.

    Example output:

      HTTP/1.1 401 Unauthorized
    www-authenticate: Bearer realm="http://www.example.com/get"
    ...
    Jwt is missing
      
  4. Get a sample JWT that is preconfigured to meet the validation requirements that you set in the JWT policy for the dev-example provider.

      TOKEN=$(curl https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/gloo-gateway/jwt/dev-example.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode
      

    Example output:

      {"iss":"https://dev.example.com","exp":4804324736,"iat":1648651136,"org":"internal","email":"dev1@solo.io","group":"engineering","scope":"is:developer%  
      
  5. Copy the value of the sample JWT to paste into the curl command in the next step.

      echo $TOKEN
      

    Example truncated output to copy:

      eyJhbGciOiJSUzI...
      
  6. Try the request to the httpbin app again. Replace the <$TOKEN> in the ?auth_token= query parameter with the JWT value that you copied in the previous step. Notice that your request is now accepted!

    In the example output you get back a 200 response. You also can see the X-Email and X-Org headers that you appended in the claimsToHeaders section of the policy.

      HTTP/1.1 200 OK 
    ...
    {
      "args": {}, 
      "headers": {
        "Accept": [
          "*/*"
        ],
        "Host": [
          "www.example.com/get"
        ],
        "X-Email": [
          "dev1@solo.io"
        ],
        "X-Org": [
          "internal"
        ],
        ...
      
  7. You can optionally remove the resources that you set up as part of this guide.
      kubectl delete RouteTable -n httpbin www-example-com
    kubectl delete JwtPolicy -n httpbin jwt-policy