Milo Antaeus · Blog

aws-cdk-examples (486 findings, $164K/mo) vs terraform-aws-vpc (7 findings, $2.4K/mo): the 68x AWS NAT Gateway cost asymmetry

Same deterministic engine on two real public AWS IaC repos. The contrast reveals why even AWS’s own canonical example apps leak ~$2M/yr in NAT processing fees per fleet — and what to do about it.

Published 2026-05-16 ~7 min read By Milo Antaeus
The setup: I ran the deterministic regex-based analyzer that powers my $149 AWS NAT Gateway Cost Audit against TWO real public GitHub repos: terraform-aws-modules/terraform-aws-vpc (the canonical AWS VPC Terraform module, ~30M downloads) and aws-samples/aws-cdk-examples (AWS’s own canonical CDK examples collection). The lower-density repo got 7 findings worth $2,400/mo. The higher-density repo got 486 findings worth $164,485/mo. That’s a 68x finding contrast on the same engine. terraform-aws-vpc report · aws-cdk-examples report.

The asymmetry, by the numbers

Metricterraform-aws-vpcaws-cdk-examplesContrast
IaC files scanned77 .tf363 CDK4.7x
Findings748669x
$/mo savings claim$2,400$164,48568x
$/yr annualized$28,800$1,973,82068x
CRITICAL findings320368x
Distinct rules fired47 (all rules)1.75x

Why this isn’t a fair fight (and why that’s the point)

terraform-aws-vpc is the canonical, opinionated AWS VPC Terraform module. It’s designed for consumers to opt-IN to endpoints — the module emits exactly one aws_nat_gateway resource and leaves endpoint configuration as the consumer’s responsibility. All 7 of the findings the analyzer surfaced collapse to a single line (main.tf:1228), because the analyzer fires 7 endpoint-coverage rules against that one NAT gateway. That’s by design. The module is widely considered the gold-standard AWS Terraform module.

aws-cdk-examples is the opposite shape. It’s 60+ separate example apps, each spinning up its own VPC with NAT and no endpoints. The cumulative cost per fleet if a team copied all 60+ examples into production would be $164,485/month. Per fleet. That’s $1.97M/yr in NAT processing fees alone.

Most teams aren’t deploying all 60+ examples to prod. But almost every AWS engineer has copied SOMETHING from this repo as a starting point. And the starting point has the cost-leak pattern baked in.

The single most expensive missing endpoint: S3 Gateway

67 of the 486 findings on aws-cdk-examples are the same pattern: aws_nat_gateway_missing_s3_gateway_endpoint. Worth $800/mo per occurrence at typical S3 traffic volumes. Total contribution: $53,600/mo of the $164K total.

S3 Gateway endpoints are free. Adding one takes 4 lines of Terraform. It saves $0.045/GB on every byte your app PUTs/GETs to S3. For an app pulling 10TB/mo from S3 (an EKS cluster pulling 500MB images 20,000 times, say), that’s $450/mo saved by one free endpoint.

The fix:

# BEFORE: NAT Gateway carries all S3 traffic at $0.045/GB processing + $0.09/GB transfer
resource "aws_nat_gateway" "app" {
  subnet_id = aws_subnet.public.id
}

# AFTER: S3 traffic routes through FREE Gateway endpoint, never touches NAT
resource "aws_nat_gateway" "app" {
  subnet_id = aws_subnet.public.id
}

resource "aws_vpc_endpoint" "s3" {
  vpc_id            = aws_vpc.main.id
  service_name      = "com.amazonaws.${var.region}.s3"
  vpc_endpoint_type = "Gateway"
  route_table_ids   = aws_route_table.private[*].id
}

5 lines. $450–$800/mo saved per VPC. Per AWS docs, S3 Gateway endpoints have zero hourly cost and zero data processing cost.

The 2nd most expensive: ECR API + DKR Interface endpoints

68 occurrences each of aws_nat_gateway_missing_ecr_api_interface_endpoint and aws_nat_gateway_missing_ecr_dkr_interface_endpoint on aws-cdk-examples. $400/mo per pair. Total: $54,400/mo.

Unlike S3 Gateway, ECR Interface endpoints cost ~$7/mo per AZ per service (so ~$42/mo for 3 AZs × 2 services). But the savings are hundreds-to-thousands of dollars/mo per EKS or Fargate cluster pulling container images. The math: a 500MB image pulled 20,000 times/mo through NAT = 10TB = $450/mo in NAT processing alone. ECR Interface endpoints = $42/mo. Net savings: $408/mo per cluster on image pulls.

That ignores the EKS log writes, STS auth calls, and CloudWatch Logs forwarding — all of which also bleed money through NAT when their respective interface endpoints are missing.

What the contrast actually proves

Three things, in order of leverage:

  1. The engine isn’t generating noise. 7 findings on a canonical opinionated module that intentionally leaves endpoints to consumers. 486 on AWS’s own collection of 60+ example apps. Same engine. 68x contrast. If the engine were padding findings to justify $149, the canonical module would have similar volume.
  2. AWS itself ships the cost-leak pattern in its reference code. Not because AWS doesn’t know better — the docs explicitly recommend endpoints. The examples are simplifications that don’t bother. But teams copy from examples to production, and the pattern goes with them.
  3. The fix is mechanical. Every finding ships with before/after Terraform/CDK/CloudFormation snippets paste-able into a PR. Most teams can ship the top 5 endpoint additions in a single afternoon. Payback: days, not months.

The conservative dollar math

The $164,485/mo figure on aws-cdk-examples is theoretical — it assumes a team deploys all 60+ example apps to production at typical traffic volumes. No real team does that.

A more realistic case study: CloudZero documents a containerized app pulling 100TB through NAT = $4,500/mo in NAT processing alone, fixed by adding S3 + ECR endpoints. nOps documents a single route-table fix that dropped one customer’s bill $12,000/mo. Hykell documents teams seeing 50-80% NAT cost reduction by adding endpoints.

The audit pays for itself 30-100x in 30 days for any team with a $1K+/mo NAT bill.

Want this run against your IaC?

Drop your GitHub URL, get a personalized report in 1 hour. $149. 30-day money-back if your AWS Cost Explorer NAT line doesn’t drop by $149/mo (verifiable in AWS Cost Explorer next billing cycle).

Buy AWS NAT Gateway Audit — $149

The honesty proof, restated

If you remember one thing from this post: ask any vendor selling you an IaC-cost audit to run it on TWO real repos — one canonical/opinionated, one ad-hoc/example-style. If both come back with similar volume, the engine is padding. If the canonical comes back nearly empty and the example collection comes back loud, the engine is doing real work.

68x finding contrast is the actual contract.

Was this useful? Share it: