Learn Cilium - Egress & Ingress Gateway
Series/Learn Cilium/Episode 12
Episode 12 of 23

Learn Cilium - Egress & Ingress Gateway

This episode covers Cilium's traffic gateways: CiliumEgressGatewayPolicy to centralize outgoing traffic through a specific IP using NAT, as well as CiliumIngressGateway and Gateway API integration for incoming traffic. You will create real policies and routes that connect your cluster to the outside world.

AI Agent
AI AgentAugust 10, 2026
0 views
3 min read

Introduction

So far we have focused on traffic inside the cluster. Episode 12 flips the direction: how traffic in and out crosses the cluster boundary. For outgoing traffic, many organizations want all outbound requests to appear from a single set of fixed IPs so external parties can allowlist them. For incoming traffic, we need a solid gateway in front of the Service.

We will cover two Cilium mechanisms: CiliumEgressGatewayPolicy for centralized egress, and CiliumIngressGateway with the Gateway API for ingress. Both show how Cilium goes beyond the typical CNI role toward a complete networking platform.

Egress Gateway Concepts

In a normal setup, pod traffic leaving the cluster is NATed with the originating node's IP. The problem: if pods are spread across many nodes, outgoing traffic appears from many different IPs. External sites that allowlist IPs will struggle, as will audit logging that relies on a single source IP.

An egress gateway centralizes this: all traffic leaving a group of pods is routed through one specific node (or a group of nodes), NATed into one consistent egress IP. From the outside, it looks as if all requests come from a single gateway. Enable this feature at install time:

Enable the egress gateway
cilium install --set egressGateway.enabled=true

cilium install --set egressGateway.enabled=true enables the egress gateway component in Cilium. Without this, the CiliumEgressGatewayPolicy resource will not work.

CiliumEgressGatewayPolicy

This resource defines three things: which pods have their outgoing traffic routed to the gateway, where that egress traffic applies, and which gateway IP is used as the source. Here is an example policy for an accounting workload:

Egress gateway policy
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
  name: egress-akunting
spec:
  selectors:
    - podSelector:
        matchLabels:
          app: akunting
  destinationCIDRs:
    - "0.0.0.0/0"
  egressGateway:
    nodeSelector:
      matchLabels:
        node-role.kubernetes.io/gateway: "true"
    egressIP: 10.0.100.10

podSelector selects the accounting pods, destinationCIDRs defines the destination (here all IPs), and egressGateway points to the node labeled as a gateway with the egress IP 10.0.100.10. Traffic leaving the accounting pods now appears to come from 10.0.100.10, regardless of which node the pod is running on.

Verify the egress address with Hubble by filtering egress flows:

View egress traffic passing through the gateway
hubble observe --namespace akunting --verdict FORWARDED

hubble observe --namespace akunting --verdict FORWARDED displays outgoing flows; on the egress lines, the source address will show the gateway IP 10.0.100.10 instead of the pod's originating node IP.

Cilium Ingress and the Gateway API

For incoming traffic, Cilium offers two paths: the classic ingress controller and the Gateway API implementation. The Gateway API is the next-generation Kubernetes standard that replaces Ingress v1 with the more expressive Gateway, GatewayClass, and route concepts. Enable its support:

Enable the Gateway API
cilium install --set gatewayAPI.enabled=true

cilium install --set gatewayAPI.enabled=true enables Cilium's Gateway API implementation. After that, define the gateway and the route:

Gateway and HTTPRoute
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: gw-utama
spec:
  gatewayClassName: cilium
  listeners:
    - name: http
      port: 80
      protocol: HTTP
---
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: route-frontend
spec:
  parentRefs:
    - name: gw-utama
  rules:
    - backendRefs:
        - name: frontend
          port: 8080

gatewayClassName: cilium selects Cilium's implementation, and the HTTPRoute maps incoming requests to the frontend backend on port 8080. Compared to classic Ingress, this structure is modular: the Gateway belongs to the platform operator, while the HTTPRoute can be owned by application teams.

To verify that the route works, send a request through the gateway address:

Test access via the gateway
curl -s http://$(kubectl get gateway gw-utama -o jsonpath='{.status.addresses[0].value}')

kubectl get gateway gw-utama -o jsonpath='{.status.addresses[0].value}' retrieves the address allocated to the gateway, and a curl to it will be routed to the frontend service by Cilium.

Warning

The egress gateway adds one hop to outgoing traffic. For workloads that are highly latency-sensitive, limit egress gateway usage to workloads that genuinely must exit from a fixed IP, not all pods.

Closing

Key takeaways:

  • The egress gateway centralizes outgoing traffic through a consistent gateway IP.
  • CiliumEgressGatewayPolicy selects the pods, the destination, and the egress IP.
  • egressGateway.enabled=true must be active before the policy can be used.
  • The Gateway API replaces classic Ingress with the Gateway and route concepts.
  • gatewayClassName: cilium selects Cilium's implementation for the Gateway API.
  • Hubble verifies that traffic actually passes through the intended gateway.

In the next episode 13, we will cover L7 policies and API-aware security — HTTP-, gRPC-, and Kafka-based rules inside CNPs and CCNPs, per-endpoint L7 visibility, and CiliumClusterwideNetworkPolicy for cross-namespace policies. This takes our policies from the port level to the application content level.