Before you begin

  1. Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.

  2. Get the external address of the gateway and save it in an environment variable.

Create a JWT policy

  1. Create a VirtualHostOption with the details of the JSON Web Key Set (JWKS) server to use to verify the signature of JWTs in future protected requests.

      kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: VirtualHostOption
    metadata:
      name: jwt
      namespace: gloo-system
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: http
        namespace: gloo-system
      options:
        jwt:
          providers:
            selfminted:
              issuer: solo.io
              jwks:
                local:
                  key: |
                    -----BEGIN PUBLIC KEY-----
                    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAskFAGESgB22iOsGk/UgX
                    BXTmMtd8R0vphvZ4RkXySOIra/vsg1UKay6aESBoZzeLX3MbBp5laQenjaYJ3U8P
                    QLCcellbaiyUuE6+obPQVIa9GEJl37GQmZIMQj4y68KHZ4m2WbQVlZVIw/Uw52cw
                    eGtitLMztiTnsve0xtgdUzV0TaynaQrRW7REF+PtLWitnvp9evweOrzHhQiPLcdm
                    fxfxCbEJHa0LRyyYatCZETOeZgkOHlYSU0ziyMhHBqpDH1vzXrM573MQ5MtrKkWR
                    T4ZQKuEe0Acyd2GhRg9ZAxNqs/gbb8bukDPXv4JnFLtWZ/7EooKbUC/QBKhQYAsK
                    bQIDAQAB
                    -----END PUBLIC KEY-----
    EOF
      
  2. Send a request to the httpbin app. Verify that your request is denied and that you get back a 401 HTTP response code, because all routes on the gateway now require a valid JWT token.

    Example output:

       < HTTP/1.1 401 Unauthorized
       HTTP/1.1 401 Unauthorized
       < www-authenticate: Bearer realm="http://www.example.com:8080/headers"
       www-authenticate: Bearer realm="http://www.example.com:8080/headers"
       < content-length: 14
       content-length: 14
       < content-type: text/plain
       content-type: text/plain
       < date: Fri, 28 Jun 2024 02:19:00 GMT
       date: Fri, 28 Jun 2024 02:19:00 GMT
       < server: envoy
       server: envoy
    
       < 
       * Connection #0 to host 34.XXX.XX.XXX left intact
       Jwt is missing% 
       

  3. Create an environment variable to save the JWT tokens for the users Alice and Bob.

    1. Save the JWT token for Alice. Alice works in the dev team.

        export ALICE_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyAiaXNzIjogInNvbG8uaW8iLCAib3JnIjogInNvbG8uaW8iLCAic3ViIjogImFsaWNlIiwgInRlYW0iOiAiZGV2IiwgImxsbXMiOiB7ICJvcGVuYWkiOiBbICJncHQtMy41LXR1cmJvIiBdIH0gfQ.I7whTti0aDKxlILc5uLK9oo6TljGS6JUrjPVd6z1PxzucUa_cnuKkY0qj_wrkzyVN5djy4t2ggE1uBO8Llpwi-Ygru9hM84-1m53aO07JYFya1VTDsI25tCRG8rYhShDdAP5L935SIARta2QtHhrVcd1Ae7yfTDZ8G1DXLtjR2QelszCd2R8PioCQmqJ8PeKg4sURhu05GlBCZoXES9-rtPVbe6j3YLBTodJAvLHhyy3LgV_QbN7IiZ5qEywdKHoEF4D4aCUf_LqPp4NoqHXnGT4jLzWJEtZXHQ4sgRy_5T93NOLzWLdIjgMjGO_F0aVLwBzU-phykOVfcBPaMvetg
        
    2. Save the JWT token for Bob. Bob works in the ops team.

        export BOB_TOKEN=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyAiaXNzIjogInNvbG8uaW8iLCAib3JnIjogInNvbG8uaW8iLCAic3ViIjogImJvYiIsICJ0ZWFtIjogIm9wcyIsICJsbG1zIjogeyAibWlzdHJhbGFpIjogWyAibWlzdHJhbC1sYXJnZS1sYXRlc3QiIF0gfSB9.p7J2UFwnUJ6C7eXsFCSKb5b7ecWZ75JO4TUJHafjLv8jJ7GzKfJVk7ney19PYUrWrO4ntwnnK5_sY7yaLUBCJ3fv9pcoKyRtJTw1VMMTQsKkWFgvy-jEwc9M-D5lrUfR1HXGEUm6NBaj_Ja78XScPZb_-APPqMIvzDZU04vd6hna3UMc4DZE0wcnTjOqoND0GllHLupYTfgX0v9_AYJiKRAcJvol1W14dI7szpY5GFZtPqq0kl1g0sJPg-HQKwf7Cfvr_JLjkepNJ6A1lsrG8QbuUvMUAdaHzwLvF3L_G6VRjEte6okZpaq0g2urWpZgdNmPVN71Q_0WhyrJTr6SyQ
        
  4. Send another request to the httpbin app. This time, you include Alice’s JWT token in the Authorization header. Because these JWT tokens were signed by the JWT issuer that is used in the VirtualHostOption, the request now succeeds. Verify that you get back a 200 HTTP response code.

    Example output:

      < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
    ....
    {
     "headers": {
         "Accept": [
         "*/*"
         ],
         "Host": [
         "www.example.com:8080"
         ],
         "User-Agent": [
         "curl/7.77.0"
         ],
         "X-Envoy-Expected-Rq-Timeout-Ms": [
         "15000"
         ],
         "X-Forwarded-Proto": [
         "http"
         ],
         "X-Request-Id": [
         "c7e10708-abda-42b7-833e-b6ac93252612"
         ]
     }
    }
      
  5. Repeat the request with Bob’s JWT token. Verify that the request succeeds with a 200 HTTP response code.

    Example output:

      < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
    ...
      

