A payment processor's allowlist doesn't care that your pod got rescheduled. It cares about one thing: does the packet arrive from an IP address it recognizes. On a stock Kubernetes cluster, that's a coin flip every time the scheduler moves a pod — a new node, a new egress IP, a firewall rule that silently stops matching. AWS and GCP sell the fix as a metered NAT gateway: a stable IP for roughly $0.135 and $0.12–0.17 per gigabyte respectively, once you add the gateway's processing fee to internet egress. Cilium's eBPF-based Egress Gateway does the identical job — pin a set of pods to one stable, auditable outbound IP — as a Kubernetes CRD with no per-gigabyte meter attached at all. On an owned Hetzner fleet with 20TB of traffic already included per cloud server, that CRD is the difference between paying over $100 a month for one service's stable IP and paying nothing beyond the node you were already running.
The problem a stable outbound IP is solving
External systems that gate access by source IP are everywhere once you look for them: a payment processor's API, a data warehouse's ingestion endpoint, a partner bank's SFTP-over-HTTPS bridge, a SaaS vendor's "enterprise" tier that requires a fixed allowlist entry instead of an API key. All of them assume the caller has a stable network identity. Kubernetes pods don't have one. A pod's IP is an implementation detail of the CNI, assigned from whatever range the node it landed on happens to own, and it changes every time the pod reschedules — a deploy, a node drain, an OOM kill, a HorizontalPodAutoscaler scaling event. Allowlist a pod IP today and it's stale by the next rollout.
The standard workaround is allowlisting the node IP range instead, but that means every pod on every node that could ever schedule that workload is implicitly allowlisted too — a far wider blast radius than the one service that actually needs external access, and an allowlist an external vendor has to keep re-approving as the cluster's node pool grows. What every team actually wants is narrower: this label selector's traffic, to this destination, leaves from one specific, known IP, regardless of which node it happened to land on.
What cloud NAT gateways charge to solve it
The mainstream cloud answer is a managed NAT gateway, and it's worth pricing out concretely because the sticker price undersells the real number. AWS's NAT Gateway pricing breaks into three line items that all apply to the same packet: $0.045/hour to run the gateway ($32.85/month per availability zone), $0.045/GB of data it processes, and — since a NAT gateway's whole job is getting traffic to the internet — the standard $0.09/GB internet egress rate on top. Add those together and a byte leaving through NAT to a third-party API costs $0.135/GB, before the $3.65/month Elastic IP the gateway needs to have a stable address at all.
Cloud NAT on GCP is structured differently but lands in the same range: $0.045/GiB for data the gateway processes, a small per-VM hourly gateway fee (capped around $0.044/hour once a project has more than 32 VMs behind it), a static external IP charge, and internet egress billed separately at $0.12/GB for the first TB.
Run the numbers for one concrete, unglamorous workload: a service that makes 500GB/month of outbound calls to a payment processor that requires IP allowlisting — not a huge number, well within what a single moderately active tenant app generates. On AWS, that's $32.85 (gateway) + $3.65 (Elastic IP) + 500 × $0.135 = $104/month, for one availability zone; run it highly available across three AZs and the fixed cost alone triples. On GCP, processing and egress for the same 500GB lands around $83.50 before the gateway and IP fees, putting the total in a similar $90–110/month band. That's the price of one thing: a source IP a vendor's firewall rule will recognize on every packet.
How Cilium does the same job at the eBPF layer
Cilium's Egress Gateway solves the identical problem — stable, known outbound IPs for a specific set of pods — as a CiliumEgressGatewayPolicy CRD instead of a managed appliance. The mechanism: Cilium's eBPF program on the pod's own node recognizes traffic matching the policy's selector and destination, and instead of letting it egress normally, redirects it to a designated gateway node. That gateway node performs the SNAT, rewriting the packet's source address to its own stable IP before it leaves the cluster. A minimal policy looks like this:
apiVersion: cilium.io/v2
kind: CiliumEgressGatewayPolicy
metadata:
name: payment-api-egress
spec:
selectors:
- podSelector:
matchLabels:
app: billing-service
io.kubernetes.pod.namespace: production
destinationCIDRs:
- "203.0.113.0/24" # payment processor's IP range
egressGateway:
nodeSelector:
matchLabels:
egress-gateway: "true"
egressIP: "10.20.0.100" # or omit egressIP/interface and let Cilium pickTwo prerequisites matter operationally: the feature requires BPF masquerading and kube-proxy replacement to be enabled, since the redirect and SNAT both happen in Cilium's own datapath rather than iptables. egressIP and interface are mutually exclusive on the same policy — pin to a specific address, or let Cilium SNAT with whatever address is assigned to a named interface on the gateway node. When more than one node matches the nodeSelector, Cilium's standard health-checking distributes endpoints across them and reroutes on a failed gateway without an external load balancer in the path.
The result is the same deliverable a cloud NAT gateway sells: billing-service's traffic to that CIDR always leaves from 10.20.0.100, regardless of which of N nodes the pod is scheduled on this week. The processor's firewall rule allowlists one address, once, and it stays valid through every future reschedule.
What it actually costs on owned hardware
This is where the two approaches stop rhyming. A cloud NAT gateway's cost model is the product itself — you're paying per gigabyte because the provider is metering a service. Cilium's Egress Gateway isn't a separate billable product at all; it's a routing decision made by a CNI you're already running, executed by an eBPF program on a node you already pay for by the hour, not by the byte.
On a Cluster API Provider Hetzner fleet, that difference is concrete, not theoretical. Hetzner's EU-region Cloud servers include 20TB of outbound traffic per month per server, with overage billed at €1/TB — roughly $0.001/GB, about 130× cheaper than AWS's $0.135/GB before you account for the fact that most fleets never touch the overage tier at all. Traffic across Hetzner's private network between nodes isn't metered against that pool in the first place. Run the same 500GB/month billing-service example from above through a Cilium egress gateway node on a CAPH fleet, and the marginal cost is effectively $0 — it's traffic inside a pool the gateway node's monthly rate already paid for, not a new line item. The AWS bill for that one capability was over $100/month; the Hetzner bill is the egress gateway node you were already running for other reasons, doing one more thing.
The honest operational cost
None of this is free in the sense that matters more than money: engineering attention. Wiring in an egress gateway has real costs a NAT gateway's managed-service model absorbs on the provider's side instead.
It's a reason to run Cilium as the CNI, not a bolt-on to any CNI. Egress Gateway is a Cilium-specific feature — choosing it means the platform's CNI decision is no longer "any CNI that satisfies the spec," it's "Cilium, with BPF masquerading and kube-proxy replacement both on." That's a real architectural commitment, not a config flag you can walk back cheaply once tenant policies depend on it.
Gateway nodes are a concentration point. Every pod matching a policy funnels through the same one or handful of nodes, so those nodes need to be sized for the aggregate egress bandwidth of everything routed through them — a capacity-planning problem a cloud NAT gateway's "just scales" abstraction hides from you. Reply traffic takes the normal return path rather than the gateway, so the concentration is asymmetric: outbound bandwidth on the gateway node, not necessarily inbound.
Gateway node failure is disruptive, not seamless. Cilium's health-checking reroutes to a healthy gateway when one is available, but a gateway node restart still terminates in-flight connections through it — a long-lived TCP stream to a partner API doesn't survive the same way it would behind a managed NAT gateway's more opaque failover. Running two gateway nodes behind the health check, not one, is the operational answer, and that's capacity you're dedicating specifically to this job.
The honest framing: a cloud NAT gateway sells you both the mechanism and someone else's on-call rotation for it. Cilium's Egress Gateway gives you the mechanism at effectively zero marginal cost per gigabyte, and hands the on-call rotation back to you.
Wiring it into a Cluster-API fleet
Concretely, adopting this on a CAPH-managed fleet is a node-pool decision, not a new piece of infrastructure. Label a small, dedicated MachineDeployment (or an existing pool, tainted to keep general workloads off it) with egress-gateway: "true", confirm BPF masquerading and kube-proxy replacement are enabled in the cluster's Cilium HelmChartConfig, and apply one CiliumEgressGatewayPolicy per tenant workload that needs a stable identity toward a specific external destination — a payment API, a data warehouse, a partner's IP-gated endpoint. Bandwidth for a noisy tenant is a capacity question you answer by sizing the gateway node pool, not a per-GB bill you discover after the fact.
That last point is the honest caveat behind "unmetered egress on owned bandwidth": it only stays true if the platform can actually answer, per tenant, which IP did your traffic leave from, and how much did you send — otherwise "we don't meter egress" is just "we don't know what egress costs us." An egress gateway policy is what makes that answer concrete instead of aspirational: a named IP, a named selector, a workload the platform can point to and say "that's yours."
Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own, with predictable, owned-hardware networking instead of a metered cloud NAT bill. Star the repo on GitHub or deploy your first app today.
Sources
- Egress Gateway — Cilium documentation
- Egress Gateway use case — Cilium.io
- Example CiliumEgressGatewayPolicy — cilium/cilium GitHub
- Pricing for NAT gateways — AWS VPC documentation
- Cloud NAT pricing — Google Cloud
- Hetzner Cloud traffic policy — Hetzner Docs
- Cluster API Provider Hetzner (CAPH) — syself/cluster-api-provider-hetzner
All figures cited above are drawn directly from the linked sources.



