API key auth

API keys are secure, long-lived UUIDs that clients provide when they send a request to your service. You might use API keys in the following scenarios:

  • You know the set of users that need access to your service. These users do not change often, or you have automation that easily generates or deletes the API key when the users do change.
  • You want direct control over how the credentials are generated and expire.
⚠️
When you use API keys, your services are only as secure as the API keys. Storing and rotating the API key securely is up to the user.

API key auth in kgateway

The kgateway proxy comes with built-in API key auth support via the TrafficPolicy resource. To secure your services with API keys, first provide your kgateway proxy with your API keys in the form of Kubernetes secrets. Then in the TrafficPolicy resource, you refer to the secrets in one of two ways.

  • Specify a label selector that matches the label of one or more API key secrets. Labels are the more flexible, scalable approach.
  • Refer to the name and namespace of each secret.

The proxy matches a request to a route that is secured by the external auth policy. The request must have a valid API key in the api-key header to be accepted. You can configure the name of the expected header. If the header is missing, or the API key is invalid, the proxy denies the request and returns a 401 response.

The following diagram illustrates the flow:

  sequenceDiagram
    participant C as Client / Agent
    participant AGW as Kgateway Proxy
    participant K8s as K8s Secrets<br/>(API Keys)
    participant Backend as Backend

    C->>AGW: POST /api<br/>(no api-key header)

    AGW->>AGW: API key auth check:<br/>No API key found

    AGW-->>C: 401 Unauthorized<br/>"no API Key found"

    Note over C,Backend: Retry with API key

    C->>AGW: POST /api<br/>api-key: Bearer N2YwMDIx...

    AGW->>K8s: Lookup referenced secret<br/>(by name or label selector)
    K8s-->>AGW: Secret found

    AGW->>AGW: Compare API key from<br/>request header vs secret

    alt mode: Strict — Key valid
        AGW->>Backend: Forward request
        Backend-->>AGW: Response
        AGW-->>C: 200 OK + Response
    else Key invalid or missing
        AGW-->>C: 401 Unauthorized
    end

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

Set up API key auth

Store your API keys in a Kubernetes secret so that you can reference it in an TrafficPolicy resource.

  1. From your API management tool, generate an API key. The examples in this guide use N2YwMDIxZTEtNGUzNS1jNzgzLTRkYjAtYjE2YzRkZGVmNjcy.

  2. Create a Kubernetes secret to store your API key.

    kubectl apply -f - <<EOF
    apiVersion: v1
    kind: Secret
    metadata:
      name: apikey
      namespace: kgateway-system
      labels:
        app: httpbin
    type: extauth.solo.io/apikey
    stringData:
      api-key: N2YwMDIxZTEtNGUzNS1jNzgzLTRkYjAtYjE2YzRkZGVmNjcy
    EOF
  3. Verify that the secret is created. Note that the data.api-key value is base64 encoded.

    kubectl get secret apikey -n kgateway-system -o yaml
  4. Create an TrafficPolicy resource that configures API key authentication for all routes that the Gateway serves and reference the apikey secret that you created earlier. The following example uses the Strict validation mode, which requires requests to include a valid Authorization header to be authenticated successfully. For other common configuration examples, see Other configuration examples.

    kubectl apply -f- <<EOF
    apiVersion: gateway.kgateway.dev/v1alpha1
    kind: TrafficPolicy
    metadata:
      name: apikey-auth
      namespace: kgateway-system
    spec:
      targetRefs:
        - group: gateway.networking.k8s.io
          kind: Gateway
          name: http
      apiKeyAuth:
        secretRef:
          name: apikey
    EOF
  5. Send a request to the httpbin app without an API key. Verify that the request fails with a 401 HTTP response code.

    curl -vi "${INGRESS_GW_ADDRESS}:8080/headers" -H "host: www.example.com"                                  
    curl -vi "localhost:8080/headers" -H "host: www.example.com" 

    Example output:

    ...
    < HTTP/1.1 401 Unauthorized
    HTTP/1.1 401 Unauthorized
    
    Client authentication failed   
    ...
  6. Repeat the request. This time, you provide a valid API key in the Authorization header. Verify that the request now succeeds.

    curl -vi "${INGRESS_GW_ADDRESS}:8080/headers" \
    -H "host: www.example.com" \
    -H "api-key: Bearer N2YwMDIxZTEtNGUzNS1jNzgzLTRkYjAtYjE2YzRkZGVmNjcy"                                 
    curl -vi "localhost:8080/headers" \
    -H "host: www.example.com" \
    -H "api-key: Bearer N2YwMDIxZTEtNGUzNS1jNzgzLTRkYjAtYjE2YzRkZGVmNjcy"  

    Example output:

    ...
    HTTP/1.1 200 OK
    < access-control-allow-credentials: true
    access-control-allow-credentials: true
    < access-control-allow-origin: *
    access-control-allow-origin: *
    < content-type: application/json; encoding=utf-8
    content-type: application/json; encoding=utf-8
    < content-length: 441
    content-length: 441
    < x-envoy-upstream-service-time: 13
    x-envoy-upstream-service-time: 13
    < server: envoy
    server: envoy
    
    {
     "headers": {
       "Accept": [
         "*/*"
       ],
       "Host": [
         "www.example.com"
       ],
       "User-Agent": [
         "curl/8.7.1"
       ],
       "X-Envoy-Expected-Rq-Timeout-Ms": [
         "15000"
       ],
       "X-Envoy-External-Address": [
         "127.0.0.1"
       ],
       "X-Forwarded-For": [
         "10.244.0.18"
       ],
       "X-Forwarded-Proto": [
         "http"
       ],
       "X-Request-Id": [
         "f64f1efa-1288-47d8-921f-4cb8f8deb96c"
       ]
     }
    }
    ...
    

