Passthrough auth

Passthrough authentication lets you delegate all authorization decisions to your own external auth server. The kgateway proxy forwards each incoming request to your auth server, which decides whether to allow or deny it. This approach is useful when you have custom authentication logic, an existing auth service you want to reuse, or compliance requirements that demand a centralized auth server.

About passthrough auth

The kgateway proxy integrates with external auth servers that implement the Envoy external authorization gRPC protocol. You configure the connection to your auth server in a GatewayExtension resource, and then reference that extension in a TrafficPolicy resource.

  sequenceDiagram
    participant C as Client
    participant AGW as Kgateway Proxy
    participant Auth as Auth Server
    participant Backend as Backend

    C->>AGW: HTTP Request

    AGW->>Auth: Forward request for auth decision<br/>(gRPC ext_authz protocol)

    alt Authorized
        Auth-->>AGW: 200 OK (allow)
        AGW->>Backend: Forward request
        Backend-->>AGW: Response
        AGW-->>C: Response
    else Not Authorized
        Auth-->>AGW: 403 Forbidden (deny)
        AGW-->>C: 403 Forbidden
    end
  1. The client sends a request to the kgateway proxy.
  2. The proxy forwards the request to your auth server using the Envoy gRPC external auth protocol.
  3. If the auth server allows the request, the proxy forwards it to the backend.
  4. If the auth server denies the request, the proxy returns the configured error status (default: 403 Forbidden) to the client.

Before you begin

  1. Follow the Get started guide to install kgateway.

  2. Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.

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

    export INGRESS_GW_ADDRESS=$(kubectl get svc -n kgateway-system http -o jsonpath="{.status.loadBalancer.ingress[0]['hostname','ip']}")
    echo $INGRESS_GW_ADDRESS  
    kubectl port-forward deployment/http -n kgateway-system 8080:8080

Deploy your auth server

Deploy an auth server that implements the Envoy external auth gRPC protocol. The following example uses the Istio external authorization service for quick testing. This service allows requests that include the x-ext-authz: allow header and denies all others.

  1. Deploy the auth server.

    kubectl apply -f - <<EOF
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: ext-authz
      namespace: kgateway-system
      labels:
        app: ext-authz
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: ext-authz
      template:
        metadata:
          labels:
            app: ext-authz
            app.kubernetes.io/name: ext-authz
        spec:
          containers:
          - name: ext-authz
            image: gcr.io/istio-testing/ext-authz:1.25-dev
            ports:
            - containerPort: 9000
    EOF
  2. Create a Service so that the proxy can reach the auth server.

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Service
    metadata:
      name: ext-authz
      namespace: kgateway-system
      labels:
        app: ext-authz
    spec:
      ports:
      - port: 4444
        targetPort: 9000
        protocol: TCP
        appProtocol: kubernetes.io/h2c
      selector:
        app: ext-authz
    EOF
  3. Verify that the auth server pod is running.

    kubectl get pods -n kgateway-system -l app=ext-authz

Set up passthrough auth

  1. Create a GatewayExtension resource that points the proxy to your auth server. The GatewayExtension must be in the same namespace as the Service that backs the auth server, or you must set up a Kubernetes ReferenceGrant.

    kubectl apply -f - <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: GatewayExtension
    metadata:
      name: passthrough-auth
      namespace: kgateway-system
      labels:
        app: ext-authz
    spec:
      type: ExtAuth
      extAuth:
        grpcService:
          backendRef:
            name: ext-authz
            port: 4444
    EOF
  2. Create a TrafficPolicy that applies passthrough auth at the Gateway level. For other common configuration examples, see Other configuration examples.

    kubectl apply -f - <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: TrafficPolicy
    metadata:
      name: passthrough-auth
      namespace: kgateway-system
      labels:
        app: ext-authz
    spec:
      targetRefs:
      - group: gateway.networking.k8s.io
        kind: Gateway
        name: http
      extAuth:
        extensionRef:
          name: passthrough-auth
    EOF
  3. Send a request without the required header. Verify that the auth server denies the request with a 403 response.

    curl -i http://$INGRESS_GW_ADDRESS:8080/headers -H "host: www.example.com:8080"
    curl -i localhost:8080/headers -H "host: www.example.com"

    Example output:

    HTTP/1.1 403 Forbidden
    x-ext-authz-check-result: denied
    ...
    denied by ext_authz for not found header `x-ext-authz: allow` in the request
  4. Send a request with the x-ext-authz: allow header. The Istio auth server is configured to allow requests with this header. Verify that the request succeeds.

    curl -i http://$INGRESS_GW_ADDRESS:8080/headers -H "host: www.example.com:8080" -H "x-ext-authz: allow"
    curl -i localhost:8080/headers -H "host: www.example.com" -H "x-ext-authz: allow"

    Example output:

    HTTP/1.1 200 OK
    ...

Cleanup

You can remove the resources that you created in this guide.
kubectl delete TrafficPolicy -A -l app=ext-authz
kubectl delete gatewayextension,deployment,service -n kgateway-system -l app=ext-authz

Other configuration examples

Review other common configuration examples.

Disable passthrough auth for a specific route

Apply a passthrough auth policy at the Gateway level, then disable it for a specific HTTPRoute — for example, to exempt health-check endpoints.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: passthrough-auth-disable
  namespace: httpbin
  labels:
    app: ext-authz
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: HTTPRoute
    name: httpbin
  extAuth:
    disable: {}
EOF

Send the request body to the auth server

By default, only request headers are forwarded to the auth server. Use withRequestBody to also buffer and send the request body. Note that buffering has performance implications for streaming requests.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: passthrough-auth
  namespace: kgateway-system
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http
  extAuth:
    extensionRef:
      name: passthrough-auth
    withRequestBody:
      maxRequestBytes: 8192
EOF

Pass additional context to the auth server

Use contextExtensions to send additional key-value metadata to the auth server alongside the request. This setup is useful for passing policy identifiers or tenant information.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: passthrough-auth
  namespace: kgateway-system
spec:
  targetRefs:
  - group: gateway.networking.k8s.io
    kind: Gateway
    name: http
  extAuth:
    extensionRef:
      name: passthrough-auth
    contextExtensions:
      policy-id: "my-auth-policy"
      tenant: "team-a"
EOF

Fail open

By default, if the auth server is unavailable, requests are denied. Set failOpen: true on the GatewayExtension to allow requests through when the auth server cannot be reached. Use this option with caution.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: GatewayExtension
metadata:
  name: passthrough-auth
  namespace: kgateway-system
spec:
  type: ExtAuth
  extAuth:
    failOpen: true
    grpcService:
      backendRef:
        name: ext-authz
        port: 4444
EOF

Custom error status code

By default, the proxy returns a 403 Forbidden when the auth server denies a request. Use statusOnError on the GatewayExtension to return a different HTTP status code, such as 401 Unauthorized.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: GatewayExtension
metadata:
  name: passthrough-auth
  namespace: kgateway-system
spec:
  type: ExtAuth
  extAuth:
    statusOnError: 401
    grpcService:
      backendRef:
        name: ext-authz
        port: 4444
EOF

Custom request timeout

Set a timeout for how long the proxy waits for the auth server to respond.

kubectl apply -f - <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: GatewayExtension
metadata:
  name: passthrough-auth
  namespace: kgateway-system
spec:
  type: ExtAuth
  extAuth:
    grpcService:
      backendRef:
        name: ext-authz
        port: 4444
      requestTimeout: 5s
EOF