The Gateway API has core support for cross Namespace routing. This is useful when more than one user or team is sharing the underlying networking infrastructure, yet control and configuration must be segmented to minimize access and fault domains. Gateways and Routes can be deployed into different Namespaces and bind with each other across Namespace boundaries. This allows differing user access and roles (RBAC) to be applied to separate Namespaces, effectively controlling who has access to different parts of the cluster-wide routing configuration. The ability for Routes to bind with Gateways across Namespace boundaries is goverend by Route binding, which is explored in this guide. The guide shows how two independent teams can safely share the same Gateway from different Namespaces.
In this guide there are two independent teams, store and site, operating
in the same Kubernetes cluster in the
site-ns Namespaces. These are
- The site team has two applications, home and login, that are running
foo.example.com. They want to isolate access and configuration across their apps as much as possible to minimize access and failure domains. They use separate HTTPRoutes for each app, to isolate app routing configurations such as canary rollouts. but share the same load balancer IP, port, domain, and TLS certificate.
- The store team has a single Service called store that they have deployed
- The Foobar Corporation operates behind the
foo.example.comdomain so they would like to host all applications on the same Gateway resource. This is controlled by a central infrastructure team, operating in the
- Lastly, the security team controls the certificate for
foo.example.com. By managing this certificate through the single shared Gateway they are able to centrally control security without directly involving application teams.
The logical relationship between the Gateway API resources looks like this:
Cross-namespace Route binding¶
Route binding is an important concept that dictates how Routes and Gateways select each other to apply routing configuration to a Gateway. It is especially relevant when there are multiple Gateways and multiple Namespaces in a cluster. Gateway and Route binding is bidirectional - a binding can only exist if the Gateway owner and Route owner owner both agree to the relationship. This bi-directional relationship exists for two reasons:
- Route owners don't want to overexpose their applications and don't want their apps to be accessible through paths they are not aware of.
- Gateway owners don't want apps using certain Gateways they should not be using. An internal application shouldn't be exposed through a public Gateway for example.
As a result, Gateways and Routes have independent control to determine which resources they permit binding with. It is a handshake between the infra owners and the application owners that allows them to be independent actors. Route-owners can specify that they will bind with all Gateways in the cluster, or only Gateways from a specific Namespace, with a specific label selector, or an individual Gateway. Similarly, Gateways provide the same level of control. This allows a cluster to be more self-governed, which requires less central administration to ensure that Routes are not over-exposed.
The infrastructure team deploys the
shared-gateway Gateway into the
apiVersion: networking.x-k8s.io/v1alpha1 kind: Gateway metadata: name: shared-gateway namespace: infra-ns spec: gatewayClassName: acme-lb listeners: - hostname: "foo.example.com" protocol: HTTP port: 80 routes: kind: HTTPRoute namespaces: from: "All"
A few notes about this Gateway:
- It is matching for the
foo.example.comdomain. This is configured on the Gateway so that each HTTPRoute does not also have to configure hostname matching, since they are all using the same domain. This also allows these HTTPRoute manifests to be reused across production and dev environments where the dev environment might be hosted at
- The Gateway is configured for HTTPS and references the
foo-example-comSecret. This allows the certificate to be managed centrally for all applications which are using this Gateway.
- It allows any Route in the cluster to use this Gateway because
namespaces.from = All. This is a permissive method of Route selection since the Routes are given full control to select this Gateway. There are more restrictive forms of Route selection that allow selection on a per-Namespace basis, detailed in Route binding. The following block specifies how this Gateway allows HTTPRoutes from all Namespaces in the cluster to bind to it:
routes: kind: HTTPRoute namespaces: from: "All"
Meanwhile, the store team deploys their route for the
store Service in the
apiVersion: networking.x-k8s.io/v1alpha1 kind: HTTPRoute metadata: name: store namespace: store-ns spec: gateways: allow: FromList gatewayRefs: - name: shared-gateway namespace: infra rules: - matches: - path: value: /store forwardTo: - serviceName: store port: 8080
This Route has straightforward routing logic as it just matches for
/store traffic which it sends to the
store Service. The following snippet
controls which Gateways this Route can bind to:
gateways: allow: FromList gatewayRefs: - name: shared-gateway namespace: infra
gateways.allow can be configured for Gateways in the same Namespace as the
Route (the default), all Gateways, or a list of specific Gateways. In this
example the store and site teams decide to reference a specific Gateway. This is
the least permissive choice which ensures that other Gateways in the cluster
(perhaps created in the future at some point) will not bind with these Routes.
If cluster administrators have full control over how Gateways are deployed in a
cluster then a more permissive binding option could be configured on Routes. The
less permissive the Gateway selection is, the less that application owners need
to know about which Gateways are deployed.
The site team now deploys Routes for their applications. They deploy two
HTTPRoutes into the
homeHTTPRoute acts as a default routing rule, matching for all traffic to
foo.example.com/*not matched by an existing routing rule and sending it to the
loginHTTPRoute routes traffic for
service/login-v2. It uses weights to granularly control traffic distribution between them.
Both of these Routes use the same Gateway binding configuration which specifies
gateway/shared-gateway in the
infra-ns Namespace as the only Gateway that these
Routes can bind with.
apiVersion: networking.x-k8s.io/v1alpha1 kind: HTTPRoute metadata: name: home namespace: site-ns spec: gateways: allow: FromList gatewayRefs: - name: shared-gateway namespace: infra rules: - forwardTo: - serviceName: home port: 8080 --- apiVersion: networking.x-k8s.io/v1alpha1 kind: HTTPRoute metadata: name: login namespace: site-ns spec: gateways: allow: FromList gatewayRefs: - name: shared-gateway namespace: infra rules: - matches: - path: value: /login forwardTo: - serviceName: login-v1 port: 8080 weight: 90 - serviceName: login-v2 port: 8080 weight: 10
After these three Routes are deployed, they will all be bound to the
shared-gateway Gateway. The Gateway merges its bound Routes into a single flat
list of routing rules. Routing
between the flat list of routing rules is determined by most specific match and
conflicts are handled according to conflict
resolution. This provides predictable and
deterministic merging of routing rules between independent users.
Thanks to cross-Namespace routing, the Foobar Corporation can distribute ownership of their infrastructure more evenly, while still retaining centralized control. This gives them the best of both worlds, all delivered through declarative and open source APIs.