Envoy Gateway Multi-Namespace and Team Ownership: allowedRoutes, ReferenceGrant, and Cross-Team Governance
One of Gateway API's biggest values isn't just prettier YAML — it finally answers a long-standing question clearly:
Who owns the ingress layer? Who can change routes? Can namespaces cross-reference each other?
Many Ingress pain points came from everything being tangled together. Platform teams feared unauthorized exposure changes. App teams felt like they had to file a ticket just to change a path. Everyone ended up torturing each other in YAML.
Gateway API's approach is to say clearly:
- Platform ingress can be independently governed
- Routes can be delegated to app teams
- Cross-namespace behavior requires explicit authorization
This post explains that ownership model from top to bottom.
Start Here: Attachment and Reference Are Two Different Things
This is the most commonly confused distinction.
Route Attachment to Gateway / Listener
This is governed by:
- The route's
parentRefs - The listener's
allowedRoutes
In other words, whether a route can attach to a listener isn't determined by ReferenceGrant — it's determined by whether the listener is willing to accept it.
Cross-Namespace Resource References
This is where ReferenceGrant typically comes in.
For example:
- A
Gatewaywants to reference aSecretin another namespace - An
HTTPRoutewants to reference aServicein another namespace
This isn't a question of attachment — it's "has the target namespace formally authorized you to use its resources?"
Many people collapse these two into one and start questioning their sanity. The rules aren't that mysterious once the roles are separated.
allowedRoutes: Decide Who Can Attach First
The most restrictive listener looks like this:
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: shared-gateway
namespace: infra
spec:
gatewayClassName: eg
listeners:
- name: https
protocol: HTTPS
port: 443
allowedRoutes:
namespaces:
from: SameThis means only routes in the infra namespace can attach to this listener.
To allow specific team namespaces to attach, use Selector:
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
shared-gateway-access: "true"This pattern works well for platform teams.
You don't have to lock everything down completely, but you also don't have to open it with from: All and let everyone in unrestricted. You can require namespaces to earn the right to attach by carrying a specific label.
💡
allowedRoutesis per-listener, not per-Gateway. Different listeners can have different access policies.
ReferenceGrant: The Target Namespace Decides
If a route or gateway wants to reference resources in another namespace, the target namespace has to authorize it.
For example, an app team's HTTPRoute wants to send traffic to a backend in a shared namespace:
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: app-route
namespace: team-a
spec:
parentRefs:
- name: shared-gateway
namespace: infra
sectionName: https
rules:
- backendRefs:
- name: shared-api
namespace: shared-services
port: 8080The shared-services namespace would need a ReferenceGrant:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-team-a-route
namespace: shared-services
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: team-a
to:
- group: ""
kind: ServiceIn plain English:
HTTPRouteresources inteam-a- Are authorized to reference
Serviceresources inshared-services
Note that the authorization is created by the target namespace, not the source. The source can't just declare it wants access — the resource owner decides. This design is actually quite principled, because owners should control who accesses their resources.
Common Platform/App Team Split
The most common ownership model looks like this:
Platform Team Owns
GatewayClassGatewayListener- TLS certificate management
allowedRoutespolicies
App Teams Own
HTTPRoute/GRPCRoutein their own namespaces- Backend services
- Routing rule adjustments
The benefits of this split are clear:
- Platform team guards the ingress exposure and security boundary
- App teams can still move fast on their own traffic rules
- No one needs to touch the shared Gateway just to change a path
You can also give all permissions to one group — that's not wrong. But in larger teams, that model tends to evolve into "anyone can change it, so when it breaks no one knows who did what."
Practical Advice: How to Avoid Multi-Tenant Disasters
Genuinely useful habits:
- Shared Gateways default to
allowedRoutes.namespaces.from: Selector - Namespace label conventions should be stable — don't change
team-atoallow-gwnext month - All cross-namespace backend/Secret references go through
ReferenceGrant - Route names should indicate team or service — e.g.,
team-a-api-route - Shared listeners should always use
sectionNameto prevent routes attaching to the wrong entry
One principle worth keeping:
If you can enforce a boundary at the ingress layer, don't rely on documentation and hoping people self-govern.
In engineering, process beats verbal agreement. That sounds like advice from someone much older, but it's genuinely useful.
One-Line Summary
In Gateway API, allowedRoutes controls "who can enter," and ReferenceGrant controls "what they can access once inside."
Keep those two straight, and multi-namespace and multi-team scenarios become much more manageable.
Next Step
With ownership and permissions sorted, the final piece is: When config doesn't take effect, which status, which condition, and which command do you look at first?
Next post covers debugging and status interpretation: 👉 Status and Debugging Handbook