ExplanationKubernetes

Choose a Cilium Gateway API External Entry Point

Understand the Cilium Gateway API data path and choose between LoadBalancer, NodePort, and hostNetwork exposure.

Updated Verified SourceEdit this page

Key takeaways

  • Cilium translates Gateway and HTTPRoute resources 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 LoadBalancer Service, a NodePort consumed by an external appliance, or a direct hostNetwork listener
  • A highly available Kubernetes control plane and a highly available application ingress path solve different problems
  • A public IP missing from eth0 can 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 GatewayClass and Gateway
    • Application teams own host, path, and backend rules through HTTPRoute and GRPCRoute
  • 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

Cilium Gateway API control plane and data plane

Establish the common prerequisites first

  • The examples are verified against Cilium 1.20.1 and Gateway API 1.6.1

    • Check the documentation and upgrade guide for the exact Cilium version deployed in the cluster
    • Treat CiliumGatewayClassConfig as a v2alpha1 API that can change between releases
  • Cilium Gateway API requires kube-proxy replacement and the L7 proxy

values-cilium-gateway.yaml
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 cilium

Choose exposure based on network ownership

EnvironmentRecommended entryAddress ownerCritical requirement
Managed cloud LB integrationLoadBalancer ServiceCloud controllerPermission to watch Services and create LBs
On-premises or bare-metal VIPLB IPAM plus BGP or L2Cilium and the networkConfigure both allocation and advertisement
Existing external LBNodePort or hostNetworkExternal LB operatorsSynchronize node targets, ports, and health checks
Per-node cloud public IPhostNetworkProvider SDN and DNSPer-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 hostNetwork and external DNS when provider SDN associates a distinct public IP with each node vNIC
  • hostNetwork and the default LoadBalancer Service mode are mutually exclusive

    • Host-network listeners bind on all interfaces of selected nodes
    • Review the current limitations before selecting it when TCPRoute or UDPRoute is required

Keep one portable Gateway contract

  • The same Gateway and HTTPRoute contract can remain in place while the external exposure mode changes
gateway-and-route.yaml
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
    • allowedRoutes must admit the Route namespace
    • Cross-namespace backend or Secret references require a ReferenceGrant owned 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 world to the ingress identity
    • The second segment is the ingress identity to the application identity
  • 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-For only 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=True confirms 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

References