NAT Gateways
The component that lets private instances reach the internet, and one of the most reliably surprising line items on a cloud bill.
Definition
Network address translation lets instances in private subnets initiate outbound connections without being reachable inbound. In cloud environments this is usually a managed NAT gateway, billed both per hour and per gigabyte processed.
Why it matters architecturally
The per-gigabyte processing charge applies to all traffic through it, including traffic to services within the same provider. A workload in a private subnet that reads terabytes from object storage through a NAT gateway is paying a processing fee on data that never needed to leave the provider's network at all.
The fix is a private endpoint — a route to the provider's service that bypasses the NAT gateway entirely. This single change routinely removes a large fraction of an unexplained networking bill, and it is one of the highest-return, lowest-risk optimisations available in a cloud estate.
The other structural decisions
- One NAT gateway per availability zone. A single shared gateway means cross-zone traffic charges on every egress and a zone-level single point of failure for all outbound connectivity.
- Egress filtering. NAT permits outbound to anywhere by default. If exfiltration or dependency control matters, a proxy with an allowlist belongs in the path.
- Port exhaustion. A NAT gateway has a finite number of simultaneous connections per destination. A workload making very many connections to one destination — a polling client, a chatty microservice — can exhaust them, producing intermittent connection failures that look like a downstream problem and are extremely hard to diagnose.
Failure scenarios
- A data pipeline pulling from object storage through NAT, generating a bill several times the compute cost of the job.
- Single-AZ NAT, so a zone failure removes outbound connectivity for the whole VPC.
- Port exhaustion under load, presenting as intermittent timeouts to one specific destination.
- Container image pulls through NAT on every scale-out event, which is both slow and charged.
Trade-offs
NAT buys outbound connectivity without inbound exposure, which is the correct default posture. It costs money proportional to traffic and introduces a shared component in the path of every outbound call. The architectural instinct worth developing is to ask, for any high-volume flow, whether it needs to traverse NAT at all.
Interview question
"Your networking costs are three times the compute cost for a batch job that reads from object storage. What is happening and what is the fix?"