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.

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 parent HTTPRoute resource delegates traffic as follows:
    • Requests to/anything/team1 are delegated to the child HTTPRoute resource child-team1 in namespace team1.
    • Requests to /anything/team2 are delegated to the child HTTPRoute resource child-team2 in namespace team2.
  • 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 the targetRefs field.
  • The delegation.gateway.solo.io/enable-policy-overrides: "*" is set on the parent allowing its immediate child HTTPRoutes to override policies of all types.

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 the team1 namespace.
  • The child-team1 resource references a RouteOption that specifies the following policies:
    • Add the custom child-team1 response header. Because the parent allowed policy overrides of all types, the test: bar response header from the parent is not applied to the child-team1 routes. Instead, the response header child: team1 in the RouteOption for child-team1 is applied.
    • A fault injection policy that is attached to all child-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 the team2 namespace.
  • The child-team2 resource inherits the response header policy from the parent HTTPRoute. No custom response headers are defined that override the setting of the parent.
  • In addition, child-team2 references a RouteOption resource that specifies the following policies:
    • A prefix rewrite policy that rewrites prefix paths to /anything/rewrite. This policy is attached to all child-team2 routes.
  • The child-team2 HTTPRoute sets the delegation.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 on child-team2.

grandchild HTTPRoute:

  • The grandchild HTTPRoute resource matches incoming traffic for the /anything/team2/bar/.* regex path and routes that traffic to the httpbin app in the team2 namespace.
  • The grandchild HTTPRoute references a RouteOption that specifies the following policies:
    • Add the grandchild: myheader response header. However, because child-team2 does not allow overriding response headers on its immediate children, this setting is ignored. Because of that, the response header from the parent HTTPRoute is applied.
    • Add a custom rewrite path that rewrites requests to the /anything/team2/bar/.* regex path to /anything/custom. However, because child-team2 does not allow overriding rewrite paths on its immediate children, this setting is ignored. Because of that, the rewrite policy from child-team2 is applied.

Before you begin

  1. Follow the Get started guide to install Gloo Gateway, set up a gateway resource, and deploy the httpbin sample app.

  2. Get the external address of the gateway and save it in an environment variable.

Deploy the apps

  1. Create the namespaces for team1 and team2.

      kubectl create namespace team1
    kubectl create namespace team2
      
  2. 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
      
  3. 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 route delegation

Set up a parent, child, grandchild route delegation example and explore how policies are inherited and overridden along the delegation chain.

  1. Create the parent HTTPRoute resource that matches incoming traffic on the delegation.example domain and allows its immediate children to override policies of all types. The parent HTTPRoute resource specifies two routes:

    • /anything/team1: The routing decision is delegated to a child-team1 HTTPRoute resource in the team1 namespace.
    • /anything/team2: The routing decision is delegated to a child-team2 HTTPRoute resource in the team2 namespace.
      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
    EOF
      
  2. Create a RouteOption resource that adds the test: bar header to the response and apply this policy to the parent HTTPRoute resource by using the spec.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
      
  3. Create the child-team1 HTTPRoute resource in the team1 namespace that matches traffic on the /anything/team1/foo prefix and routes traffic to the httpbin app in the team1 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
      
  4. Create a RouteOption resource that adds a custom header child: team1 to all responses and aborts all requests with a 418 HTTP response code. Because the parent HTTPRoute allows overriding policies of all types, the custom header is applied to all child-team1 routes.

      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
    EOF
      
  5. Create the child-team2 HTTPRoute resource in the team2 namespace that matches traffic on the /anything/team2/bar/ prefix and delegates traffic to the grandchild HTTPRoute resource in the team2 namespace. Note that because the child delegates traffic to a grandchild, a PathPrefix matcher must be used. In addition, the child-team2 HTTPRoute allows its immediate children to override any fault injection and CORS policies that are set on child-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
    EOF
      
  6. Create a RouteOption resource that rewrites prefix paths to /anything/rewrite and apply this policy to the child-team2 HTTPRoute resource by using the spec.targetRefs section.

      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
    EOF
      
  7. Create a grandchild HTTPRoute resource that matches traffic on the /anything/team2/.* regex path and routes traffic to the httpbin app in the team2 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
      
  8. Create a RouteOption resource that sets a custom rewrite and response header policy. The RouteOption is applied to the grandchild HTTPRoute resource by using the spec.targetRefs option. Because child-team2 does not allow overriding prefix rewrite and header manipulation policies, these settings are ignored. Instead, the response header of the parent and the prefix rewrite policy of child-team2 are 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 overriden along the delegation chain.

  1. Send a request to the delegation.example domain along the /anything/team1/foo path. child1-team1 overrides the response header policy from the parent 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 the child: team1 header 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 abort
       

  2. Send another request to the delegation.example domain along the /anything/team2/bar/test path. Although the grandchild defines a custom response header and rewrite policy, these policies are not applied because the child-team2 HTTPRoute 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/rewrite as defined in child-team2, and the test: bar response header is added as defined in the parent.

    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