Cleanup

You can remove the resources that you created in this guide.
kubectl delete TrafficPolicy apikey-auth -n kgateway-system
kubectl delete secret apikey -n kgateway-system

Other configuration examples

Review other common configuration examples.

Label selectors

Refer to your API key secrets by using label selectors.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: http
  apiKeyAuth:
    secretSelector:
      matchLabels:
        app: httpbin
EOF

Custom header name

By default, kgateway reads the API key from the api-key header. Use keySources to specify a different header name.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: http
  apiKeyAuth:
    secretRef:
      name: apikey
    keySources:
      - header: X-API-KEY
EOF

Multiple key sources

Configure multiple key sources. The gateway proxy checks them in order. If you define different types of key sources, the precedence is determined as follows:

  • Header key sources take precedence over query parameter
  • Query parameter key sources take precedence over cookie key sources
kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: http
  apiKeyAuth:
    secretRef:
      name: apikey
    keySources:
      - header: X-API-KEY
      - query: api_key
      - cookie: auth_token
EOF

Forward client ID header

Use clientIdHeader to forward the authenticated client identifier to the upstream service in a request header. This setup is useful for passing caller identity to backend services.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: http
  apiKeyAuth:
    secretRef:
      name: apikey
    clientIdHeader: x-client-id
EOF

Forward credential to upstream

By default, the API key is stripped from the request before it is forwarded to the upstream. Set forwardCredential: true to preserve the API key in the upstream request.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: Gateway
      name: http
  apiKeyAuth:
    secretRef:
      name: apikey
    forwardCredential: true
EOF

Disable API key auth

Use disable to override an API key auth policy that is applied at a higher level in the hierarchy, such as a gateway-level policy, for a specific route.

kubectl apply -f- <<EOF
apiVersion: gateway.kgateway.dev/v1alpha1
kind: TrafficPolicy
metadata:
  name: apikey-auth-disable
  namespace: kgateway-system
spec:
  targetRefs:
    - group: gateway.networking.k8s.io
      kind: HTTPRoute
      name: httpbin
  apiKeyAuth:
    disable: {}
EOF