Configure Gateway API Routing
Purpose: For platform engineers, shows how to configure Gateway API routing for services, covering Gateway creation, HTTPRoute configuration, TLS termination, and cross-namespace references.
Prerequisites
-
Gateway API installed in cluster
-
Envoy Gateway deployed
-
cert-manager configured for TLS
-
Service deployed and accessible via ClusterIP
Steps
The examples below assume a common consumer layout where cluster-local service manifests live under applications/overlays/<cluster>/services/. If your cluster repository uses a different root, apply the same resources from the equivalent service overlay path in that repo.
1. Verify Gateway API installation
# Check Gateway API CRDs
kubectl get crd | grep gateway.networking.k8s.io
# Expected CRDs:
# gateways.gateway.networking.k8s.io
# httproutes.gateway.networking.k8s.io
# referencegrants.gateway.networking.k8s.io
# Check Envoy Gateway
kubectl get pods -n envoy-gateway-system
2. Create Gateway
Create applications/base/services/gateway-api/gateway.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: platform-gateway
namespace: envoy-gateway-system
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
spec:
gatewayClassName: envoy
listeners:
# HTTP listener (redirects to HTTPS)
- name: http
protocol: HTTP
port: 80
hostname: "*.example.com"
allowedRoutes:
namespaces:
from: All
# HTTPS listener with TLS
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
allowedRoutes:
namespaces:
from: All
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: platform-gateway-tls
namespace: envoy-gateway-system
Apply:
kubectl apply -f applications/base/services/gateway-api/gateway.yaml
Verify:
kubectl get gateway platform-gateway -n envoy-gateway-system
kubectl describe gateway platform-gateway -n envoy-gateway-system
3. Create TLS certificate
Create applications/base/services/gateway-api/certificate.yaml:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: platform-gateway-tls
namespace: envoy-gateway-system
spec:
secretName: platform-gateway-tls
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
dnsNames:
- "*.example.com"
- example.com
# For wildcard certificates, use DNS01 challenge
# For single domain, use HTTP01 challenge
Apply:
kubectl apply -f applications/base/services/gateway-api/certificate.yaml
Verify certificate issuance:
kubectl get certificate platform-gateway-tls -n envoy-gateway-system
kubectl describe certificate platform-gateway-tls -n envoy-gateway-system
# Check secret was created
kubectl get secret platform-gateway-tls -n envoy-gateway-system
4. Create HTTPRoute for service
In your cluster repo, create an HTTPRoute in the service overlay path. In the common layout used in these examples, that file is applications/overlays/<cluster>/services/my-service/httproute.yaml:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-service
namespace: my-service
spec:
parentRefs:
- name: platform-gateway
namespace: envoy-gateway-system
sectionName: https
hostnames:
- my-service.example.com
rules:
# Default route to service
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-service
port: 8080
weight: 100
Apply:
kubectl apply -f applications/overlays/<cluster>/services/my-service/httproute.yaml
5. Create ReferenceGrant for cross-namespace access
When HTTPRoute in one namespace references Gateway in another, create ReferenceGrant:
Create applications/base/services/gateway-api/referencegrant.yaml:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-httproutes-to-gateway
namespace: envoy-gateway-system
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: my-service
to:
- group: gateway.networking.k8s.io
kind: Gateway
name: platform-gateway
For multiple namespaces, use wildcard:
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: "*" # Allow all namespaces
Apply:
kubectl apply -f applications/base/services/gateway-api/referencegrant.yaml
6. Verify routing
Check HTTPRoute status:
kubectl get httproute my-service -n my-service
kubectl describe httproute my-service -n my-service
Test endpoint:
# Get Gateway external IP
GATEWAY_IP=$(kubectl get gateway platform-gateway -n envoy-gateway-system -o jsonpath='{.status.addresses[0].value}')
# Test HTTP (should redirect to HTTPS)
curl -v http://my-service.example.com --resolve my-service.example.com:80:${GATEWAY_IP}
# Test HTTPS
curl -v https://my-service.example.com --resolve my-service.example.com:443:${GATEWAY_IP}
Advanced Routing Patterns
Path-based routing
Route different paths to different services:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-routes
namespace: my-service
spec:
parentRefs:
- name: platform-gateway
namespace: envoy-gateway-system
hostnames:
- api.example.com
rules:
# Route /v1/* to v1 service
- matches:
- path:
type: PathPrefix
value: /v1
backendRefs:
- name: my-service-v1
port: 8080
# Route /v2/* to v2 service
- matches:
- path:
type: PathPrefix
value: /v2
backendRefs:
- name: my-service-v2
port: 8080
# Default route
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-service-v1
port: 8080
Header-based routing
Route based on HTTP headers:
rules:
# Route requests with specific header to canary
- matches:
- headers:
- name: X-Canary
value: "true"
backendRefs:
- name: my-service-canary
port: 8080
# Default route
- backendRefs:
- name: my-service-stable
port: 8080
Weighted traffic splitting
Canary deployment with traffic split:
rules:
- backendRefs:
# 90% to stable
- name: my-service-stable
port: 8080
weight: 90
# 10% to canary
- name: my-service-canary
port: 8080
weight: 10
Request header manipulation
Add or modify headers:
rules:
- matches:
- path:
type: PathPrefix
value: /
filters:
# Add request header
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Custom-Header
value: "custom-value"
set:
- name: X-Forwarded-Proto
value: "https"
remove:
- X-Internal-Header
backendRefs:
- name: my-service
port: 8080
URL rewriting
Rewrite request path:
rules:
- matches:
- path:
type: PathPrefix
value: /api/v1
filters:
- type: URLRewrite
urlRewrite:
path:
type: ReplacePrefixMatch
replacePrefixMatch: /v1
backendRefs:
- name: my-service
port: 8080
Request to /api/v1/users becomes /v1/users at backend.
Redirects
HTTP to HTTPS redirect:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: http-redirect
namespace: my-service
spec:
parentRefs:
- name: platform-gateway
namespace: envoy-gateway-system
sectionName: http
hostnames:
- my-service.example.com
rules:
- filters:
- type: RequestRedirect
requestRedirect:
scheme: https
statusCode: 301
Troubleshooting
HTTPRoute not working
Check HTTPRoute status:
kubectl describe httproute my-service -n my-service
Look for conditions:
- Accepted: True - Route accepted by Gateway
- ResolvedRefs: True - Backend references resolved
"Backend not found" error
Verify service exists:
kubectl get service my-service -n my-service
Check service port matches HTTPRoute:
kubectl get service my-service -n my-service -o jsonpath='{.spec.ports[0].port}'
Cross-namespace reference denied
Check ReferenceGrant exists:
kubectl get referencegrant -n envoy-gateway-system
kubectl describe referencegrant allow-httproutes-to-gateway -n envoy-gateway-system
Verify namespace matches:
kubectl get httproute my-service -n my-service -o jsonpath='{.spec.parentRefs[0].namespace}'
Verification
Complete verification checklist:
# 1. Gateway is ready
kubectl get gateway platform-gateway -n envoy-gateway-system -o jsonpath='{.status.conditions[?(@.type=="Programmed")].status}'
# Expected: True
# 2. Certificate is ready
kubectl get certificate platform-gateway-tls -n envoy-gateway-system -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}'
# Expected: True
# 3. HTTPRoute is accepted
kubectl get httproute my-service -n my-service -o jsonpath='{.status.parents[0].conditions[?(@.type=="Accepted")].status}'
# Expected: True
# 4. Service is accessible
curl -k https://my-service.example.com/health
# Expected: 200 OK