Policy overrides
Explore how to override policies along the delegation chain with annotations.
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.targetRefsfield 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-overridesannotation 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-overridesannotation 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-overridesannotation 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-overridesannotation 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 multi-level route delegation example with parent, child, and grandchild HTTPRoutes. This example lets you explore how policies can be inherited and overridden along the delegation chain.
The following image illustrates the route delegation hierarchy and policy inheritance:
parent HTTPRoute:
- The
parentHTTPRoute resource delegates traffic as follows:- Requests to
/anything/team1are delegated to the child HTTPRoute resourcechild-team1in namespaceteam1. - Requests to
/anything/team2are delegated to the child HTTPRoute resourcechild-team2in namespaceteam2.
- Requests to
- The response header
test: baris 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 thetargetRefsfield. - The
delegation.gateway.solo.io/enable-policy-overrides: "*"is set on theparentallowing its immediate child HTTPRoutes to override policies of all types.
child-team1 HTTPRoute:
- The child HTTPRoute resource
child-team1matches incoming traffic for the/anything/team1/fooprefix path and routes that traffic to the httpbin app in theteam1namespace. - The
child-team1resource references a RouteOption that specifies the following policies:- Add the custom
child-team1response header. Because theparentallowed policy overrides of all types, thetest: barresponse header from theparentis not applied to thechild-team1routes. Instead, the response headerchild: team1in the RouteOption forchild-team1is applied. - A fault injection policy that is attached to all
child-team1routes and aborts all incoming requests with a 418 HTTP response code.
- Add the custom
child-team2 HTTPRoute:
- The child HTTPRoute resource
child-team2delegates traffic on the/anything/team2/barpath to a grandchild HTTPRoute resource in theteam2namespace. - The
child-team2resource inherits the response header policy from the parent HTTPRoute. No custom response headers are defined that override the setting of theparent. - In addition,
child-team2references a RouteOption resource that specifies the following policies:- A prefix rewrite policy that rewrites prefix paths to
/anything/rewrite. This policy is attached to allchild-team2routes.
- A prefix rewrite policy that rewrites prefix paths to
- The
child-team2HTTPRoute sets thedelegation.gateway.solo.io/enable-policy-overrides: "faults,cors"annotation allowing its immediate child HTTPRoute to override any fault injection and CORS policies that are set onchild-team2.
grandchild HTTPRoute:
- The
grandchildHTTPRoute resource matches incoming traffic for the/anything/team2/bar/.*regex path and routes that traffic to the httpbin app in theteam2namespace. - The
grandchildHTTPRoute references a RouteOption that specifies the following policies:- Add the
grandchild: myheaderresponse header. However, becausechild-team2does not allow overriding response headers on its immediate children, this setting is ignored. Because of that, the response header from theparentHTTPRoute is applied. - Add a custom rewrite path that rewrites requests to the
/anything/team2/bar/.*regex path to/anything/custom. However, becausechild-team2does not allow overriding rewrite paths on its immediate children, this setting is ignored. Because of that, the rewrite policy fromchild-team2is applied.
- Add the
Before you begin
Get the external address of the gateway and save it in an environment variable.
Deploy the apps
Create the namespaces for
team1andteam2.kubectl create namespace team1 kubectl create namespace team2Deploy 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.yamlVerify that the httpbin apps are up and running.
kubectl get pods -n team1 kubectl get pods -n team2Example 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 route delegation
Set up a parent, child, grandchild route delegation example and explore how policies are inherited and overridden along the delegation chain.
Create the
parentHTTPRoute resource that matches incoming traffic on thedelegation.exampledomain and allows its immediate children to override policies of all types. TheparentHTTPRoute resource specifies two routes:/anything/team1: The routing decision is delegated to achild-team1HTTPRoute resource in theteam1namespace./anything/team2: The routing decision is delegated to achild-team2HTTPRoute resource in theteam2namespace.
kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: parent namespace: gloo-system annotations: delegation.gateway.solo.io/enable-policy-overrides: "*" 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 EOFCreate a RouteOption resource that adds the
test: barheader to the response and apply this policy to theparentHTTPRoute resource by using thespec.targetRefssection.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 EOFCreate the
child-team1HTTPRoute resource in theteam1namespace that matches traffic on the/anything/team1/fooprefix and routes traffic to the httpbin app in theteam1namespace. 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 EOFCreate a RouteOption resource that adds a custom header
child: team1to all responses and aborts all requests with a 418 HTTP response code. Because theparentHTTPRoute allows overriding policies of all types, the custom header is applied to allchild-team1routes.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: child-team1-policy namespace: team1 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: child-team1 options: faults: abort: percentage: 100 httpStatus: 418 headerManipulation: responseHeadersToAdd: - header: key: child value: team1 EOFCreate the
child-team2HTTPRoute resource in theteam2namespace that matches traffic on the/anything/team2/bar/prefix and delegates traffic to thegrandchildHTTPRoute resource in theteam2namespace. Note that because the child delegates traffic to a grandchild, aPathPrefixmatcher must be used. In addition, thechild-team2HTTPRoute allows its immediate children to override any fault injection and CORS policies that are set onchild-team2.kubectl apply -f- <<EOF apiVersion: gateway.networking.k8s.io/v1 kind: HTTPRoute metadata: name: child-team2 namespace: team2 annotations: delegation.gateway.solo.io/enable-policy-overrides: "faults,cors" 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 EOFCreate a RouteOption resource that rewrites prefix paths to
/anything/rewriteand apply this policy to thechild-team2HTTPRoute resource by using thespec.targetRefssection.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: child-team2-policy namespace: team2 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: child-team2 options: prefixRewrite: /anything/rewrite EOFCreate a
grandchildHTTPRoute resource that matches traffic on the/anything/team2/.*regex path and routes traffic to the httpbin app in theteam2namespace.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 EOFCreate a RouteOption resource that sets a custom rewrite and response header policy. The RouteOption is applied to the
grandchildHTTPRoute resource by using thespec.targetRefsoption. Becausechild-team2does not allow overriding prefix rewrite and header manipulation policies, these settings are ignored. Instead, the response header of theparentand the prefix rewrite policy ofchild-team2are enforced.kubectl apply -f- <<EOF apiVersion: gateway.solo.io/v1 kind: RouteOption metadata: name: grandchild-policy namespace: team2 spec: targetRefs: - group: gateway.networking.k8s.io kind: HTTPRoute name: grandchild options: prefixRewrite: /anything/custom headerManipulation: responseHeadersToAdd: - header: key: grandchild value: myheader 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 and overridden by sending requests along the different requests paths in the delegation chain.
Verify
Verify that the policies are correctly inherited and overridden along the delegation chain.
Send a request to the
delegation.exampledomain along the/anything/team1/foopath.child1-team1overrides the response header policy from theparentand applies a fault injection policy that aborts all incoming requests. Verify that you get back a 418 HTTP response code and that you see thechild: team1header in your response.Example output:
* Request completely sent off < HTTP/1.1 418 Unknown HTTP/1.1 418 Unknown < child: team1 child: team1 < content-length: 18 content-length: 18 < ... fault filter abortSend another request to the
delegation.exampledomain along the/anything/team2/bar/testpath. Although thegrandchilddefines a custom response header and rewrite policy, these policies are not applied because thechild-team2HTTPRoute only allows overriding of fault injection and CORS policies. Verify that you get back a 200 HTTP response code, that the request path is rewritten to/anything/rewriteas defined inchild-team2, and thetest: barresponse header is added as defined in theparent.Example output:
< 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: Wed, 18 Dec 2024 21:59:22 GMT date: Wed, 18 Dec 2024 21:59:22 GMT < content-length: 579 content-length: 579 < x-envoy-upstream-service-time: 2 x-envoy-upstream-service-time: 2 < test: bar test: bar < server: envoy server: envoy < { "args": {}, "headers": { "Accept": [ "*/*" ], "Host": [ "delegation.example:8080" ], "User-Agent": [ "curl/8.7.1" ], "X-Envoy-Expected-Rq-Timeout-Ms": [ "15000" ], "X-Envoy-Original-Path": [ "/anything/team2/bar/test" ], "X-Forwarded-Proto": [ "http" ], "X-Request-Id": [ "aa8829ee-5e31-4582-8a00-eadbd484289a" ] }, "origin": "10.111.1.11:54812", "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-policy -n team1
kubectl delete routeoption child-team2-policy -n team2
kubectl delete routeoption grandchild-policy -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