Authorize access based on claims

You can use the claims in the JWT token to restrict access beyond basic authentication.

  1. Create a RouteOption resource that extracts the team claim from the JWT token. The following example allows access to httpbin only if the JWT contains the "team": "dev" claim.

      kubectl apply -f- <<EOF
    apiVersion: gateway.solo.io/v1
    kind: RouteOption
    metadata:
      name: jwt
      namespace: httpbin
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: HTTPRoute
        name: httpbin
      options:
        rbac:
          policies:
            viewer:
              nestedClaimDelimiter: .
              principals:
              - jwtPrincipal:
                  claims:
                    team: dev
    EOF
      
  2. Send another request to the httpbin with the JWT token for Alice. Because the JWT matcher is set to LIST_CONTAINS, the request only succeeds if the team: dev claims is present in the JWT token. Because Alice’s JWT token includes that claim, the request succeeds.

    Example output:

      < HTTP/1.1 200 OK
    HTTP/1.1 200 OK
    ....
    {
     "headers": {
         "Accept": [
         "*/*"
         ],
         "Host": [
         "www.example.com:8080"
         ],
         "User-Agent": [
         "curl/7.77.0"
         ],
         "X-Envoy-Expected-Rq-Timeout-Ms": [
         "15000"
         ],
         "X-Forwarded-Proto": [
         "http"
         ],
         "X-Request-Id": [
         "c7e10708-abda-42b7-833e-b6ac93252612"
         ]
     }
    }
      
  3. Repeat the request with Bob’s JWT token. Because Bob’s token does not include the team: dev claim, the request is denied and a 403 HTTP response code is returned.

    Example output:

      * Mark bundle as not supporting multiuse
    < HTTP/1.1 403 Forbidden
    < content-type: text/plain
    < date: Tue, 18 Jun 2024 03:21:26 GMT
    < server: envoy
    < connection: close
    < transfer-encoding: chunked   
      

Cleanup

You can remove the resources that you created in this guide.

  kubectl delete routeoption jwt -n httpbin
kubectl delete virtualhostoption jwt -n gloo-system