For more information about JWTs, see the JWT overview and API docs.

Before you begin

  1. Set up Gloo Mesh Gateway in a single cluster.
  2. Install Bookinfo and other sample apps.
  3. Configure an HTTP listener on your gateway and set up basic routing for the sample apps.

Clear route cache

The Envoy proxy in your gateway instance keeps a route cache in memory of precomputed routing decisions to help speed up performance. When the gateway proxy gets a request, it can check the route cache to decide where to send the request. When the route cache is cleared, Gloo recomputes the routing rules. This way, any old and potentially conflicting data from the initial request is cleared. Then, your traffic rules apply to the fresh route that might have new information, such as for claim-based routing with a JWT.

By default, the route cache is cleared in Gloo Gateway when the auth response is successful or if the JWT policy adds a claim in the claimsToHeader field. To change this behavior, you can use the clearRouteCache setting to explicitly set when to clear the route cache on a JWT policy. For more information about how route caching works with the JWT policy, see the API docs.

The following example shows how to use the clearRouteCache setting to keep the route cache. This way, when a request is sent with a header that you want to extract from the JWT instead, the request is denied with a direct response. This approach can help prevent spoofing, saves route processing time by not proxying the request upstream, and provides an informative error message to the client.

  1. Add another route for the httpbin app in the sample route table. This new route returns a direct response when the X-email header is in the request. The direct response tells the client not to include an X-email header because you want to extract the email address from the JWT. The direct response route is configured before other httpbin routes so that it is matched first.

      kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: www-example-com
      namespace: bookinfo
    spec:
      hosts:
        - www.example.com
      # Selects the virtual gateway you previously created
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
      http:
        # Route for the main productpage app
        - name: productpage
          matchers:
          - uri:
              prefix: /productpage
          forwardTo:
            destinations:
              - ref:
                  name: productpage
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Routes all /reviews requests to the reviews-v1 or reviews-v2 apps
        - name: reviews
          labels: 
            route: reviews
          matchers:
          - uri:
              prefix: /reviews
          forwardTo:
            destinations:
              - ref:
                  name: reviews
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Routes all /ratings requests to the ratings-v1 app
        - name: ratings-ingress
          labels:
            route: ratings
          matchers:
          - uri:
              prefix: /ratings
          forwardTo:
            destinations:
              - ref:
                  name: ratings
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Direct response route for httpbin requests with X-email header
        - name: httpbin-direct-response
          labels:
            route: httpbin
          matchers:
          - headers:
            - name: X-email
          directResponse:
            body: '{"message": "Based on your routing configuration, Gloo expects to get the X-email header from the JWT, not from the request. Remove the X-email header from the request and try again."}'
            status: 510
        # Main route for requests to the httpbin app
        - name: httpbin-ingress
          labels:
            route: httpbin
          matchers:
          - headers:
            - name: X-httpbin
          forwardTo:
            destinations:
              - ref:
                  name: httpbin
                  namespace: httpbin
                  cluster: $CLUSTER_NAME
                port:
                  number: 8000
    EOF
      
  2. Send the following requests to test the httpbin routing behavior.

  3. Create a JWT policy without the clearRouteCache setting. By default, the route cache is cleared if you add claims in the claimsToHeaders section.

      kubectl apply -f - <<EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: JWTPolicy
    metadata:
      annotations:
        cluster.solo.io/cluster: ""
      name: jwt-policy
      namespace: httpbin
    spec:
      applyToRoutes:
      - route:
          labels:
            route: httpbin
      config:
        phase:
          preAuthz: {}
        providers:
          provider1:
            claimsToHeaders:
            - append: true
              claim: org
              header: x-org
            - append: true
              claim: email
              header: x-email
            issuer: https://localhost
            local:
              inline: |-
                -----BEGIN PUBLIC KEY-----
                MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnknfKiIDREaE/vxu8rtz
                oMaPop6rsiX7GANCRcqFks0j96Gb+UssKD8zJs2JBvEe4n0wNKVeLRbOctII+ZEO
                G8b+Dqig/1ubq3xiGbDBbZqHiFKjFQVUnII3Un9VRtDcJdgaaPGHnhlPs79sJNgQ
                e6AWJmfAasdT7i3MVEW7/dXcROiMRGapmxv+nQbKdoeiCJDULRdMSodhg/WJw2sH
                LLVxh4fPSF7cRxj36Y9FKWcGUH+YKe7n4gufAeEsHk+tPBndymYpmcMjb6W9HrJO
                39vvyMTjLAUyElCEfeMqCpFBCElhaGbF8ZncbV6vvDEkOxMX/m1TYhoJr1E2U8y/
                NwIDAQAB
                -----END PUBLIC KEY-----
            tokenSource:                    
              headers:  
              - name: X-Auth
                prefix: 'Bearer '
              queryParams:       
              - auth_token
    EOF
      
  4. Repeat the request with the X-email header. This time, the request is denied, but not with the direct response that you configured in the routing rules. Instead, a 401 Unauthorized response is returned because you did not include the JWT in the header. The default behavior is to clear the routing cache when you add a claim in the JWT policy, as you did with the x-email header in the claimsToHeader section.

      curl -vik http://www.example.com:80/status/200 -H "X-email: user2@solo.io" -H "X-httpbin: true" --resolve www.example.com:80:$INGRESS_GW_IP
      

    Example response:

      HTTP/1.1 401 Unauthorized
    ...
    Jwt is missing
      
  5. Update the JWT policy to keep the route cache by setting clearRouteCache to false.

      kubectl apply -f - <<EOF
    apiVersion: security.policy.gloo.solo.io/v2
    kind: JWTPolicy
    metadata:
      annotations:
        cluster.solo.io/cluster: ""
      name: jwt-policy
      namespace: httpbin
    spec:
      applyToRoutes:
      - route:
          labels:
            route: httpbin
      config:
        phase:
          preAuthz: {}
        clearRouteCache: "FALSE"
        providers:
          provider1:
            claimsToHeaders:
            - append: true
              claim: org
              header: x-org
            - append: true
              claim: email
              header: x-email
            issuer: https://localhost
            local:
              inline: |-
                -----BEGIN PUBLIC KEY-----
                MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAnknfKiIDREaE/vxu8rtz
                oMaPop6rsiX7GANCRcqFks0j96Gb+UssKD8zJs2JBvEe4n0wNKVeLRbOctII+ZEO
                G8b+Dqig/1ubq3xiGbDBbZqHiFKjFQVUnII3Un9VRtDcJdgaaPGHnhlPs79sJNgQ
                e6AWJmfAasdT7i3MVEW7/dXcROiMRGapmxv+nQbKdoeiCJDULRdMSodhg/WJw2sH
                LLVxh4fPSF7cRxj36Y9FKWcGUH+YKe7n4gufAeEsHk+tPBndymYpmcMjb6W9HrJO
                39vvyMTjLAUyElCEfeMqCpFBCElhaGbF8ZncbV6vvDEkOxMX/m1TYhoJr1E2U8y/
                NwIDAQAB
                -----END PUBLIC KEY-----
            tokenSource:                    
              headers:  
              - name: X-Auth
                prefix: 'Bearer '
              queryParams:       
              - auth_token
    EOF
      
  6. Follow the steps in Basic JWT example to update the policy and set a JWT token for the X-Auth header.

  7. Repeat the request with the X-email header again. Now that you kept the route cache, the request is once again denied based on the directResponse routing rules that you set up.

      curl -vik http://www.example.com:80/status/200 -H "X-Auth: ${TOKEN}" -H "X-email: user2@solo.io" -H "X-httpbin: true" --resolve www.example.com:80:$INGRESS_GW_IP
      

    Example response:

      HTTP/1.1 510 Not Extended
    ...
    {"message": "Based on your routing configuration, Gloo expects to get the X-email header from the JWT, not from the request. Remove the X-email header from the request and try again."}%
      

