Request headers
Use the RequestHeaderModifier filter to add, append, overwrite, or remove request headers for a specific route.
For more information, see the HTTPHeaderFilter specification.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Follow the Sample app guide to create a gateway proxy with an HTTP listener and deploy the httpbin sample app.
-
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_ADDRESSkubectl port-forward deployment/http -n kgateway-system 8080:8080
Add and append request headers
Add headers to incoming requests before they are forwarded to an upstream service. If the request already has the header set, the value of the header in the RequestHeaderModifier filter is appended to the value of the header in the request.
-
Set up a header modifier that adds a
my-header: hellorequest header. Choose between the HTTPRoute for a Gateway API-native way, or TrafficPolicy for more flexible attachment options such as a gateway-level policy.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - filters: - type: RequestHeaderModifier requestHeaderModifier: add: - name: my-header value: hello backendRefs: - name: httpbin port: 8000 EOFSetting Description spec.parentRefsThe name and namespace of the gateway that serves this HTTPRoute. In this example, you use the httpGateway that was created as part of the get started guide.spec.rules.filters.typeThe type of filter that you want to apply to incoming requests. In this example, the RequestHeaderModifierfilter is used.spec.rules.filters.requestHeaderModifier.addThe name and value of the request header that you want to add. spec.rules.backendRefsThe backend destination you want to forward traffic to. In this example, all traffic is forwarded to the httpbin app that you set up as part of the get started guide. Note: The steps in this section use the Envoy-based kgateway data plane. The steps do not work with the agentgateway data plane.
-
Create an HTTPRoute resource for the route that you want to modify. Note that the example selects the http Gateway that you created before you began.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - backendRefs: - name: httpbin port: 8000 EOF -
Create a TrafficPolicy that adds a
my-header: helloheader to a request. The following example attaches the TrafficPolicy to the http Gateway.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: httpbin-headers namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http headerModifiers: request: add: - name: my-header value: hello EOF
-
-
Send a request to the httpbin app on the
headers.exampledomain and verify that you get back a 200 HTTP response code and that you see themy-headerrequest header.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080"curl -vi localhost:8080/headers -H "host: headers.example"Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19* Mark bundle as not supporting multiuse < HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "My-Header": [ "hello" ], "User-Agent": [ "curl/7.77.0" ], ... -
Send another request to the httpbin app. This time, you already include the
my-headerheader in your request. Verify that you get back a 200 HTTP response code and that yourmy-headerheader value is appended with the value from theRequestHeaderModifierfilter.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080" \ -H "my-header: foo"curl -vi localhost:8080/headers -H "host: headers.example" \ -H "my-header: foo"Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17* Mark bundle as not supporting multiuse < HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "My-Header": [ "foo", "hello" ], ... -
Optional: Remove the resources that you created.
kubectl delete httproute httpbin-headers -n httpbinkubectl delete httproute httpbin-headers -n httpbin kubectl delete TrafficPolicy httpbin-headers -n kgateway-system
Set request headers
Setting headers is similar to adding headers. If the request does not include the header, it is added by the RequestHeaderModifier filter. However, if the request already contains the header, its value is overwritten with the value from the RequestHeaderModifier filter.
-
Set up a header modifier that sets a
my-header: hellorequest header. Choose between the HTTPRoute for a Gateway API-native way, or TrafficPolicy for more flexible attachment options such as a gateway-level policy.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - filters: - type: RequestHeaderModifier requestHeaderModifier: set: - name: my-header value: hello backendRefs: - name: httpbin port: 8000 EOFSetting Description spec.parentRefsThe name and namespace of the gateway that serves this HTTPRoute. In this example, you use the httpGateway that was created as part of the get started guide.spec.rules.filters.typeThe type of filter that you want to apply to incoming requests. In this example, the RequestHeaderModifierfilter is used.spec.rules.filters.requestHeaderModifier.setThe name and value of the request header that you want to set. spec.rules.backendRefsThe Kubernetes service you want to forward traffic to. In this example, all traffic is forwarded to the httpbin app that you set up as part of the get started guide. Note: The steps in this section use the Envoy-based kgateway data plane. The steps do not work with the agentgateway data plane.
-
Create an HTTPRoute resource for the route that you want to modify. Note that the example selects the http Gateway that you created before you began.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - backendRefs: - name: httpbin port: 8000 EOF -
Create a TrafficPolicy that sets the
my-headerheader value tohelloon a request. The following example attaches the TrafficPolicy to the http Gateway.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: httpbin-headers namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http headerModifiers: request: set: - name: my-header value: hello EOF
-
-
Send a request to the httpbin app on the
headers.exampledomain. Verify that you get back a 200 HTTP response code and that themy-header: helloheader was added.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080"curl -vi localhost:8080/headers -H "host: headers.example"Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19* Mark bundle as not supporting multiuse < HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "My-Header": [ "hello" ], "User-Agent": [ "curl/7.77.0" ], ... -
Send another request to the httpbin app. This time, you already include the
my-headerheader in your request. Verify that you get back a 200 HTTP response code and that yourmy-headerheader value is overwritten with the value from theRequestHeaderModifierfilter.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080" \ -H "my-header: foo"curl -vi localhost:8080/headers -H "host: headers.example" \ -H "my-header: foo"Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16* Mark bundle as not supporting multiuse < HTTP/1.1 200 OK HTTP/1.1 200 OK ... { "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "My-Header": [ "hello" ], ... -
Optional: Remove the resources that you created.
kubectl delete httproute httpbin-headers -n httpbinkubectl delete httproute httpbin-headers -n httpbin kubectl delete TrafficPolicy httpbin-headers -n kgateway-system
Remove request headers
You can remove HTTP headers from a request before the request is forwarded to the target service in the cluster.
-
Send a request to the httpbin app and find the
User-Agentheader.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: www.example.com:8080"curl -vi localhost:8080/headers -H "host: www.example.com"Example output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23... { "headers": { "Accept": [ "*/*" ], "Host": [ "www.example.com:8080" ], "User-Agent": [ "curl/7.77.0" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "5b14c790-3870-4f73-a12e-4cba9a7eccd7" ] } } -
Set up a header modifier that removes the
User-Agentheader when requests are sent to theheaders.exampledomain. Choose between the HTTPRoute for a Gateway API-native way, or TrafficPolicy for more flexible attachment options such as a gateway-level policy.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - filters: - type: RequestHeaderModifier requestHeaderModifier: remove: - User-Agent backendRefs: - name: httpbin port: 8000 EOFSetting Description spec.parentRefsThe name and namespace of the gateway that serves this HTTPRoute. In this example, you use the httpGateway that was created as part of the get started guide.spec.rules.filters.typeThe type of filter that you want to apply to incoming requests. In this example, the RequestHeaderModifierfilter is used.spec.rules.filters.requestHeaderModifier.removeThe name of the request header that you want to remove. spec.rules.backendRefsThe backend destination you want to forward traffic to. In this example, all traffic is forwarded to the httpbin app that you set up as part of the get started guide. Note: The steps in this section use the Envoy-based kgateway data plane. The steps do not work with the agentgateway data plane.
-
Create an HTTPRoute resource for the route that you want to modify. Note that the example selects the http Gateway that you created before you began.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - backendRefs: - name: httpbin port: 8000 EOF -
Create a TrafficPolicy that removes the
User-Agentheader from a request. The following example attaches the TrafficPolicy to the http Gateway.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: httpbin-headers namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http headerModifiers: request: remove: - User-Agent EOF
-
-
Send a request to the httpbin app on the
headers.exampledomain . Verify that theUser-Agentrequest header is removed.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080"curl -vi localhost:8080/headers -H "host: headers.example"Example output:
{ "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "f83bb750-67f7-47dc-8c79-4a582892034c" ] } } -
Optional: Clean up the resources that you created.
kubectl delete httproute httpbin-headers -n httpbinkubectl delete httproute httpbin-headers -n httpbin kubectl delete TrafficPolicy httpbin-headers -n kgateway-system
Source a header value from a Secret
If the header value is sensitive, such as a backend API key or a tenant credential, you might not want to commit it to a manifest in plain text or send it as part of the request. You can source a request header value from a Kubernetes Secret by replacing value with secretRef in the TrafficPolicy resource. The gateway proxy resolves the Secret at translation time, so the value never appears in the policy spec. If the Secret changes later, the proxy applies the changes automatically.
HTTPRoute RequestHeaderModifier filter does not support the secretRef option.-
Create a Secret that holds the values you want to inject. The data keys do not need to match the eventual header names.
kubectl apply -f- <<EOF apiVersion: v1 kind: Secret metadata: name: backend-creds namespace: kgateway-system type: Opaque stringData: api-key: my-secret-api-key tenant-id: tenant-abc EOF -
Create an HTTPRoute for the httpbin app. The example selects the http Gateway that you created before you began.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - backendRefs: - name: httpbin port: 8000 EOF -
Create the TrafficPolicy resource that sets two request header values from keys that you stored in the
backend-credsSecret. The following example attaches the TrafficPolicy to the http Gateway.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: httpbin-secret-headers namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http headerModifiers: request: set: - name: X-Api-Key secretRef: name: backend-creds key: api-key - name: X-Tenant-Id secretRef: name: backend-creds key: tenant-id EOFSetting Description headerModifiers.request.set.nameThe HTTP header name that the upstream service receives. headerModifiers.request.set.secretRef.nameThe name of the Kubernetes Secret to read the value from. If the Secret does not exist when the policy is applied, the policy reports Accepted=Falseand the affected route returns a 500 response.headerModifiers.request.set.secretRef.keyThe key in the Secret’s datato use as the header value. Optional. Ifkeyis omitted, it defaults to the value ofheaderModifiers.request.set.name.headerModifiers.request.set.secretRef.namespaceThe namespace of the Secret. Optional. If namespaceis omitted, it defaults to the namespace of the TrafficPolicy. -
Send a request to the httpbin app on the
headers.exampledomain and confirm that the upstream sees theX-Api-KeyandX-Tenant-Idheaders with the values from the Secret. Note that the values do not appear in the TrafficPolicy or in the request you sent.
curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080"curl -vi localhost:8080/headers -H "host: headers.example"Example output:
{
"headers": {
"Host": [
"headers.example:8080"
],
"X-Api-Key": [
"my-secret-api-key"
],
"X-Tenant-Id": [
"tenant-abc"
],
...
}
}- Optional: When you are finished, you can clean up the resources that you created.
kubectl delete httproute httpbin-headers -n httpbin
kubectl delete TrafficPolicy httpbin-secret-headers -n kgateway-system
kubectl delete secret backend-creds -n kgateway-systemField defaulting
The name field on a set or add entry and the key field on secretRef are both optional. How the gateway proxy resolves a header value depends on which combination of fields you provide. If the Secret does not contain the key or name data, the policy reports Accepted=False and the affected route returns a 500 response.
Header name and secretRef.key both set
The following example defines both a name for the header (request.set.name) and a data key from your Secret (secretRef.key). The gateway proxy uses name as the header name and looks up the header value from the Secret using secretRef.key as the data key.
headerModifiers:
request:
set:
- name: X-Api-Key
secretRef:
name: backend-creds
key: api-keysecretRef.key omitted
In this example, the data key is omitted from the secretRef block. The gateway proxy uses the header name (X-Api-Key) to look up a data key in the referenced Secret that matches the header name. Then, it uses the header name and matched data value from the Secret to construct the request header.
headerModifiers:
request:
set:
- name: X-Api-Key
secretRef:
name: backend-credsHeader name omitted
In this example, the name of the header is omitted, but a data key is referenced in the secretRef block. The gateway proxy looks up the data key from the Secret and injects it into a header with the same name as the data key.
headerModifiers:
request:
set:
- secretRef:
name: backend-creds
key: api-keyHeader name and secretRef.key omitted
The following example omits both the header name and the data key in the secret. In such cases, the gateway proxy injects every data key entry in the Secret as a request header. Each data key becomes a header name. Use this combination to mirror an entire Secret into headers without listing each entry individually.
headerModifiers:
request:
set:
- secretRef:
name: backend-credsDynamic request headers
You can return dynamic information about the request in the request header. For more information, see the Envoy docs for Custom request/response headers.
Keep in mind that some variables are available only at certain times. For example, response codes (%RESPONSE_CODE%) are only available after the response has been sent to the client. If you set a response code in a request header, the value is empty.
You might use some of the following common values in your request or response headers.
Request and response information:
- %REQ(:METHOD)% - HTTP method
- %REQ(:PATH)% - Request path
- %REQ(:AUTHORITY)% - Host header
- %REQ(HEADER_NAME)% - Any request header
- %RESP(HEADER_NAME)% - Any response header
- %RESPONSE_CODE% - HTTP response code
- %RESPONSE_FLAGS% - Response flags
Connection information:
- %DOWNSTREAM_REMOTE_ADDRESS% - Client IP address with port
- %DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT% - Client IP address without port
- %DOWNSTREAM_LOCAL_ADDRESS% - Local address
- %DOWNSTREAM_CONNECTION_ID% - Connection ID
Timing information:
- %START_TIME% - Request start time
- %DURATION% - Request duration
Upstream information:
- %UPSTREAM_HOST% - Upstream host
- %UPSTREAM_CLUSTER% - Upstream Envoy cluster
- %UPSTREAM_LOCAL_ADDRESS% - Upstream local address
Data transfer:
- %BYTES_RECEIVED% - Bytes received
- %BYTES_SENT% - Bytes sent
For more potential values, see Command operators in the Envoy docs.
-
Set up a header modifier that sets the
X-Client-Ipheader with the value of the downstream remote address. Choose between the HTTPRoute for a Gateway API-native way, or TrafficPolicy for more flexible attachment options such as a gateway-level policy.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - filters: - type: RequestHeaderModifier requestHeaderModifier: set: - name: x-client-ip value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%" backendRefs: - name: httpbin port: 8000 EOFSetting Description spec.parentRefsThe name and namespace of the gateway that serves this HTTPRoute. In this example, you use the httpGateway that was created as part of the get started guide.spec.rules.filters.typeThe type of filter that you want to apply to incoming requests. In this example, the RequestHeaderModifierfilter is used.spec.rules.filters.requestHeaderModifier.setThe request header that you want to set. In this example, the x-client-ipheader is set to the downstream remote address without the port. For more potential values, see Command operators in the Envoy docs.spec.rules.backendRefsThe backend destination you want to forward traffic to. In this example, all traffic is forwarded to the httpbin app that you set up as part of the get started guide. -
Create an HTTPRoute resource for the route that you want to modify. Note that the example selects the http Gateway that you created before you began.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: httpbin-headers namespace: httpbin spec: parentRefs: - name: http namespace: kgateway-system hostnames: - headers.example rules: - backendRefs: - name: httpbin port: 8000 EOF -
Create a TrafficPolicy that sets the
x-client-ipheader to the downstream remote address without the port for a request. For more potential values, see Command operators in the Envoy docs. The following example attaches the TrafficPolicy to the http Gateway.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: httpbin-headers namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: Gateway name: http headerModifiers: request: set: - name: x-client-ip value: "%DOWNSTREAM_REMOTE_ADDRESS_WITHOUT_PORT%" EOF
-
-
Send a request to the httpbin app on the
headers.exampledomain. Verify that theX-Client-Iprequest header is set to the downstream remote address without the port.curl -vi http://$INGRESS_GW_ADDRESS:8080/headers -H "host: headers.example:8080"curl -vi localhost:8080/headers -H "host: headers.example"Example output:
{ "headers": { "Accept": [ "*/*" ], "Host": [ "headers.example:8080" ], "X-Client-Ip": [ "127.0.0.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "f83bb750-67f7-47dc-8c79-4a582892034c" ] } } -
Optional: Clean up the resources that you created.
kubectl delete httproute httpbin-headers -n httpbinkubectl delete httproute httpbin-headers -n httpbin kubectl delete TrafficPolicy httpbin-headers -n kgateway-system