Skip to content

Cross-Namespace routing

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 Routes can attach to Gateways across Namespace boundaries. This allows user access control to be applied differently across Namespaces for Routes and Gateways, effectively segmenting access and control to different parts of the cluster-wide routing configuration. The ability for Routes to attach to Gateways across Namespace boundaries are governed by Route Attachment. Route attachment is explored in this guide and demonstrates how independent teams can safely share the same Gateway.

In this guide there are two independent teams, store and site, operating in the same Kubernetes cluster in the store-ns and site-ns Namespaces. These are their goals and how they use Gateway API resources to accomplish them:

  • The site team has two applications, home and login. The team wants to to isolate access and configuration across their apps as much as possible to minimize access and failure domains. They use separate HTTPRoutes attached to the same Gateway to isolate routing configurations, such as canary rollouts, and still share the same but share the same IP address, port, DNS domain, and TLS certificate.
  • The store team has a single Service called store that they have deployed in the store-ns Namespace which also needs to be exposed behind the same IP address and domain.
  • The Foobar Corporation operates behind the foo.example.com domain for all apps. This is controlled by a central infrastructure team, operating in the infra-ns Namespace.
  • 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 routing

Cross-namespace Route Attachment

Route attachment is an important concept that dictates how Routes attach to Gateways and program their routing rules. It is especially relevant when there are Routes across Namespaces that share one or more Gateways. Gateway and Route attachment is bidirectional - attachment can only succeed 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 through paths they are not aware of.
  • Gateway owners don't want certain apps or teams using Gateways without permission. For example, an internal service shouldn't be accessible through an internet Gateway.

Gateways support attachment constraints which are fields on Gateway listeners that restrict which Routes can be attached. Gateways support Namespaces and Route types as attachment constraints. Any Routes that do not meet the attachment constraints are not able to attach to that Gateway. Similarly, Routes explicitly reference Gateways that they want to attach to through the Route's parentRef field. Together these create a handshake between the infra owners and application owners that enables them to independently define how applications are exposed through Gateways. This is effectively a policy that reduces administrative overhead. App owners can specify which Gateways their apps should use and infra owners can constrain the Namespaces and types of Routes that a Gateway accepts.

Shared Gateway

The infrastructure team deploys the shared-gateway Gateway into the infra-ns Namespace:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
  name: shared-gateway
  namespace: infra-ns
spec:
  gatewayClassName: shared-gateway-class
  listeners:
  - name: https
    hostname: "foo.example.com"
    protocol: HTTPS
    port: 443
    allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            shared-gateway-access: "true"
    tls:
      certificateRef:
        name: foo-example-com

The https listener in the above Gateway matches traffic for the foo.example.com domain. This allows the infrastructure team to manage all aspects of the domain. The HTTPRoutes below do not need to specify domains and will match all traffic by default if hostname is not set. This makes it easier to manage HTTPRoutes because they can be domain agnostic, which is helpful when application domains are not static.

This Gateway also configures HTTPS using the foo-example-com Secret in the infra-ns Namespace. This allows the infrastructure team to centrally manage TLS on behalf of app owners. The foo-example-com certificate will terminate all traffic going to its attached Routes, without any TLS configuration on the HTTPRoutes themselves.

This Gateway uses a Namespace selector to define which HTTPRoutes are allowed to attach. This allows the infrastructure team to constrain who or which apps can use this Gateway by allowlisting a set of Namespaces.

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
spec:
  listeners:
  - allowedRoutes:
      namespaces:
        from: Selector
        selector:
          matchLabels:
            shared-gateway-access: "true"
...

Only Namespaces which are labelled shared-gateway-access: "true" will be able to attach their Routes to shared-gateway. In the following set of Namespaces, if an HTTPRoute existed in the no-external-access Namespace with a parentRef for infra-ns/shared-gateway, it would be ignored by the Gateway because the attachment constraint (Namespace label) was not met.

apiVersion: v1
kind: Namespace
metadata:
  name: infra-ns
  labels:
    shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
  name: site-ns
  labels:
    shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
  name: store-ns
  labels:
    shared-gateway-access: "true"
---
apiVersion: v1
kind: Namespace
metadata:
  name: no-external-access

Note that attachment constraints on the Gateway are not required, but they are a best-practice if operating a cluster with many different teams and Namespaces. In environments where all apps in a cluster have permission to attach to a Gateway then the listeners[].routes field does not have to be configured and all Routes can freely use the Gateway.

Route Attachment

The store team deploys their route for the store Service in the store-ns Namespace:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: store
  namespace: store-ns
spec:
  parentRefs:
  - name: shared-gateway
    namespace: infra-ns
  rules:
  - matches:
    - path:
        value: /store
    backendRefs:
    - name: store
      port: 8080

This Route has straightforward routing logic as it just matches for /store traffic which it sends to the store Service.

The site team now deploys Routes for their applications. They deploy two HTTPRoutes into the site-ns Namespace:

  • The home HTTPRoute 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 home Service.
  • The login HTTPRoute routes traffic for foo.example.com/login to service/login-v1 and service/login-v2. It uses weights to granularly control traffic distribution between them.

Both of these Routes use the same Gateway attachment configuration which specifies gateway/shared-gateway in the infra-ns Namespace as the only Gateway that these Routes want to attach to.

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: home
  namespace: site-ns
spec:
  parentRefs:
  - name: shared-gateway
    namespace: infra-ns
  rules:
  - backendRefs:
    - name: home
      port: 8080
---
apiVersion: gateway.networking.k8s.io/v1alpha2
kind: HTTPRoute
metadata:
  name: login
  namespace: site-ns
spec:
  parentRefs:
  - name: shared-gateway
    namespace: infra-ns
  rules:
  - matches:
    - path:
        value: /login
    backendRefs:
    - name: login-v1
      port: 8080
      weight: 90
    - name: login-v2
      port: 8080
      weight: 10

After these three Routes are deployed, they will all be attached to the shared-gateway Gateway. The Gateway merges these Routes into a single flat list of routing rules. Routing precedence between these 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.

Back to top