Introduction
In the complex landscape of modern microservices, managing API traffic is paramount. Beyond basic routing, organizations require sophisticated control over how clients interact with their services. Challenges like preventing abuse, ensuring fair resource allocation, and enforcing security policies often lead to the deployment of dedicated API gateways or complex Ingress controllers. While Kubernetes Ingress has long been the de facto standard for exposing services, its limitations in expressing advanced traffic management policies have become increasingly apparent. This is where the Kubernetes Gateway API steps in, offering a more expressive, extensible, and role-oriented approach to API traffic management.
The Gateway API revolutionizes how we define and apply policies to network resources. Instead of monolithic configurations, it introduces a powerful concept: Policy Attachment. This mechanism allows for the flexible attachment of policies—like rate limiting, authentication, and authorization—to various Gateway API resources such as Gateways, HTTPRoutes, or even specific hostnames and paths. This separation of concerns empowers infrastructure providers to manage the underlying network fabric, while application developers can define granular policies pertinent to their services, fostering a truly collaborative and efficient operational model.
This guide will dive deep into leveraging the Gateway API’s policy attachment capabilities to implement crucial traffic management features: rate limiting and authentication. We’ll explore how to define custom policies, attach them to your HTTPRoutes, and observe their effects in a live Kubernetes environment. By the end, you’ll have a solid understanding of how to use the Gateway API to build robust, secure, and performant API frontends, moving beyond the capabilities of traditional Ingress controllers and embracing the future of Kubernetes networking. For a comprehensive comparison and migration path, check out our Kubernetes Gateway API vs Ingress: The Complete Migration Guide.
TL;DR: Gateway API Policy Attachment for Rate Limiting & Auth
The Kubernetes Gateway API enables advanced traffic management policies like rate limiting and authentication through its flexible Policy Attachment mechanism. This guide demonstrates how to deploy a Gateway API controller (like Envoy Gateway), define custom policies, and attach them to HTTPRoutes to control access and resource consumption.
Key Commands:
- Install Envoy Gateway:
kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/main/config/install.yaml - Deploy Sample Application:
kubectl create deployment kuard --image=gcr.io/kuar-demo/kuard-amd64:1 --port=8080 kubectl expose deployment kuard --port=80 --target-port=8080 - Create Gateway & HTTPRoute:
kubectl apply -f gateway.yaml kubectl apply -f httproute.yaml - Apply RateLimit Policy:
kubectl apply -f rate-limit-policy.yaml - Apply Auth Policy:
kubectl apply -f auth-policy.yaml - Test Rate Limiting:
for i in $(seq 1 5); do curl -s -o /dev/null -w "%{http_code}\n" "$(kubectl get gtw public-gateway -o jsonpath='{.status.addresses[0].value}')"; done - Test Authentication:
curl -H "Authorization: Bearer valid-token" "$(kubectl get gtw public-gateway -o jsonpath='{.status.addresses[0].value}')" - Cleanup:
kubectl delete -f . kubectl delete -f https://raw.githubusercontent.com/envoyproxy/gateway/main/config/install.yaml
Prerequisites
Before we embark on this journey, ensure you have the following:
- A Kubernetes Cluster: Version 1.25+ is recommended for full Gateway API support. You can use Kind, Minikube, or a cloud-managed cluster (EKS, GKE, AKS).
kubectl: The Kubernetes command-line tool, configured to connect to your cluster. Refer to the official Kubernetes documentation for installation instructions.- Basic understanding of Kubernetes concepts: Pods, Services, Deployments, and Networking.
- Familiarity with Gateway API concepts: GatewayClasses, Gateways, and HTTPRoutes. If you’re new to Gateway API, our Gateway API Migration Guide is an excellent starting point.
curl: For testing our endpoints.
Step-by-Step Guide
1. Install a Gateway API Controller (Envoy Gateway)
The Gateway API is a set of CRDs (Custom Resource Definitions); it requires an implementation, or “controller,” to make it functional. For this guide, we’ll use Envoy Gateway, a popular open-source implementation based on the high-performance Envoy proxy. Envoy Gateway provides a straightforward way to deploy and manage Envoy as a Gateway API ingress controller.
First, we’ll install Envoy Gateway, which will deploy the necessary Gateway API CRDs, the Envoy Gateway controller, and the Envoy proxy itself. This process typically takes a few minutes, as it involves pulling container images and setting up deployments and services.
kubectl apply -f https://raw.githubusercontent.com/envoyproxy/gateway/main/config/install.yaml
Verify:
Check if the Envoy Gateway pods are running and healthy. You should see pods in the envoy-gateway-system namespace, including the controller and Envoy proxy.
kubectl get pods -n envoy-gateway-system
kubectl get gatewayclass
Expected Output:
NAME READY STATUS RESTARTS AGE
envoy-gateway-7b8c8d8c9f-abcde 1/1 Running 0 2m
envoy-7c7c7c7c7c-fghij 1/1 Running 0 1m
NAME CONTROLLER ACCEPTED AGE
envoy gateway.envoyproxy.io/gateway True 2m
2. Deploy a Sample Application
To demonstrate rate limiting and authentication, we need a simple application to expose. We’ll use kuard, a demonstration application from Google, which is perfect for testing. We’ll deploy it and expose it via a Kubernetes Service.
First, create a deployment for kuard. Then, expose it using a ClusterIP Service. This service will be the backend for our Gateway API HTTPRoute.
kubectl create deployment kuard --image=gcr.io/kuar-demo/kuard-amd64:1 --port=8080
kubectl expose deployment kuard --port=80 --target-port=8080
Verify:
Ensure the deployment and service are up and running in the default namespace.
kubectl get deployment kuard
kubectl get service kuard
Expected Output:
NAME READY UP-TO-DATE AVAILABLE AGE
kuard 1/1 1 1 30s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kuard ClusterIP 10.96.10.XX <none> 80/TCP 25s
3. Create a Gateway and HTTPRoute
Now, let’s define our Gateway API resources. The Gateway resource represents the entry point for traffic into your cluster, similar to an Ingress controller. The HTTPRoute defines how HTTP traffic is routed from the Gateway to your backend services.
We’ll create a Gateway that listens on port 80 and an HTTPRoute that matches all traffic to a specific hostname (e.g., example.com) and forwards it to our kuard service.
# gateway.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public-gateway
spec:
gatewayClassName: envoy
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: All
# httproute.yaml
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: kuard-route
spec:
parentRefs:
- name: public-gateway
hostnames:
- "example.com"
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: kuard
port: 80
Apply these configurations:
kubectl apply -f gateway.yaml
kubectl apply -f httproute.yaml
Verify:
Check the status of your Gateway and HTTPRoute. The Gateway should have an assigned IP address (if running on a cloud provider) or a hostname (if using a local setup with a LoadBalancer service). The HTTPRoute should be accepted and attached to the Gateway.
kubectl get gateway public-gateway
kubectl get httproute kuard-route
Expected Output:
NAME CLASS ADDRESS READY AGE
public-gateway envoy XXX.XXX.XXX.XXX True 1m
NAME HOSTNAMES PARENTREFS AGE
kuard-route ["example.com"] ["Gateway/public-gateway"] 1m
Get the Gateway’s external IP/hostname:
GATEWAY_IP=$(kubectl get gtw public-gateway -o jsonpath='{.status.addresses[0].value}')
echo $GATEWAY_IP
Test the route:
curl -H "Host: example.com" http://$GATEWAY_IP
You should see the HTML output from the kuard application.
4. Implement Rate Limiting with Policy Attachment
Rate limiting is a critical policy for preventing abuse, ensuring fair resource usage, and protecting your backend services from being overwhelmed. With Gateway API, we can define a RateLimitPolicy and attach it to our HTTPRoute. Envoy Gateway implements this using its custom RateLimitPolicy CRD.
This policy will limit requests to 2 requests per minute from the same source IP. This is a common way to manage traffic, though more sophisticated policies can be built based on headers, JWT claims, etc.
# rate-limit-policy.yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: RateLimitPolicy
metadata:
name: kuard-rate-limit
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: kuard-route
global:
rules:
- limit: 2
interval: 60s
type:
# Define a rate limit based on the source IP address
# This will limit requests from a single client IP.
sourceRemoteIP: {}
Apply the rate limit policy:
kubectl apply -f rate-limit-policy.yaml
Verify:
Check the status of the RateLimitPolicy. It should show as accepted and attached. Then, try to send more requests than allowed within the interval.
kubectl get ratelimitpolicy kuard-rate-limit
Expected Output:
NAME AGE
kuard-rate-limit 10s
Now, test the rate limit. Replace $GATEWAY_IP with the actual IP from the previous step:
GATEWAY_IP=$(kubectl get gtw public-gateway -o jsonpath='{.status.addresses[0].value}')
for i in $(seq 1 5); do curl -s -o /dev/null -w "%{http_code}\n" -H "Host: example.com" http://$GATEWAY_IP; sleep 1; done
Expected Output:
200
200
429
429
429
You should see the first two requests succeed (HTTP 200), and subsequent requests within the 60-second window should return HTTP 429 (Too Many Requests).
5. Implement Authentication with Policy Attachment
Authentication is another crucial aspect of securing your APIs. The Gateway API, through implementations like Envoy Gateway, supports various authentication methods. Here, we’ll demonstrate External Authentication, where the Envoy proxy forwards authentication requests to an external service. This is a common pattern for integrating with existing identity providers or custom authentication logic.
We’ll deploy a simple mock authentication service that accepts a specific “valid-token” and rejects others. Then, we’ll create an AuthenticationPolicy to integrate it.
First, deploy a mock external authentication service:
# auth-service.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: auth-service
spec:
replicas: 1
selector:
matchLabels:
app: auth-service
template:
metadata:
labels:
app: auth-service
spec:
containers:
- name: auth-service
image: nginxdemos/hello:plain-text # A simple service that can be configured to act as an auth server
ports:
- containerPort: 80
env:
- name: MESSAGE
value: "Auth service running" # Placeholder, in a real scenario this would be a dedicated auth app
---
apiVersion: v1
kind: Service
metadata:
name: auth-service
spec:
selector:
app: auth-service
ports:
- protocol: TCP
port: 80
targetPort: 80
Note: A real external auth service would typically be a custom application that validates tokens/credentials and returns specific HTTP status codes (e.g., 200 for success, 401 for unauthorized). For this demo, we’ll configure the policy to look for a specific header from the client.
Apply the auth service:
kubectl apply -f auth-service.yaml
Now, define the AuthenticationPolicy. This example uses a simple header-based check, but more complex scenarios (e.g., JWT validation, OIDC) are supported by various Gateway API implementations. Here, we’ll configure Envoy Gateway to check for an Authorization: Bearer valid-token header.
# auth-policy.yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: AuthenticationPolicy
metadata:
name: kuard-auth
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: kuard-route
jwt:
- jwtProviders:
# This is a simplified example. In a real scenario, you'd integrate with a JWT provider (e.g., Auth0, Keycloak)
# and provide JWKS URI for public key fetching.
# For this demo, we'll simulate a JWT check using a static secret.
# A more robust external auth solution is usually preferred for production.
- name: demo-provider
issuer: "https://example.com/auth"
audiences: ["kuard-app"]
# In a real scenario, jwks.remote would point to your IdP's JWKS endpoint.
# For a direct token check, this might involve an external auth service.
# For simplicity, we'll use a placeholder and demonstrate the policy attachment.
# Envoy Gateway's JWT policy typically validates the token structure and signature.
# For raw token validation, an external auth service is more common.
# Let's adjust this to use an external service for granular control.
# Reverting to an external auth service for broader applicability.
# --- Alternative: External Authentication (more flexible for custom logic) ---
# Let's use external authentication, as it's more versatile for custom token validation.
# This will forward the request to our dummy 'auth-service'.
# The 'auth-service' will need to return HTTP 200 for success and other codes for failure.
externalRef:
name: auth-service
port: 80
failRequest: true # If the auth service fails or returns non-200, the request is denied.
# We can also add context to forward headers if needed.
# request:
# headers:
# - name: X-Auth-Request-Redirect
# value: "true"
# allowedRequestHeaders:
# - Authorization
# allowedResponseHeaders:
# - X-Auth-User
# - X-Auth-Email
Note: The AuthenticationPolicy CRD for Envoy Gateway has evolved. The above YAML provides a conceptual framework for external authentication. For a real external auth service, you’d typically have a service that processes the incoming request (e.g., checks the Authorization header) and returns a 200 OK for success or a 401/403 for failure. Envoy Gateway would then enforce this. In this simplified demo, we’ll rely on the policy attaching and the external service being present. For a robust setup, consider implementing a proper external auth server.
Let’s refine the external authentication demonstration for clarity. Instead of a generic `nginxdemos/hello`, we’ll assume a truly minimal external auth service that responds with 200 for a specific `Authorization` header and 401 otherwise.
First, let’s update our `auth-service.yaml` to be more explicit about its mock authentication behavior, even if the image itself is simple.
For a truly functional demo without building a custom auth server, we can rely on Envoy’s built-in JWT capabilities or use a more sophisticated external auth service. Given the constraints of a simple demo, simulating an external auth service’s behavior with a placeholder is common.
Let’s simplify the `AuthenticationPolicy` for the demo, assuming a real external auth service behind `auth-service`.
# auth-policy.yaml
apiVersion: gateway.envoyproxy.io/v1alpha1
kind: AuthenticationPolicy
metadata:
name: kuard-auth
spec:
targetRef:
group: gateway.networking.k8s.io
kind: HTTPRoute
name: kuard-route
externalRef:
name: auth-service
port: 80
failRequest: true # If the auth service returns non-2xx, the request is denied.
# The external auth service will receive the original request headers,
# including 'Authorization' and should respond with 200 for success.
# For this demo, let's assume 'auth-service' would validate the 'Authorization' header.
# In a real scenario, you'd have an actual auth microservice here.
Apply the authentication policy:
kubectl apply -f auth-policy.yaml
Verify:
Check the status of the AuthenticationPolicy. It should show as accepted. Then, try accessing the service with and without the expected authentication header.
kubectl get authenticationpolicy kuard-auth
Expected Output:
NAME AGE
kuard-auth 10s
Now, test the authentication. Replace $GATEWAY_IP with the actual IP from the previous step:
GATEWAY_IP=$(kubectl get gtw public-gateway -o jsonpath='{.status.addresses[0].value}')
# Attempt without authorization header (should fail)
curl -s -o /dev/null -w "%{http_code}\n" -H "Host: example.com" http://$GATEWAY_IP
# Attempt with a 'valid' token (should succeed, assuming auth-service validates this)
# Note: For the actual `nginxdemos/hello` image, it will always return 200,
# so this external auth setup primarily demonstrates the *attachment* mechanism.
# A real external auth service would return 401/403 for invalid tokens.
# To simulate failure, we'd need a more sophisticated auth service or policy.
curl -s -o /dev/null -w "%{http_code}\n" -H "Host: example.com" -H "Authorization: Bearer valid-token" http://$GATEWAY_IP
Expected Output (with a real auth service that processes the header):
401 # Or 403, depending on auth service
200
Due to the simplicity of the `nginxdemos/hello` image, the external authentication will pass all requests through to the backend, as the `auth-service` always returns 200. To truly demonstrate authentication failure, you would need to replace `nginxdemos/hello` with an actual authentication microservice that inspects the `Authorization` header and returns a non-200 status code for invalid tokens. The above demonstrates the policy attachment.
Production Considerations
Implementing rate limiting and authentication in production requires careful planning beyond basic policy attachment.
- Robust External Authentication Service: For authentication, relying on a simple mock service is insufficient. In production, your external authentication service should integrate with your identity provider (e.g., OAuth 2.0, OpenID Connect), perform proper token validation (JWT signature, expiration, issuer, audience), and handle refresh tokens. Consider using open-source solutions like Keycloak or commercial identity platforms.
- Advanced Rate Limiting Strategies: Source IP is a good start, but production systems often require more sophisticated rate limiting based on authenticated user IDs, API keys, specific HTTP headers, or even combinations of these. Envoy Gateway’s
RateLimitPolicyallows for custom dimensions, enabling highly granular control. - Observability and Monitoring: Ensure your Gateway API implementation and attached policies are well-monitored. Collect metrics on rate limit hits, authentication successes/failures, and latency. Tools like Prometheus and Grafana are essential. If using Cilium (which often integrates well with Gateway API), consider eBPF Observability with Hubble for deep network insights.
- Policy Hierarchy and Overrides: Understand how policies are applied when multiple policies target the same resource or when policies are attached at different levels (e.g., Gateway, HTTPRoute, Namespace). Gateway API implementations define precedence rules, which are crucial for predictable behavior.
- Security Best Practices: Always use HTTPS for all external traffic. Ensure your external authentication service is highly available and secured itself. Implement Kubernetes Network Policies to restrict traffic between your services and the authentication service.
- Scalability and Resilience: Your Gateway API controller (e.g., Envoy Gateway) must be able to scale horizontally to handle peak traffic. Ensure its underlying Envoy proxies are configured with appropriate resource limits and requests.
- Testing: Thoroughly test your rate limiting and authentication policies under various load conditions and failure scenarios. Automated testing should cover edge cases and ensure policies behave as expected.
- GitOps Integration: Manage your Gateway API resources and policies using GitOps principles. Store all configurations in a Git repository and use tools like Argo CD or Flux CD for automated deployment and synchronization.
- Integration with Service Mesh: For advanced traffic management and security within the cluster, consider integrating Gateway API with a service mesh like Istio Ambient Mesh. Gateway API handles north-south traffic (external to cluster), while a service mesh manages east-west traffic (internal cluster traffic).
Troubleshooting
Here are some common issues you might encounter and their solutions:
-
Gateway IP Address Not Available:
Issue: The
Gatewayresource’s status does not show an external IP address or hostname.Solution:
- Ensure your Kubernetes cluster has a LoadBalancer implementation (e.g., a cloud provider’s LoadBalancer controller or MetalLB for on-prem).
- Check the logs of the Envoy Gateway controller pod in
envoy-gateway-systemfor errors related to service creation or LoadBalancer provisioning. - Verify the GatewayClass is correctly configured and referenced:
kubectl get gatewayclass envoy -o yaml
-
HTTPRoute Not Attaching to Gateway:
Issue: The
HTTPRoutestatus showsAccepted: falseor does not list the Gateway in itsparentRefsstatus.Solution:
- Verify the
parentRefsin theHTTPRoutecorrectly reference the Gateway by name. - Check the
allowedRoutesconfiguration in the Gateway spec. Iffrom: SameNamespaceis used, ensure the HTTPRoute is in the same namespace as the Gateway. We usedfrom: Allin this guide, which is more permissive. - Inspect the events of the HTTPRoute:
kubectl describe httproute kuard-routefor specific error messages.
- Verify the
-
Rate Limiting Not Working:
Issue: Requests are not being rate-limited, even after applying the
RateLimitPolicy.Solution:
- Ensure the
RateLimitPolicy‘stargetRefcorrectly points to theHTTPRoute(or other Gateway API resource). - Check the status of the
RateLimitPolicy:kubectl get ratelimitpolicy kuard-rate-limit -o yaml. Look for any conditions indicating errors.
- Verify the Envoy Gateway controller logs for any policy application errors.
- Confirm that traffic is indeed flowing through the Envoy Gateway. If you’re hitting the service directly, rate limiting won’t apply.
- Ensure the
-
Authentication Not Working (Always 200 or Always 401):
Issue: The authentication policy is not enforcing as expected; either all requests pass, or all requests fail.
Solution:
- All requests pass: If using an external auth service, ensure it’s configured to return non-2xx status codes for unauthorized requests. Our demo
nginxdemos/helloservice will always return 200, bypassing the auth check. You need a proper auth service. - All requests fail:
- Check the external auth service logs for errors.
- Verify the
externalRefin theAuthenticationPolicy(service name and port) is correct and the service is reachable. - Ensure the
failRequest: trueis set if you want unauthorized requests to be blocked by the Gateway. - If using JWT, double-check the issuer, audience, and JWKS URI configuration.
- Inspect the events of the
AuthenticationPolicyfor clues:kubectl describe authenticationpolicy kuard-auth
- All requests pass: If using an external auth service, ensure it’s configured to return non-2xx status codes for unauthorized requests. Our demo
-
Policy Not Applying (Generic):
Issue: Any policy (rate limit, auth) seems to be ignored or not taking effect.
Solution:
- Check CRD existence: Ensure the CRDs for
RateLimitPolicyandAuthenticationPolicy(if using Envoy Gateway’s specific CRDs) are installed:kubectl get crd | grep policy - Controller Logs: The most valuable source of information is always the controller’s logs:
kubectl logs -n envoy-gateway-system -l app.kubernetes.io/component=controller - Policy TargetRef: Double-check that the
targetRefin your policy YAML (group, kind, name) exactly matches the resource it’s supposed to attach to. - API Version: Ensure you’re using the correct API version for the policies (e.g.,
gateway.envoyproxy.io/v1alpha1).
- Check CRD existence: Ensure the CRDs for
FAQ Section
-
What is the difference between Gateway API and Ingress?
The Kubernetes Gateway API is a successor to Ingress, offering a more expressive, extensible, and role-oriented approach to API traffic management. It separates concerns between infrastructure providers (managing Gateways) and application developers (managing HTTPRoutes). Ingress is simpler but often requires vendor-specific annotations for advanced features, leading to less portability.
-
Can I use other Gateway API implementations instead of Envoy Gateway?
Yes! The Gateway API is a specification, and many implementations exist, including Istio, Contour, Kong, Nginx Gateway Fabric, and others. While the core Gateway API resources (Gateway, HTTPRoute) are standard, the custom policy resources (like
RateLimitPolicyorAuthenticationPolicy) are often implementation-specific. Always refer to the documentation of your chosen Gateway API implementation for policy CRD details. -
Where can I attach policies in Gateway API?
Policies can be attached to various Gateway API resources depending on the policy type and implementation. Common attachment points include:
- GatewayClass: For cluster-wide default policies.
- Gateway: For policies applying to all traffic entering a specific Gateway.
- HTTPRoute (or other Route types): For policies specific to a hostname, path, or service.
- Service (BackendRef): Some policies can even apply to target backends.
The flexibility of policy attachment is a core strength of the Gateway API.
-
How do I handle complex authentication scenarios like OAuth/OIDC?
For complex authentication flows like OAuth 2.0 or OpenID Connect, you typically integrate an external authentication service. This service acts as an intermediary, handling the redirect to the identity provider, token exchange, and validation. The Gateway API’s
AuthenticationPolicy(viaexternalRef) then directs traffic to this service. Some Gateway API implementations might also offer built-in JWT validation capabilities, reducing the need for a separate service for