Cleanup

You can optionally remove the resources that you set up as part of this guide.
  1. Delete the JWT policy that you created.
      kubectl delete jwtpolicy jwt-policy -n default
      
  2. Remove the direct response route from your route table.
      kubectl apply -f- <<EOF
    apiVersion: networking.gloo.solo.io/v2
    kind: RouteTable
    metadata:
      name: www-example-com
      namespace: bookinfo
    spec:
      hosts:
        - www.example.com
      # Selects the virtual gateway you previously created
      virtualGateways:
        - name: istio-ingressgateway
          namespace: bookinfo
      http:
        # Route for the main productpage app
        - name: productpage
          matchers:
          - uri:
              prefix: /productpage
          forwardTo:
            destinations:
              - ref:
                  name: productpage
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Routes all /reviews requests to the reviews-v1 or reviews-v2 apps
        - name: reviews
          labels: 
            route: reviews
          matchers:
          - uri:
              prefix: /reviews
          forwardTo:
            destinations:
              - ref:
                  name: reviews
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Routes all /ratings requests to the ratings-v1 app
        - name: ratings-ingress
          labels:
            route: ratings
          matchers:
          - uri:
              prefix: /ratings
          forwardTo:
            destinations:
              - ref:
                  name: ratings
                  namespace: bookinfo
                  cluster: $CLUSTER_NAME
                port:
                  number: 9080
        # Main route for requests to the httpbin app
        - name: httpbin-ingress
          labels:
            route: httpbin
          matchers:
          - headers:
            - name: X-httpbin
          forwardTo:
            destinations:
              - ref:
                  name: httpbin
                  namespace: httpbin
                  cluster: $CLUSTER_NAME
                port:
                  number: 8000
    EOF