JWT Authentication

This task provides instructions for configuring JSON Web Token (JWT) authentication. JWT authentication checks if an incoming request has a valid JWT before routing the request to a backend service. Currently, Envoy Gateway only supports validating a JWT from an HTTP header, e.g. Authorization: Bearer <token>.

Envoy Gateway introduces a new CRD called SecurityPolicy that allows the user to configure JWT authentication. This instantiated resource can be linked to a Gateway, HTTPRoute or GRPCRoute resource.

Prerequisites

Follow the steps from the Quickstart task to install Envoy Gateway and the example manifest. Before proceeding, you should be able to query the example backend using HTTP.

Verify the Gateway status:

kubectl get gateway/eg -o yaml
egctl x status gateway -v

For GRPC - follow the steps from the GRPC Routing example.

Configuration

Allow requests with a valid JWT by creating an SecurityPolicy and attaching it to the example HTTPRoute or GRPCRoute.

HTTPRoute

kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/jwt/jwt.yaml

Two HTTPRoute has been created, one for /foo and another for /bar. A SecurityPolicy has been created and targeted HTTPRoute foo to authenticate requests for /foo. The HTTPRoute bar is not targeted by the SecurityPolicy and will allow unauthenticated requests to /bar.

Verify the HTTPRoute configuration and status:

kubectl get httproute/foo -o yaml
kubectl get httproute/bar -o yaml

The SecurityPolicy is configured for JWT authentication and uses a single JSON Web Key Set (JWKS) provider for authenticating the JWT.

Verify the SecurityPolicy configuration:

kubectl get securitypolicy/jwt-example -o yaml

GRPCRoute

kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/latest/examples/kubernetes/jwt/grpc-jwt.yaml

A SecurityPolicy has been created and targeted GRPCRoute yages to authenticate all requests for yages service..

Verify the GRPCRoute configuration and status:

kubectl get grpcroute/yages -o yaml

The SecurityPolicy is configured for JWT authentication and uses a single JSON Web Key Set (JWKS) provider for authenticating the JWT.

Verify the SecurityPolicy configuration:

kubectl get securitypolicy/jwt-example -o yaml

Testing

Ensure the GATEWAY_HOST environment variable from the Quickstart is set. If not, follow the Quickstart instructions to set the variable.

echo $GATEWAY_HOST

HTTPRoute

Verify that requests to /foo are denied without a JWT:

curl -sS -o /dev/null -H "Host: www.example.com" -w "%{http_code}\n" http://$GATEWAY_HOST/foo

A 401 HTTP response code should be returned.

Get the JWT used for testing request authentication:

TOKEN=$(curl https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/jwt/test.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode

Note: The above command decodes and returns the token’s payload. You can replace f2 with f1 to view the token’s header.

Verify that a request to /foo with a valid JWT is allowed:

curl -sS -o /dev/null -H "Host: www.example.com" -H "Authorization: Bearer $TOKEN" -w "%{http_code}\n" http://$GATEWAY_HOST/foo

A 200 HTTP response code should be returned.

Verify that requests to /bar are allowed without a JWT:

curl -sS -o /dev/null -H "Host: www.example.com" -w "%{http_code}\n" http://$GATEWAY_HOST/bar

GRPCRoute

Verify that requests to yagesservice are denied without a JWT:

grpcurl -plaintext -authority=grpc-example.com ${GATEWAY_HOST}:80 yages.Echo/Ping

You should see the below response

Error invoking method "yages.Echo/Ping": rpc error: code = Unauthenticated desc = failed to query for service descriptor "yages.Echo": Jwt is missing

Get the JWT used for testing request authentication:

TOKEN=$(curl https://raw.githubusercontent.com/envoyproxy/gateway/main/examples/kubernetes/jwt/test.jwt -s) && echo "$TOKEN" | cut -d '.' -f2 - | base64 --decode

Note: The above command decodes and returns the token’s payload. You can replace f2 with f1 to view the token’s header.

Verify that a request to yages service with a valid JWT is allowed:

grpcurl -plaintext -H "authorization: Bearer $TOKEN" -authority=grpc-example.com ${GATEWAY_HOST}:80 yages.Echo/Ping

You should see the below response

{
  "text": "pong"
}

Connect to a remote JWKS with Self-Signed Certificate

To connect to a remote JWKS with a self-signed certificate, you need to configure it using the Backend resource within the SecurityPolicy. Additionally, use the BackendTLSPolicy to specify the CA certificate required to authenticate the JWKS host.

The following example demonstrates how to configure the remote JWKS with a self-signed certificate.

cat <<EOF | kubectl apply -f -
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: jwt-example
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: foo
  jwt:
    providers:
    - name: example
      remoteJWKS:
        backendRefs:
          - group: gateway.envoyproxy.io
            kind: Backend
            name: remote-jwks
            port: 443
        backendSettings:
          retry:
            numRetries: 3
            perRetry:
              backOff:
                baseInterval: 1s
                maxInterval: 5s
            retryOn:
              triggers: ["5xx", "gateway-error", "reset"]
        uri: https://foo.bar.com/jwks.json
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: remote-jwks
spec:
  endpoints:
  - fqdn:
      hostname: foo.bar.com
      port: 443
---
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
  name: remote-jwks-btls
spec:
  targetRefs:
  - group: gateway.envoyproxy.io
    kind: Backend
    name: remote-jwks
    sectionName: "443"
  validation:
    caCertificateRefs:
    - name: remote-jwks-server-ca
      group: ""
      kind: ConfigMap
    hostname: foo.bar.com
EOF

Save and apply the following resource to your cluster:

---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: SecurityPolicy
metadata:
  name: jwt-example
spec:
  targetRef:
    group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: foo
  jwt:
    providers:
    - name: example
      remoteJWKS:
        backendRefs:
          - group: gateway.envoyproxy.io
            kind: Backend
            name: remote-jwks
            port: 443
        backendSettings:
          retry:
            numRetries: 3
            perRetry:
              backOff:
                baseInterval: 1s
                maxInterval: 5s
            retryOn:
              triggers: ["5xx", "gateway-error", "reset"]
        uri: https://foo.bar.com/jwks.json
---
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: Backend
metadata:
  name: remote-jwks
spec:
  endpoints:
  - fqdn:
      hostname: foo.bar.com
      port: 443
---
apiVersion: gateway.networking.k8s.io/v1alpha3
kind: BackendTLSPolicy
metadata:
  name: remote-jwks-btls
spec:
  targetRefs:
  - group: gateway.envoyproxy.io
    kind: Backend
    name: remote-jwks
    sectionName: "443"
  validation:
    caCertificateRefs:
    - name: remote-jwks-server-ca
      group: ""
      kind: ConfigMap
    hostname: foo.bar.com

As shown in the example above, the SecurityPolicy resource is configured with a remote JWKS within its JWT settings. The backendRefs field references the Backend resource that defines the JWKS host. The BackendTLSPolicy resource specifies the CA certificate required to authenticate the JWKS host.

Additional connection settings for the remote JWKS host can be configured in the backendSettings. Currently, only the retry policy is supported.

For more information about Backend and BackendTLSPolicy, refer to the Backend Routing and Backend TLS: Gateway to Backend tasks.

Clean-Up

Follow the steps from the Quickstart to uninstall Envoy Gateway and the example manifest.

Delete the SecurityPolicy:

kubectl delete securitypolicy/jwt-example

Next Steps

Checkout the Developer Guide to get involved in the project.


Last modified January 30, 2025: [release/1.3] release notes (#5177) (c2215b2)