Cilium Gateway API Basics: Routing and Header Modifications
In this post, we’ll explore how to configure traffic routing using Kubernetes Gateway API. We’ll cover different routing techniques and header manipulation examples — all with simple, clear YAML snippets.
Jump to a section below:
- Creating an HTTPRoute for Traffic Routing
- Routing Based on Header Match
- Routing Based on Query Parameter Match
- Request Header Modifier Example (Add, Set, Remove)
- Response Header Modifier Example (Add, Set, Remove)
First, we create a new namespace called app-ns
to keep our apps separate. Next, we start two small apps called echo-1 and echo-2. These apps send a message when someone talks to them:
- echo-1 says “Hello from echo-1”
- echo-2 says “Hello from echo-2”
Each app runs one copy and listens on port 8080.
Then, we open these apps to the outside by making a Service on port 80. This lets other apps connect easily.
1
2
3
4
5
6
7
8
9
10
11
kubectl -n app-ns create namespace app-ns
kubectl -n app-ns create deployment echo-1 --image=hashicorp/http-echo --replicas=1 -- \
-text="Hello from echo-1" -listen=:8080
kubectl -n app-ns expose deployment echo-1 --port=80 --target-port=8080
kubectl -n app-ns create deployment echo-2 --image=hashicorp/http-echo --replicas=1 -- \
-text="Hello from echo-2" -listen=:8080
kubectl -n app-ns expose deployment echo-2 --port=80 --target-port=8080
In this step, we create a Gateway resource in the app-ns namespace. The Gateway is named demo-gateway
. It uses the cilium GatewayClass, which means Cilium will manage this Gateway. We define one listener that listens for HTTP traffic on port 80.
The listener allows routing only from services inside the same namespace (app-ns).
This Gateway acts like an entry point that controls how HTTP traffic comes into our cluster. It will help us test Cilium’s advanced networking features like routing and traffic management between our echo services.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
kubectl -n app-ns apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: Gateway
metadata:
name: demo-gateway
spec:
gatewayClassName: cilium
listeners:
- name: http
protocol: HTTP
port: 80
allowedRoutes:
namespaces:
from: Same
EOF
Now, let’s check the status of our gateway to see if it’s ready.
1
kubectl -n app-ns get gateway demo-gateway -o wide
We check the demo-gateway status with this command. The gateway is managed by Cilium and has been assigned the external IP address 192.168.49.20
by the load balancer. The PROGRAMMED status shows True, which means the gateway is active and ready to handle traffic. Now, we can use this IP to test routing and other features through the Cilium Gateway API.
Creating an HTTPRoute for Traffic Routing
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
kubectl -n app-ns apply -f - <<EOF
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: echo-routing
spec:
parentRefs:
- name: demo-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /echo1
backendRefs:
- name: echo-1
port: 80
- matches:
- path:
type: PathPrefix
value: /echo2
backendRefs:
- name: echo-2
port: 80
EOF
Here, we create an HTTPRoute resource named echo-routing in the app-ns namespace.
This route links to the demo-gateway we created earlier (using
parentRefs
).It defines two rules to direct HTTP traffic based on the request path:
Requests starting with
/echo1
are sent to the echo-1 service on port 80.Requests starting with
/echo2
are sent to the echo-2 service on port 80.
With this setup, the gateway will route incoming traffic to different backend services depending on the URL path. This helps us test Cilium Gateway API’s traffic routing capabilities.
First, we find the external IP address of our gateway with this command:
1
2
3
GATEWAY=$(kubectl -n app-ns get gateway demo-gateway -o jsonpath='{.status.addresses[0].value}')
echo $GATEWAY
It returns 192.168.49.20
, which is the load balancer IP where our gateway listens. Now, let’s test the routing by sending HTTP requests with curl
1
2
3
4
5
curl http://$GATEWAY/echo1
Hello from echo-1
curl http://$GATEWAY/echo2
Hello from echo-2
These results confirm that our gateway and routing rules work perfectly — traffic is correctly sent to the right service based on the URL path.
Routing Based on Header Match
In this example, we create an HTTPRoute called header-match-example in the app-ns namespace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: header-match-example
namespace: app-ns
spec:
parentRefs:
- name: demo-gateway
rules:
- matches:
- headers:
- name: X-Region
value: tr
backendRefs:
- name: echo-1
port: 80
- backendRefs:
- name: echo-2
port: 80
- The route links to our demo-gateway.
- It has two rules:
- If the incoming HTTP request has a header
X-Region
with the valuetr
, traffic is routed to echo-1. - If the header is missing or different, traffic goes to echo-2.
- If the incoming HTTP request has a header
Testing with curl
:
- Sending a request with the header
X-Region: tr
:
1
2
curl -H "X-Region: tr" http://$GATEWAY/
Hello from echo-1
- Sending a request without that header:
1
2
curl http://$GATEWAY/
Hello from echo-2
This shows how Cilium Gateway API can route traffic based on HTTP headers, enabling advanced traffic control.
Routing Based on Query Parameter Match
In this example, we create an HTTPRoute named query-param-match in the app-ns namespace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: query-param-match
namespace: app-ns
spec:
parentRefs:
- name: demo-gateway
rules:
- matches:
- queryParams:
- name: user
value: admin
backendRefs:
- name: echo-1
port: 80
- backendRefs:
- name: echo-2
port: 80
- The route connects to the demo-gateway.
- It has two rules:
- If the URL contains the query parameter
user=admin
, traffic is routed to echo-1. - For all other cases (different or missing query parameter), traffic goes to echo-2.
- If the URL contains the query parameter
Testing with curl
:
- Request with
?user=admin
:
1
2
curl "http://$GATEWAY/?user=admin"
Hello from echo-1
- Request without the user query parameter:
1
2
curl "http://$GATEWAY/"
Hello from echo-2
This demonstrates how Cilium Gateway API can route traffic based on query parameters, allowing flexible traffic control.
Request Header Modifier Example (Add, Set, Remove)
In this example, we create an HTTPRoute named request-header-mod in the app-ns namespace.
- The route is linked to the demo-gateway.
- It matches requests with the path prefix
/header-mod
. - For these requests, we apply a RequestHeaderModifier filter that:
- Adds a header
X-Debug: true
- Sets (overrides) the value of
X-User
header to"override"
if it exists - Removes the header
X-Remove-Me
if it is present
- Adds a header
- After modifying headers, the request is routed to the echo-1 service on port 80.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: request-header-mod
namespace: app-ns
spec:
parentRefs:
- name: demo-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /header-mod
filters:
- type: RequestHeaderModifier
requestHeaderModifier:
add:
- name: X-Debug
value: "true"
set:
- name: X-User
value: "override"
remove:
- X-Remove-Me
backendRefs:
- name: echo-1
port: 80
Use curl
to send requests with different headers to test the behavior:
1
curl -v -H "X-User: original" -H "X-Remove-Me: remove-this" http://$GATEWAY/header-mod
Expected behavior:
X-Debug: true
header is addedX-User
header value is changed to"override"
X-Remove-Me
header is removed
Response Header Modifier Example (Add, Set, Remove)
In this example, we create an HTTPRoute named response-header-mod in the app-ns namespace.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
apiVersion: gateway.networking.k8s.io/v1beta1
kind: HTTPRoute
metadata:
name: response-header-mod
namespace: app-ns
spec:
parentRefs:
- name: demo-gateway
rules:
- matches:
- path:
type: PathPrefix
value: /resp-header
filters:
- type: ResponseHeaderModifier
responseHeaderModifier:
add:
- name: X-Trace
value: active
set:
- name: X-Powered-By
value: cilium
remove:
- X-Remove-This
backendRefs:
- name: echo-2
port: 80
- The route matches requests with the path prefix
/resp-header
. - It is linked to the demo-gateway.
- It applies a ResponseHeaderModifier filter that:
- Adds the header
X-Trace: active
- Sets (overrides) the header
X-Powered-By
tocilium
if it exists - Removes the header
X-Remove-This
if present
- Adds the header
- Requests matching this route are sent to the echo-2 service on port 80.
When you run the command:
1
2
3
4
5
curl -i http://$GATEWAY/resp-header
...
x-powered-by: cilium
x-trace: active
along with other default headers like content-type, date, etc.
Thanks for reading! Hope this gave you a clear idea of how to use Gateway API for advanced routing.
Feel free to explore, experiment, and make it your own.
📚 If you’re curious to learn more