Cross-Namespace Routing¶
This guide covers routing traffic to services in different namespaces using ReferenceGrant.
Overview¶
By default, Gateway API only allows Routes to reference Services in the same namespace. Cross-namespace references require explicit permission via ReferenceGrant.
Use Cases¶
- Shared services: Route to services in a
shared-servicesnamespace - Multi-team deployments: Teams own namespaces but share ingress
- Service mesh patterns: Central gateway routing to distributed services
Basic Setup¶
1. Create ReferenceGrant in Target Namespace¶
The ReferenceGrant must be created in the namespace where the Service exists:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-frontend-routes
namespace: backend # Where the Service is
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: frontend # Where the Route is
to:
- group: "" # Core API group
kind: Service
2. Create HTTPRoute with Cross-Namespace Reference¶
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: api-route
namespace: frontend # Source namespace
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- api.example.com
rules:
- backendRefs:
- name: api-service
namespace: backend # Target namespace
port: 8080
Common Patterns¶
Shared Services Namespace¶
Allow all namespaces to route to shared services:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-all-to-shared
namespace: shared-services
spec:
from:
# Allow from app namespaces
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-a
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-b
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: app-team-c
to:
- group: ""
kind: Service
Specific Service Access¶
Restrict access to specific services:
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-public-api-only
namespace: backend
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: frontend
to:
- group: ""
kind: Service
name: public-api # Only this service
GRPCRoute Cross-Namespace¶
---
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-grpc-routes
namespace: grpc-services
spec:
from:
- group: gateway.networking.k8s.io
kind: GRPCRoute
namespace: grpc-clients
to:
- group: ""
kind: Service
---
apiVersion: gateway.networking.k8s.io/v1
kind: GRPCRoute
metadata:
name: user-service
namespace: grpc-clients
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- grpc.example.com
rules:
- matches:
- method:
service: mypackage.UserService
backendRefs:
- name: user-grpc
namespace: grpc-services
port: 50051
Multi-Service Routing¶
Route to multiple services in different namespaces:
---
# ReferenceGrant for team-a services
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-gateway-routes
namespace: team-a
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: ingress
to:
- group: ""
kind: Service
---
# ReferenceGrant for team-b services
apiVersion: gateway.networking.k8s.io/v1beta1
kind: ReferenceGrant
metadata:
name: allow-gateway-routes
namespace: team-b
spec:
from:
- group: gateway.networking.k8s.io
kind: HTTPRoute
namespace: ingress
to:
- group: ""
kind: Service
---
# Single HTTPRoute routing to multiple namespaces
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: multi-team-route
namespace: ingress
spec:
parentRefs:
- name: cloudflare-tunnel
namespace: cloudflare-tunnel-system
hostnames:
- app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /team-a
backendRefs:
- name: team-a-service
namespace: team-a
port: 8080
- matches:
- path:
type: PathPrefix
value: /team-b
backendRefs:
- name: team-b-service
namespace: team-b
port: 8080
Verification¶
Check ReferenceGrant Status¶
Check Route Status¶
kubectl get httproute api-route --namespace frontend \
--output jsonpath='{.status.parents[*].conditions}'
Look for ResolvedRefs: True. If False with reason RefNotPermitted, the ReferenceGrant is missing or misconfigured.
Debug Missing Grants¶
# Check controller logs for reference errors
kubectl logs --selector app.kubernetes.io/name=cloudflare-tunnel-gateway-controller \
--namespace cloudflare-tunnel-system | grep -i reference
Security Considerations¶
Principle of Least Privilege
- Create ReferenceGrants with minimum necessary permissions
- Use
to[].nameto restrict to specific Services when possible - Regularly audit ReferenceGrants in shared namespaces
- Consider namespace isolation for sensitive services
Audit Script¶
#!/bin/bash
# List all cross-namespace permissions
for ns in $(kubectl get ns -o jsonpath='{.items[*].metadata.name}'); do
grants=$(kubectl get referencegrant -n "$ns" -o name 2>/dev/null)
if [ -n "$grants" ]; then
echo "Namespace: $ns"
kubectl get referencegrant -n "$ns" -o yaml | grep -A5 'from:'
echo "---"
fi
done
Troubleshooting¶
RefNotPermitted Error¶
- Verify ReferenceGrant is in the target namespace (where Service is)
- Check
from[].namespacematches the Route's namespace - Check
from[].kindis correct (HTTPRoute or GRPCRoute) - Check
from[].groupisgateway.networking.k8s.io - Check
to[].groupis""(empty string for Services)
Service Not Found¶
Even with ReferenceGrant, the target Service must exist:
Network Policy Blocking Traffic¶
If using NetworkPolicy, ensure traffic is allowed between namespaces: