Policy inheritance
Learn how policy inheritance works in a route delegation setup.
About policy inheritance
Policies that are defined in a RouteOption resource and that are applied to a parent HTTPRoute resource are inherited by all the child or grandchild HTTPRoutes along the route delegation chain. The following rules apply:
- Only policies that are specified in a RouteOption resource can be inherited by a child HTTPRoute. For inheritance to take effect, you must use the
spec.targetRefs
field in the RouteOption resource to apply the RouteOption resource to the parent HTTPRoute resource. Any child or grandchild HTTPRoute that the parent delegates traffic to inherits these policies. - You can add the
delegation.gateway.solo.io/enable-policy-overrides
annotation to a parent HTTPRoute to allow its immediate child HTTPRoutes to override the top-level policies that are defined on the parent. You have the option to allow overriding policies of all types (delegation.gateway.solo.io/enable-policy-overrides: "*"
) or to limit the type of policies that a child can override (delegation.gateway.solo.io/enable-policy-overrides: "faults,headerManipulation,cors"
). - In a multi-level delegation chain with parent, child, and grandchild HTTPRoutes, the parent and the child HTTPRoutes must both set the
delegation.gateway.solo.io/enable-policy-overrides
annotation for the grandchild to be able to override the top-level policies that were defined on the parent. - If no
delegation.gateway.solo.io/enable-policy-overrides
annotation is set on the parent and the child HTTPRoute sets a policy that is already defined on the parent HTTPRoute, the setting on the parent HTTPRoute takes precedence and the setting on the child is ignored. For example, if the parent HTTPRoute defines a data loss prevention policy, the child HTTPRoute cannot change these settings or disable that policy. - If no
delegation.gateway.solo.io/enable-policy-overrides
annotation is set on the parent HTTPRoute, child HTTPRoutes can augment the inherited settings by defining RouteOption fields that were not already set on the parent HTTPRoute.
The example in this guide attaches the RouteOption policies by using the targetRefs
attachment setting. You might attach RouteOption resources by using the extensionRef
filter in the HTTPRoute resource instead. Note that attaching RouteOptions in different ways can result in conflicting policies or policy merging. To learn more about how conflicting RouteOption resources are handled, see Conflicting policies in the RouteOption concepts.
Configuration overview
In this guide you walk through a route delegation example where a child HTTPRoute inherits policies that are set on a parent HTTPRoute. In addition, the child HTTPRoute defines other policies that are only applied to the child HTTPRoute.
The following image illustrates the route delegation hierarchy and policy inheritance:
parent
HTTPRoute:
- The
parent
HTTPRoute resource delegates traffic as follows:- Requests to
/anything/team1
are delegated to the child HTTPRoute resourcechild-team1
in namespaceteam1
. - Requests to
/anything/team2
are delegated to the child HTTPRoute resourcechild-team2
in namespaceteam2
.
- Requests to
- The response header
test: bar
is added to all requests to the routes that the parent HTTPRoute serves. This policy is defined in a RouteOption resource that is applied to the parent HTTPRoute by using thetargetRefs
field.
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. - The
child-team1
resource inherits the response header policy from the parent HTTPRoute. In addition, a RouteOption resource that specifies a fault injection policy is attached to allchild-team1
routes and aborts all incoming requests with a 418 HTTP response code.
child-team2
HTTPRoute:
- The child HTTPRoute resource
child-team2
delegates traffic on the/anything/team2/bar
path to a grandchild HTTPRoute resource in theteam2
namespace. - The
child-team2
resource inherits the response header policy from the parent HTTPRoute. In addition, a RouteOption resource that specifies a prefix rewrite policy is attached to allchild-team2
routes and rewrites prefix paths to/anything/rewrite
.
grandchild
HTTPRoute:
- The grandchild HTTPRoute resource
grandchild
matches incoming traffic for the/anything/team2/bar/.*
regex path and routes that traffic to the httpbin app in theteam2
namespace. - The
grandchild
HTTPRoute inherits all policies from theparent
andchild-team2
HTTPRoute resources. Because of that, requests to the/anything/team2/bar/.*
regex path are rewritten to/anything/rewrite
. In addition, thetest: bar
header is added to all responses.
Before you begin
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/solo-io/gloo-mesh-use-cases/main/policy-demo/httpbin.yaml kubectl -n team2 apply -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/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
Set up a parent, child, grandchild route delegation example and explore how policies are inherited in the delegation chain.
Create the parent HTTPRoute resource that matches incoming traffic on the
delegation.example
domain. The HTTPRoute resource specifies two routes:/anything/team1
: The routing decision is delegated to achild-team1
HTTPRoute resource in theteam1
namespace./anything/team2
: The routing decision is delegated to achild-team2
HTTPRoute resource in theteam2
namespace.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: parent namespace: gloo-system spec: parentRefs: - name: http hostnames: - "delegation.example" rules: - matches: - path: type: PathPrefix value: /anything/team1 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team1 - matches: - path: type: PathPrefix value: /anything/team2 backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team2 EOF
Create a RouteOption resource that adds the
test: bar
header to the response and apply this policy to theparent
HTTPRoute resource by using thespec.targetRefs
section.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: parent-remove-header namespace: gloo-system spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: parent options: headerManipulation: responseHeadersToAdd: - header: key: test value: bar EOF
Create the
child-team1
HTTPRoute resource in theteam1
namespace that matches traffic on the/anything/team1/foo
prefix and routes traffic to the httpbin app in theteam1
namespace. The child HTTPRoute resource does not select a specific parent HTTPRoute resource. Because of that, the child HTTPRoute resource is automatically selected by all parent HTTPRoute resources that delegate traffic to this child.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 RouteOption resource that aborts all requests with a 418 HTTP response code and apply this policy to the
child-team1
HTTPRoute resource by using thespec.targetRefs
section.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: child-team1-fault namespace: team1 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: child-team1 options: faults: abort: percentage: 100 httpStatus: 418 EOF
Create the
child-team2
HTTPRoute resource in theteam2
namespace that matches traffic on the/anything/team2/bar/
prefix and delegates traffic to thegrandchild
HTTPRoute resource in theteam2
namespace. Note that because the child delegates traffic to a grandchild, aPathPrefix
matcher must be used.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: child-team2 namespace: team2 spec: parentRefs: - name: parent namespace: gloo-system group: gateway.networking.k8s.io kind: HTTPRoute rules: - matches: - path: type: PathPrefix value: /anything/team2/bar/ backendRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: "*" namespace: team2 EOF
Create a RouteOption resource that rewrites prefix paths to
/anything/rewrite
apply this policy to thechild-team2
HTTPRoute resource by using thespec.targetRefs
section.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: child-team2-rewrite namespace: team2 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: child-team2 options: prefixRewrite: /anything/rewrite EOF
Create a grandchild HTTPRoute resource that matches traffic on the
/anything/team2/.*
regex path and routes traffic to the httpbin app in theteam2
namespace.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: grandchild namespace: team2 spec: rules: - matches: - path: type: RegularExpression value: /anything/team2/bar/.* backendRefs: - name: httpbin port: 8000 EOF
Great job. You successfully deployed the multi-level route delegation example that is defined in the Configuration overview. Next, you verify that the policies are correctly inherited by sending requests along the different requests paths in the delegation chain.
Verify
Verify that the policies are correctly inherited along the delegation chain.
Send a request to the
delegation.example
domain along the/anything/team1/foo
path. Becausechild1-team1
inherits the response header policy from theparent
and applies a fault injection policy that aborts all incoming requests, verify that you get back a 418 HTTP response code and that you see thetest: bar
header in your response.Example output:
* Mark bundle as not supporting multiuse < HTTP/1.1 418 Unknown HTTP/1.1 418 Unknown < test: bar test: bar < content-length: 18 content-length: 18 < content-type: text/plain content-type: text/plain ... fault filter abort
Send another request to the
delegation.example
domain along the/anything/team2/bar/test
path. Thegrandchild
inherits the response header policy from the parent and the rewrite policy fromchild-team2
. Verify that you get back a 200 HTTP response code, that the request path is rewritten to/anything/rewrite
, and thetest: bar
response header is added.Example output:
* Mark bundle as not supporting multiuse < HTTP/1.1 200 OK HTTP/1.1 200 OK < access-control-allow-credentials: true access-control-allow-credentials: true < access-control-allow-origin: * access-control-allow-origin: * < content-type: application/json; encoding=utf-8 content-type: application/json; encoding=utf-8 < date: Tue, 11 Jun 2024 17:42:45 GMT date: Tue, 11 Jun 2024 17:42:45 GMT < content-length: 579 content-length: 579 < x-envoy-upstream-service-time: 5 x-envoy-upstream-service-time: 5 < test: bar test: bar < server: envoy server: envoy < { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation.example:8080" ], "User-Agent": [ "curl/7.77.0" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Envoy-Original-Path": [ "/anything/team2/bar/test" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "d936987f-879f-474c-be2c-ed66e85944f4" ] }, "origin": "10.XX.X.XX:49018", "url": "http://delegation.example:8080/anything/rewrite", "data": "", "files": null, "form": null, "json": null }
Cleanup
You can remove the resources that you created in this guide.
kubectl delete httproute parent -n gloo-system
kubectl delete httproute child-team1 -n team1
kubectl delete httproute child-team2 -n team2
kubectl delete httproute grandchild -n team2
kubectl delete routeoption parent-remove-header -n gloo-system
kubectl delete routeoption child-team1-fault -n team1
kubectl delete routeoption child-team2-rewrite -n team2
kubectl delete -n team1 -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/httpbin.yaml
kubectl delete -n team2 -f https://raw.githubusercontent.com/solo-io/gloo-mesh-use-cases/main/policy-demo/httpbin.yaml
kubectl delete namespaces team1 team2