Kgateway policies
Learn how policy inheritance and overrides work for kgateway policies in a route delegation setup.
About policy inheritance
The following policy inheritance and override rules apply for TrafficPolicies:
- Policies that are defined in a TrafficPolicy resource and applied to a parent HTTPRoute resource are automatically inherited by all child and grandchild HTTPRoutes along the route delegation chain.
- If the TrafficPolicy applies to a child or grandchild HTTPRoute and defines a top-level policy that is different from the policy that is defined on the parent, the policies are merged and both the parent and child/grandchild policies are applied. For example, if the parent applies a rate limiting policy and the child applies a transformation policy, both policies are applied.
- If the TrafficPolicy applies to a child or grandchild HTTPRoute and defines the same top-level policy, the policy of the parent takes precedence and the policy on the child/grandchild is ignored. Note that you can add the
delegation.kgateway.dev/inherited-policy-priority: PreferChild
annotation to the parent HTTPRoute to allow a child/grandchild HTTPRoute to override the same top-level policies. In such cases, the child policy takes precedence and the parent policy is ignored. - If you used multiple attachment options to apply a TrafficPolicy with the same top-level policy to a parent or child HTTPRoute, only the policy with the highest priority is applied. The priority is determined by the attachment option that you chose. The following options are sorted from highest to lowest.
- Policy defined in a TrafficPolicy and attached to an HTTPRoute via the HTTPRoute’s
extensionRef
filter - Policy defined in a TrafficPolicy resource and attached to an HTTPRouteRule via the
targetRef.sectionName
option - Policy defined in a TrafficPolicy resource and attached to an HTTPRoute via the
targetRef
option
- Policy defined in a TrafficPolicy and attached to an HTTPRoute via the HTTPRoute’s
Configuration overview
In this guide you walk through a route delegation example where a child HTTPRoute inherits or overrides policies that are set on a parent HTTPRoute.
The following image illustrates the route delegation hierarchy and policy inheritance:
parent1
and parent2
HTTPRoutes:
- The
parent1
HTTPRoute resource serves traffic for thedelegation-parent1.example
domain and delegates traffic on the/anything/team1
prefix path to the child HTTPRoute resourcechild-team1
in namespaceteam1
. - The
parent2
HTTPRoute resource serves traffic for thedelegation-parent2.example
domain and also delegates traffic on the/anything/team1
prefix path to the child HTTPRoute resourcechild-team1
in namespaceteam1
. - In addition, the
parent2
HTTPRoute specifies thedelegation.kgateway.dev/inherited-policy-priority: PreferChild
annotation, which allows a child HTTPRoute to override policies that are applied toparent2
. To override a parent policy, you must create a TrafficPolicy that defines the same top-level policy as the parent and attach that policy to the child. Keep in mind that any policy that is defined on the parent and not overriden by a child, is still inherited ad applied to the child. - The
parent1
HTTPRoute resource does specify this annotation and therefore does not allow a child HTTPRoute to override policies that are set onparent1
. - A TrafficPolicy defines a transformation and local rate limiting policy and is applied to both
parent1
andparent2
HTTPRoutes via thetargetRefs
option.
child-team1
HTTPRoute:
- The child HTTPRoute resource
child-team1
matches incoming traffic for the/anything/team1/foo
prefix path and routes that traffic to the httpbin app in theteam1
namespace. - A TrafficPolicy defines a transformation policy and is applied to the
child-team1
HTTPRoute via thetargetRefs
option.
Before you begin
-
Follow the Get started guide to install kgateway.
-
Create a Gateway resource and configure an HTTP listener. The following Gateway can serve HTTPRoute resources from all namespaces.
kubectl apply -f- <<EOF kind: Gateway apiVersion: gateway.networking.k8s.io/v1 metadata: name: http namespace: kgateway-system spec: gatewayClassName: kgateway listeners: - protocol: HTTP port: 8080 name: http allowedRoutes: namespaces: from: All EOF
-
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
-
Create the namespaces for
team1
andteam2
.kubectl create namespace team1 kubectl create namespace team2
-
Deploy the httpbin app into both namespaces.
kubectl -n team1 apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/main/assets/docs/examples/httpbin.yaml kubectl -n team2 apply -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/main/assets/docs/examples/httpbin.yaml
-
Verify that the httpbin apps are up and running.
kubectl get pods -n team1 kubectl get pods -n team2
Example output:
NAME READY STATUS RESTARTS AGE httpbin-f46cc8b9b-bzl9z 3/3 Running 0 7s NAME READY STATUS RESTARTS AGE httpbin-f46cc8b9b-nhtmg 3/3 Running 0 6s
Setup
-
Create the
parent1
HTTPRoute resource that matches incoming traffic on thedelegation-parent1.example
domain. The HTTPRoute resource specifies the following route:/anything/team1
: The routing decision is delegated to a child HTTPRoute resource in theteam1
namespace.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: parent1 namespace: kgateway-system spec: parentRefs: - name: http namespace: kgateway-system hostnames: - "delegation-parent1.example" rules: - matches: - path: type: PathPrefix value: /anything/team1 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team1 EOF
-
Create the
parent2
HTTPRoute resource that matches incoming traffic on thedelegation-parent2.example
domain. The HTTPRoute resource specifies the same route as theparent1
HTTPRoute. However, theparent2
HTTPRoute sets thedelegation.kgateway.dev/inherited-policy-priority: PreferChild
annotation that allows any child HTTPRoute to override policies that are set on theparent2
HTTPRoute.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: parent2 namespace: kgateway-system annotations: delegation.kgateway.dev/inherited-policy-priority: PreferChild spec: parentRefs: - name: http namespace: kgateway-system hostnames: - "delegation-parent2.example" rules: - matches: - path: type: PathPrefix value: /anything/team1 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team1 EOF
-
Create a TrafficPolicy that defines the following policies:
- Transformation policy: The
x-parent-policy: This policy is inherited from the parent.
header is set on any request. - Local rate limiting: Requests to the routes are limited to 1 request per minute.
The TrafficPolicy is applied to the
parent1
andparent2
HTTPRoutes by using thetargetRefs
option.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: parent-policy namespace: kgateway-system spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: parent1 - group: gateway.networking.k8s.io kind: HTTPRoute name: parent2 transformation: request: set: - name: x-parent-policy value: This policy is inherited from the parent. rateLimit: local: tokenBucket: maxTokens: 1 tokensPerFill: 1 fillInterval: 60s EOF
- Transformation policy: The
-
Create the child HTTPRoute resource for the
team1
namespace that matches traffic on the/anything/team1/foo
prefix and routes traffic to the httpbin app in theteam1
namespace.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: child-team1 namespace: team1 spec: rules: - matches: - path: type: PathPrefix value: /anything/team1/foo backendRefs: - name: httpbin port: 8000 EOF
-
Create a TrafficPolicy that defines a custom transformation policy for the
child-team1
HTTPRoute. The policy sets thex-child-team1: This is the child-team1 policy.
request header.kubectl apply -f- <<EOF apiVersion: gateway.kgateway.dev/v1alpha1 kind: TrafficPolicy metadata: name: child-policy namespace: team1 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: child-team1 transformation: request: set: - name: x-child-team1 value: This is the child-team1 policy. EOF
-
Send a request to the httpbin app on the
delegation.parent1.example
domain. Because theparent1
HTTPRoute does not allow a child HTTPRoute to override the policies, the child HTTPRoute inherits the policies that are set on theparent1
HTTPRoute. The TrafficPolicy that you created earlier and applied to thechild-team1
HTTPRoute is ignored. Verify that you see theX-Parent-Policy
header in your response.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team1/foo \ -H "host: delegation-parent1.example:8080"
curl -i localhost:8080/anything/team1/foo \ -H "host: delegation-parent1.example"
Example output:
HTTP/1.1 200 OK access-control-allow-credentials: true access-control-allow-origin: * content-type: application/json; encoding=utf-8 ... { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation-parent1.example:8080" ], "User-Agent": [ "curl/8.7.1" ], ... "X-Parent-Policy": [ "This policy is inherited from the parent." ], "X-Request-Id": [ "db2affa4-2d03-4ee7-8624-75c3f9b40889" ] }, "origin": "10.X.XX.XXX", "url": "http://delegation-parent1.example:8080/anything/team1/foo", "data": "", "files": null, "form": null, "json": null }
-
Send another request to the
delegation.parent1.example
domain. Verify that this time the request is rate limited and a 429 HTTP response is returned, because only 1 request is allowed in a 60 second timeframe.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team1/foo \ -H "host: delegation-parent1.example:8080"
curl -i localhost:8080/anything/team1/foo \ -H "host: delegation-parent1.example"
Example output:
HTTP/1.1 429 Too Many Requests content-length: 18 content-type: text/plain date: Fri, 06 Jun 2025 15:43:43 GMT server: envoy local_rate_limited%
-
Send a request to the
delegation.parent2.example
domain. Because theparent2
HTTPRoute resource has thedelegation.kgateway.dev/inherited-policy-priority: PreferChild
annotation set, the child HTTPRoute can override any top-level policies that are defined onparent2
. Policies that are not overridden are still inherited from the parent and applied to the child HTTPRoute.Verify that you see the custom
X-Child-Team1
header in your response.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team1/foo \ -H "host: delegation-parent2.example:8080"
curl -i localhost:8080/anything/team1/foo \ -H "host: delegation-parent2.example"
Example output:
HTTP/1.1 200 OK access-control-allow-credentials: true access-control-allow-origin: * content-type: application/json; encoding=utf-8 ... { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation-parent2.example:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Child-Team1": [ "This is the child-team1 policy." ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], ... "origin": "10.X.X.XXX", "url": "http://delegation-parent2.example:8080/anything/team1/foo", "data": "", "files": null, "form": null, "json": null }
-
Send another request to the
delegation.parent2.example
domain. Because the child HTTPRoute does not define any rate limiting policies, it inherits the rate limiting policy ofparent2
. Verify that the request is rate limited and a 429 HTTP response is returned, because only 1 request is allowed in a 60 second timeframe.curl -i http://$INGRESS_GW_ADDRESS:8080/anything/team1/foo \ -H "host: delegation-parent2.example:8080"
curl -i localhost:8080/anything/team1/foo \ -H "host: delegation-parent2.example"
Example output:
HTTP/1.1 429 Too Many Requests content-length: 18 content-type: text/plain date: Fri, 06 Jun 2025 15:43:43 GMT server: envoy local_rate_limited%
Cleanup
You can remove the resources that you created in this guide.kubectl delete gateway http -n kgateway-system
kubectl delete httproute parent1 -n kgateway-system
kubectl delete httproute parent2 -n kgateway-system
kubectl delete httproute child-team1 -n team1
kubectl delete -n team1 -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/v2.0.x/assets/docs/examples/httpbin.yaml
kubectl delete -n team2 -f https://raw.githubusercontent.com/kgateway-dev/kgateway.dev/v2.0.x/assets/docs/examples/httpbin.yaml
kubectl delete namespaces team1 team2