VPC Endpoints vs NAT Gateways: Stop Paying for Traffic That Never Leaves AWS
If you're paying NAT gateway charges to fetch from S3, DynamoDB, or Secrets Manager — and a lot of teams are — this post is for you.
The bill nobody questions
NAT Gateways feel like infrastructure. They sit there in the diagram, "internet egress for private subnets," and nobody touches them once they're set up. The trap is the pricing model: £0.036/hour (~£26/month per gateway) is fine — but the data processing charge is £0.036/GB. And that's the bit that quietly goes nuclear.
1TB/day through your NAT — common for an active production VPC — is ~£1,080/month, just in NAT processing. Nobody flags it because "of course, it's egress." Except a lot of that traffic isn't going to the internet at all. It's going to AWS services, in your same region, via the NAT and back.
What VPC endpoints actually are
A VPC endpoint is a private route from your VPC to an AWS service that bypasses the public internet (and bypasses your NAT). Two flavours:
Gateway endpoints — only for S3 and DynamoDB. Free. Just a route table entry. There is genuinely no reason not to have these.
Interface endpoints — for everything else (Secrets Manager, KMS, ECR, SSM, STS, SQS, SNS, etc.). £0.008/hour per endpoint per AZ + £0.008/GB processed.
The maths for interface endpoints isn't always favourable — you're paying per-AZ for the ENI and per-GB for processing. But for high-traffic services it usually beats NAT.
The free win — gateway endpoints for S3 and DynamoDB
If you have a VPC with private subnets pulling from S3 — Lambda, ECS task, EC2 with an SDK call — and you don't have a gateway endpoint, you are paying NAT processing charges to reach an AWS service in the same region. There is no reason for this. The fix:
aws ec2 create-vpc-endpoint \
--vpc-id vpc-abc123 \
--service-name com.amazonaws.eu-west-2.s3 \
--vpc-endpoint-type Gateway \
--route-table-ids rtb-private-1 rtb-private-2
That's it. Existing connections need to retry once; new connections route through the endpoint automatically. We've seen accounts drop ~£640/month off the NAT bill from a single Terraform PR doing this for both S3 and DynamoDB endpoints across all VPCs.
The "is it worth it" calc for interface endpoints
Interface endpoints aren't free, so do the maths. The break-even rule of thumb:
Endpoint cost: £0.008/hr × 24 × 30 × number_of_AZs ≈ £5.75/month per AZ.
Per-GB: £0.008/GB through endpoint vs £0.036/GB through NAT.
An interface endpoint pays for itself if you're moving more than ~200GB/month per AZ to that service. For Secrets Manager (small payloads, frequent calls): probably not worth it on cost alone, but worth it for the latency drop and the fact that it works without internet egress (useful for compliance).
For ECR pulling container images on every ECS task launch, KMS encrypting/decrypting at high volume, or SSM pulling parameters into hundreds of instances — the savings get serious quickly.
The compliance angle nobody mentions
VPC endpoints have a security benefit that's worth more than the cost savings: you can write an endpoint policy that allows only your buckets, only your KMS keys, only your secrets. Combined with a deny-all-public-egress at the security group level, you get a network where data can't physically leave your AWS environment, even if a misconfigured app tried.
That's a powerful story for SOC 2, ISO 27001, or any regulator asking "how do you prevent data exfiltration." The technical control is genuinely strong, not just policy.
How to find out where your NAT money is going
VPC Flow Logs are the canonical answer, and the queries get gnarly fast. The fastest practical approach:
Enable Flow Logs to S3 in Parquet format. (Custom format with action, srcaddr, dstaddr, bytes.)
Query with Athena, group by destination, sum bytes.
The top destinations are usually some combination of
s3.amazonaws.comranges,dynamodb.amazonaws.comranges, and ECR/Secrets Manager.
Anything in those ranges is a candidate for an endpoint. AWS publishes the IP ranges in JSON at https://ip-ranges.amazonaws.com/ip-ranges.json if you want to do the lookup automatically.
The migration order that doesn't break things
If you're rolling endpoints out across an existing production VPC, do it in this order to avoid a "nothing can talk to anything" afternoon:
Gateway endpoints (S3, DynamoDB) first. Zero risk; just adds a route. No app changes.
Interface endpoints second, with privateDnsEnabled = true. Apps using the public hostname automatically resolve to the endpoint. Verify with
dig secretsmanager.eu-west-2.amazonaws.comfrom inside the VPC — should resolve to a private IP.Endpoint policies third. Once traffic is flowing through endpoints, add the deny-by-default policy. Test in a non-prod VPC first; an over-restrictive policy is a great way to lose a Friday.
NAT downsize last. Once endpoint traffic is the majority, you may be able to drop from one NAT-per-AZ to one NAT-per-VPC, or remove NAT entirely if everything that needs egress now goes through endpoints.
The headline
If your VPC has a NAT and a private subnet that talks to AWS services, you almost certainly have free money sitting on the table. Two gateway endpoints (S3 + DynamoDB) cost nothing and pay for themselves in days. Interface endpoints are a calculator job — usually worth it above ~200GB/month per AZ to a service. The compliance side-benefit is the cherry on top.
Open your last 30 days of Cost Explorer, filter to NatGateway, look at the DataProcessing-Bytes line. If it's a meaningful number, this is the cheapest engineering win available to you.