Route policy attachment
Review how you can apply policies to routes, including across delegated routes in different workspaces.
Overview
You learned about how to organize routes into delegated route tables and manage those route tables with labels. Now, consider how routes are impacted by workspaces and policies, and then review basic, delegated, and advanced scenarios.
Workspaces
You can implement multi-tenancy for your teams by organizing the Kubernetes, Gloo, and other custom resources for each team into Gloo workspaces.
Workspaces can share resources with other workspaces by setting up mutual import and export rules. These resources include route tables and their backing destinations, such as Kubernetes services or Gloo virtual destinations. For more information, see the Concept docs about import and export.
In general, Gloo workspaces are set up to give you control of your microservices. When it comes to sharing policies across workspaces, the following rules generally apply after you enable the VirtualDestinationWorkspacePolicyOverride
feature gate:
- Client-side policies that apply to imported virtual destinations keep the original policy from the source workspace, but can be overwritten by client-side policies in the target workspace. This way, each workspace owner can control the client-side policies that are applied to their own destinations.
- Policies that select workloads (
applyToWorkloads
) do not apply across workspaces, even if their underlying services are imported. - Policies that select routes (
applyToRoutes
) or the destinations of routes (applyToRouteDestination
) do still apply across workspaces. This way, you control how your services are accessed via the routes, even if those routes are exported to other workspaces.
For a parent route table to forward requests to a delegated route in a different workspace:
- The parent’s workspace must export
ROUTE_TABLE
to all of its descendants’ workspaces. This includes when the parent has multiple level of descendants, such as child and grandchild route tables. - All descendent workspaces must import the
ROUTE_TABLE
from the parent workspace. - The parent’s workspace can optionally import back the
ROUTE_TABLE
of any children workspaces. For example, the parent workspace might be for the host domain’s ingress gateway and the children workspaces are for apps at specific paths along the host domain. This way, the parent gateway workspace gets the translated Istio VirtualDestination and can set up routing rules to the apps. - To route to a destination, the parent workspace must have the destination in its workspace. If not, the parent must import the destination, such as
SERVICE
orVIRTUAL_DESTINATION
from the child workspace (and the child must export the destination to the parent). The reason is that, without importing the route tables and backing resources, the source workspace has nothing to delegate the routes to.
If these import and export rules are not met, the route is considered invalid. The route table status has an error message, and users get back a direct response error.
Policies
You can manage and protect traffic along your routes by applying Gloo policies.
Typically, you apply policies through label selectors. The advantage of labels is that you can apply policies to many routes at once. On the other hand, such bulk selection can also make it harder for you to keep track of which policies are applied to the routes.
For example, you might apply a val:foo
label at the table-level. Then, the routes within the table get this label. Also, any delegated routes in a sub-table inherit this label from the parent route table. As such, policies in a different namespace and workspace might apply to your route. However, you might not have visibility into that source namespace and workspace which can make troubleshooting routing issues more difficult. Policies can also cause seemingly conflicting behavior. You might know of an external auth policy that selects your route and enforces authentication via the configured method. However, if a JWT policy also selects the route, you might also need a valid JWT before getting access to the app along the route.
creationTimestamp
takes precedence. Other policies might get created but do not apply and have a warning on their status.Basic routing scenarios
Review the following scenarios that show how route- and table-level labels work, including in cases of conflicting values.
- Policy selects route by label
- Policy applies to many routes with table labels
- Conflicting route and table labels
Basic scenario 1: Policy selects route by label
Policies can select routes by label.
Two policies exist that apply to routes with either the label val:foo
or val:bar
. The route table has a Route A with the val:foo
label.
Route A ends up with the following labels and policies:
- Label
val:foo
, specified on the route - Policy 1 applied to routes with label
val:foo
Basic scenario 2: Policy applies to many routes with table labels
With table labels, you can apply the same policy to many routes at once.
Two policies apply to routes with either the label val:foo
or val:bar
. The route table has the env:prod
label. Route A has the val:foo
label. Route B does not have route-specific labels.
Route A ends up with the following labels and policies:
env:prod
, inherited from the tableval:foo
, specified on the route- Policy 1 applied to routes with the
val:foo
label - Policy 2 applied to routes with the
env:prod
label
Route B ends up with the following labels and policies:
env:prod
, inherited from the table- Policy 2 applied to routes with the
env:prod
label
Basic scenario 3: Conflicting route and table labels
Remember that in case of conflict, the route label overwrites any table labels.
Three policies apply to routes with different labels. The route table has the env:prod
and val:bar
labels. Route A has the val:foo
label. Route B does not have route-specific labels.
Route A ends up with the following labels and policies:
env:prod
, inherited from the tableval:foo
, specified on the route, which overwrites theval:bar
table label- Policy 1 applied to routes with the
val:foo
label - Policy 2 applied to routes with the
env:prod
label
Route B ends up with the following labels and policies:
env:prod
, inherited from the tableval:bar
, inherited from the table- Policy 2 applied to routes with the
env:prod
label - Policy 3 applied to routes with the
val:bar
label
Delegated routing across workspaces
Review the following scenarios that show how label inheritance and policy attachment work with delegated routes. In general, the precedence of labels and policies are the same, but the parent-child relationship can be harder to figure out than in non-delegated, basic scenarios.
- Label inheritance
- Multiple policies
- Conflicting labels
- Workspace boundaries prevent child policy attachment
Delegated scenario 1: Label inheritance
Delegated routes inherit labels similarly to non-delegated routes, as described in the Route label inheritance concept. Policies are applied based on the labels that the route ends up with. Child routes even get policies from the parent workspace, as long as workspace import and export rules are set up correctly.
One policy applies to routes with the val:foo
label. The parent route has the val:foo
label. The route is delegated to a child route table that has neither table nor route labels.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent route - Policy 1 applied to routes with label
val:foo
Delegated scenario 2: Multiple policies
As you saw in the previous example, policies in parent workspaces might get applied to delegated routes that exist in other workspaces. Policies in the child workspace can also apply to the routes.
In case of conflicting policies, the oldest policy bycreationTimestamp
takes precedence. Other policies might get created but do not apply and have a warning on their status.Policies that select routes with the val:foo
label are in both workspaces. The parent route has the val:foo
label. The route is delegated to a child route table that has neither table nor route labels.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, specified on the route - Policy 1 applied to routes with label
val:foo
- Policy 2 applied to routes with label
val:foo
Delegated scenario 3: Conflicting labels
Sometimes, it can be tricky to figure out which policies apply when you have many policies, delegated routes, and labels at both table- and route-levels. As you consider the following scenario, keep in mind the precedence of delegated label inheritance that you learned about in the Route label inheritance concept.
Policies that select routes with the val:foo
label are in both workspaces, and a policy that selects val:bar
is in the target workspace. The parent route has the val:foo
route label. The route is delegated to a child route table that has a val:bar
table label.
The val:foo
policy in the parent workspace does not apply, because the child route table has a val:bar
table label that takes precedence. For more information, see the Route label inheritance concept.
Delegated route A ends up with the following labels and policies:
- Label
val:bar
, specified on the child table, which overwrites the inheritedval:foo
parent route label - Policy 3 applied to routes with label
val:bar
Delegated scenario 4: Workspace boundaries prevent child policy attachment
Workspace boundaries are another factor in determining which policies apply to routes. In previous examples, you saw that a policy in a parent workspace can apply to the final route in the child workspace. However, the reverse is not always true, as the following scenario demonstrates.
Policies that select routes with the val:foo
label are in both workspaces. The parent route table has two routes and the val:foo
table label. Route A is delegated to a child route table in a different workspace. Route B is not delegated.
Because you have mutual import and export rules, you might be tempted to think that both workspaces’ policies apply to routes with the matching labels. However, policies themselves are not shareable resources, but only as attached to an imported route. Because Route B is not imported, policies from other workspaces are not applied.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table - Policy 1 from the parent workspace, applied to routes with label
val:foo
- Policy 2 from the child workspace, applied to routes with label
val:foo
Route B ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table - Policy 1 from the same parent workspace, applied to routes with label
val:foo
Advanced delegation scenarios
Review the following scenarios that show more advanced considerations for delegation. In general, the precedence of labels and policies are the same, but the relationships for these corner cases can be harder to figure out than in non-delegated, basic scenarios.
- Imported routes
- Multiple workspaces
- Multi-level delegation (parent-child-grandchild)
- Workload selectors
Advanced scenario 1: Imported routes
Building off the workspace boundaries scenario, let’s consider how this scenario changes when Route B is imported to the child workspace. Imported routes still get policies from the parent workspace, but the policies from the child workspace do not apply.
Policies that select routes with the val:foo
label are in both workspaces. The parent route table has two routes and the val:foo
table label. Route A is delegated to a child route table in a different workspace. Route B is not delegated, but is imported by the child workspace.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table - Policy 1 from the parent workspace, applied to routes with label
val:foo
- Policy 2 from the child workspace, applied to routes with label
val:foo
Imported route B ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table - Policy 1 from the parent workspace, applied to routes with label
val:foo
Note that if Route B were delegated to the child route table, and not just imported, then both the source and target workspaces’ policies would apply, similar to Route A.
Advanced scenario 2: Multiple workspaces
The previous scenarios consider a simple workspace scenario of two workspaces only. But what if you have many workspaces? In general, the same principles of workspace boundaries and label inheritance apply.
The environment has three workspaces, a Source workspace and two Target A and Target B workspaces. Each workspace has its own policy. The parent route table in the Source workspace has three routes and the val:foo
table label. Route A is delegated to a child route table in Target A workspace. Route B is delegated to a child route table in Target B workspace. Route B’s child route table has a table label that conflicts with the inherited parent table label. Route C is not delegated and stays in the Source workspace.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table - Policy 1 from the parent Source workspace, applied to routes with label
val:foo
- Policy 2 from the child Target A workspace, applied to routes with label
val:foo
Route B ends up with the following labels and policies:
- Label
val:bar
, specified on the child table, which overwrites the inheritedval:foo
label - Policy 3 from the child Target B workspace, applied to routes with label
val:bar
Route C ends up with the following labels and policies:
- Label
val:foo
, specified on the parent table - Policy 1 from the parent Source workspace, applied to routes with label
val:foo
Advanced scenario 3: Multi-level delegation (parent-child-grandchild)
The previous scenarios consider a parent-child relationship for delegation. But what if you delegate a route to one sub-table, only to delegate the route again in that sub-table to another sub-table? In general, the same principles of workspace boundaries and label inheritance apply.
Source workspace: The parent route table has two routes and the val:foo
table label. Route A is delegated to a child route table in Sub Target 1 workspace. Route B is not delegated. The workspace has a policy that applies to routes with the val:foo
label.
Sub Target 1 workspace: The child route table also has the val:foo
table label and delegates Route A to another grandchild route table in Sub Target 2 workspace. The child route table has another route, Route C, which is not delegated. The workspace has a policy that applies to routes with the val:foo
label.
Sub Target 2 workspace: The grandchild route table has no table labels, and does not delegate Route A anymore. The grandchild route table has another route, Route D, which is not delegated and has a val:bar
label. The workspace has a policy that applies to routes with the val:bar
label.
Delegated route A ends up with the following labels and policies:
- Label
val:foo
, inherited from the parent table and not overwritten by any subsequent sub-tables - Policy 1 from the parent Source workspace, applied to routes with label
val:foo
- Policy 2 from the child Sub Target 1 workspace, applied to routes with label
val:foo
. Note that this policy gets attached because the route was first delegated to the child route table in Sub Target 1. If the parent table delegated the route directly to the grandchild route table in Sub Target 2, Policy 2 from Sub Target 1 would not apply.
Route B ends up with the following labels and policies:
- Label
val:foo
, specified on the parent table - Policy 1 from the same Source workspace, applied to routes with label
val:foo
Route C ends up with the following labels and policies:
- Label
val:foo
, specified on the child table - Policy 1, inherited from the parent Source workspace, applied to routes with the label
val:foo
. Note that this policy applies because Route C is in a route table that the parent route table delegates to. If Route C were in a different route table that did not have a parent route table in the Source workspace, then policies from the Source workspace would not apply. - Policy 2 from the same Sub Target 1 workspace, applied to routes with label
val:foo
.
Route D ends up with the following labels and policies:
- Label
val:bar
, specified on the grandchild route - Policy 3 from the same Sub Target 2 workspace, applied to routes with the label
val:bar
.
Advanced scenario 4: Workload selectors
You can use workload selectors to restrict traffic routing along the host and path to the selected backing workloads. With delegation, each child route table can select its own workloads. This way, you can apply custom policies to select workloads, such as retries that are unique per zone. For more information, see Gateways to route traffic.
To use this feature, you must have a Gloo Mesh Enterprise license in addition to your Gloo Mesh Gateway license.
In Source workspace:
- The parent route table delegates Route A to two child route tables, as well as configures a default Route A.
- A default Policy 1 applies to routes with the
default
label.
In Target A workspace:
- The child route table has a label and workload selector for its region,
us-east
. - Route A matches requests with the
region:us-east
header. - Policy 2 applies to routes with the
us-east
label.
In Target B workspace:
- The child route table has a label and workload selector for its region,
apac
. - Route A matches requests with the
region:apac
header. - Policy 3 applies to routes with the
apac
label.
Requests to Route A are processed as follows:
- With the
region:us-east
header, the request gets Policy 1 and 2 applied. The request is fulfilled only by workloads with theus-east
label. - With the
region:apac
header, the request gets Policy 1 and 3 applied. The request is fulfilled only by workloads with theapac
label. - For requests to the route without those headers, the request gets Policy 1 applied. The request can be fulfilled by any workload, because the parent route table does not specify a workload selector.
# Example of workload selector inheritance
# Parent table with two matchers
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
name: parent
namespace: source-apps
labels:
# Default label for applying policies
policy: default
spec:
hosts:
- www.example.com
# Select all workloads by default. Child route tables can specify their own workloads.
workloadSelectors:
- {}
virtualGateways:
- name: istio-ingressgateway
namespace: gloo-mesh-gateways
http:
- name: route-a
# Match requests along the path `www.example.com/route-a`
matchers:
- uri:
prefix: /route-a
ignoreCase: true
# Delegate requests that match this path to child-tracks
delegate:
routeTables:
- labels:
table: child-a-overrides
- name: route-a
# Also matches requests along the path `www.example.com/route-a` as a default route
matchers:
- uri:
prefix: /route-a
ignoreCase: true
# Forward to a default app
forwardTo:
destinations:
- ref:
name: default-a
namespace: source-apps
port:
number: 8080
kind: VIRTUAL_DESTINATION
---
# Child 1 route table for US East
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
name: child-1-us-east
namespace: target-a-apps
labels:
# Matches label in parent route table to for delegation
table: child-a-overrides
# Label for applying policies
policy: us-east
spec:
# Restricts matching traffic to workloads with the label 'region: us-east'
workloadSelectors:
- selector:
labels:
region: us-east
http:
# Table routes matching requests along the path `www.example.com/route-a` with a us-east header
- name: route-a
matchers:
- headers:
- name: region
value: us-east
forwardTo:
destinations:
- ref:
name: default-a
namespace: target-a-apps
port:
number: 8080
kind: VIRTUAL_DESTINATION
---
# Child 2 route table for APAC
apiVersion: networking.gloo.solo.io/v2
kind: RouteTable
metadata:
name: child-2-apac
namespace: target-b-apps
labels:
# Matches label in parent route table to for delegation
table: child-a-overrides
# Label for applying policies
policy: apac
spec:
# Restricts matching traffic to workloads with the label 'region: apac'
workloadSelectors:
- selector:
labels:
region: apac
http:
# Table routes matching requests along the path `www.example.com/route-a` with an apac header
- name: route-a
matchers:
- headers:
- name: region
value: apac
forwardTo:
destinations:
- ref:
name: default-a
namespace: target-b-apps
port:
number: 8080
kind: VIRTUAL_DESTINATION
Next steps
Now that you are done learning about route table delegation, try it out! The following guides include examples of delegating routes.
- Delegate requests to child route tables, including examples for sorting delegated routes by weight and specificity.
- Deny requests to routes with the
gatewayDefaultDenyAllHTTPRequests
feature gate. This example makes use of label inheritance. - Bundle APIs into API products that you can expose in a developer portal by using delegated route tables. This example shows how route table delegation can manage routes under the same host domain. You also make use of the labels in the sub-table routes to do other things, like attach policies and expose APIs securely in a developer portal.