Key takeaways
- Cilium translates
GatewayandHTTPRouteresources into Envoy configuration, while its eBPF data path delivers incoming connections to per-node Envoy - The external entry point must be chosen explicitly from a
LoadBalancerService, aNodePortconsumed by an external appliance, or a directhostNetworklistener - A highly available Kubernetes control plane and a highly available application ingress path solve different problems
- A public IP missing from
eth0can still be associated with a node vNIC by provider SDN or virtual networking, so inspect the observed destination and provider requirements first - Production readiness requires routing, advertisement, policy, client-IP trust, and failure removal checks in addition to address allocation
Gateway API separates roles from the data path
-
Gateway API separates infrastructure ownership from application routing ownership
- Platform teams own the implementation, listeners, and TLS boundary through
GatewayClassandGateway - Application teams own host, path, and backend rules through
HTTPRouteandGRPCRoute
- Platform teams own the implementation, listeners, and TLS boundary through
-
Cilium Gateway API is integrated into the CNI data path rather than being only another ingress-controller Deployment
- The Cilium operator validates resources and produces
CiliumEnvoyConfig - Cilium eBPF intercepts Service or host-port traffic and transparently directs it to Envoy
- Envoy performs L7 routing and TLS termination before opening a connection to the backend Service
- The Cilium operator validates resources and produces
Establish the common prerequisites first
-
The examples are verified against Cilium
1.20.1and Gateway API1.6.1- Check the documentation and upgrade guide for the exact Cilium version deployed in the cluster
- Treat
CiliumGatewayClassConfigas av2alpha1API that can change between releases
-
Cilium Gateway API requires kube-proxy replacement and the L7 proxy
kubeProxyReplacement: true
l7Proxy: true
gatewayAPI:
enabled: true- Install compatible Gateway API CRDs before enabling the controller
kubectl apply --server-side \
-f https://github.com/kubernetes-sigs/gateway-api/releases/download/v1.6.1/standard-install.yaml
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--values values-cilium-gateway.yaml- Verify both the Cilium settings and the GatewayClass after installation
cilium status --wait
kubectl -n kube-system exec ds/cilium -- \
cilium-dbg config --all | rg 'KubeProxyReplacement|EnableL7Proxy'
kubectl get gatewayclass ciliumChoose exposure based on network ownership
| Environment | Recommended entry | Address owner | Critical requirement |
|---|---|---|---|
| Managed cloud LB integration | LoadBalancer Service | Cloud controller | Permission to watch Services and create LBs |
| On-premises or bare-metal VIP | LB IPAM plus BGP or L2 | Cilium and the network | Configure both allocation and advertisement |
| Existing external LB | NodePort or hostNetwork | External LB operators | Synchronize node targets, ports, and health checks |
| Per-node cloud public IP | hostNetwork | Provider SDN and DNS | Per-node association and failed-address removal |
-
LB IPAM allocates an address but does not make it reachable by itself
- Use Cilium BGP Control Plane when routers can learn the Service VIP over BGP
- Use L2 Announcements when the VIP is reachable on the same L2 network
- Use
hostNetworkand external DNS when provider SDN associates a distinct public IP with each node vNIC
-
hostNetworkand the defaultLoadBalancerService mode are mutually exclusive- Host-network listeners bind on all interfaces of selected nodes
- Review the current limitations before selecting it when
TCPRouteorUDPRouteis required
Keep one portable Gateway contract
- The same
GatewayandHTTPRoutecontract can remain in place while the external exposure mode changes
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
name: public
namespace: edge
spec:
gatewayClassName: cilium
listeners:
- name: https
protocol: HTTPS
port: 443
hostname: "*.example.com"
tls:
mode: Terminate
certificateRefs:
- kind: Secret
name: wildcard-example-com
allowedRoutes:
namespaces:
from: Selector
selector:
matchLabels:
gateway-access: public
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: shop
namespace: shop
spec:
parentRefs:
- name: public
namespace: edge
hostnames: ["shop.example.com"]
rules:
- backendRefs:
- name: shop-web
port: 8080- Cross-namespace attachment requires explicit permission on both sides
allowedRoutesmust admit the Route namespace- Cross-namespace backend or Secret references require a
ReferenceGrantowned by the target namespace
Design policy and client-IP trust together
-
Cilium policy sees the external-to-Envoy and Envoy-to-backend segments as distinct flows
- The first segment is commonly
worldto theingressidentity - The second segment is the
ingressidentity to the application identity
- The first segment is commonly
-
An external LB requires an explicit authority for client IP information
- Keep the default remote-address behavior when an L4 LB preserves source IP
- Trust
X-Forwarded-Foronly when a controlled L7 LB creates it and direct node access is blocked - An Internet client must never be able to inject a header that bypasses IP policy or audit attribution
Verify the request path, not just the address
Programmed=Trueconfirms that configuration was produced, not that the Gateway is reachable from the Internet
kubectl get gateway -A
kubectl describe gateway -n edge public
kubectl get httproute -A
kubectl get svc -n edge
kubectl -n kube-system logs ds/cilium-envoy --since=10m- Test DNS, TCP, TLS, and HTTP from an external vantage point
dig +short shop.example.com
nc -vz shop.example.com 443
openssl s_client -connect shop.example.com:443 -servername shop.example.com </dev/null
curl --fail-with-body --resolve shop.example.com:443:203.0.113.10 \
https://shop.example.com/healthz- The remaining articles keep this Gateway contract and change only the entry-point topology