Back to resources
// finops · hidden costs

The 5 lines that wreck your bill

It's never the EC2 that surprises you — it's what's around them. Here are the five line items I find bloated on almost every audit, quietly bleeding a bill with nobody watching.

TechnicalJul 16, 2026~7 min · intermediate
NAT GatewayData transferEBSsnapshotsCloudWatch
01

The ranking

Order of magnitude from a typical scale-up audit: the monthly share of each hidden cost, once isolated from the rest.

NAT Gateway
$1,350
Egress (data out)
$980
Forgotten snapshots
$640
Oversized EBS
$520
CloudWatch logs
$410
02

Why they bloat

01
NAT Gateway

Billed per hour AND per GB processed. Every call from a private instance to the internet goes through it. A VPC Endpoint for S3/DynamoDB bypasses the NAT — and the cost.

02
Egress

Getting data out of AWS is expensive; cross-region or cross-AZ too. Serve assets via CloudFront and keep traffic within one AZ where you can.

03
Snapshots

Every automatic backup piles up and never expires on its own. Without a retention policy, you pay for years of dead backups.

04
EBS & logs

500 GB volumes used at 40, logs kept forever. Size to actual use and set an expiration.

03

The fixes

NATVPC Endpoints for S3/DynamoDB; a single shared NAT if throughput allows
egressCloudFront in front of anything public; avoid needless cross-AZ
snapshotsDLM (Data Lifecycle Manager): automatic 7/30-day retention
EBSgp3 instead of gp2, size to reality, delete detached volumes
logslog-group expiration + S3/Glacier export for archive
!

NAT Gateway is trap number one: invisible inside “EC2,” it can exceed the cost of your instances. It's always the first line I go hunting for.

04

The topology that cuts the NAT

A NAT Gateway isn't expensive because it's switched on — it's expensive because every byte leaving a private subnet passes through it, and you pay $0.045/hour PLUS $0.045 per GB processed. Every `GET` to S3, every DynamoDB query, every `docker pull` from a private instance stacks up. So the question isn't “how do I pay less for the NAT” but “which traffic has no business going through it.”

Gateway endpoints: free, and that's where I start

S3 and DynamoDB offer gateway endpoints that inject a route into your route table and bypass the NAT entirely — no internet gateway, no NAT device. The clincher: `There is no additional charge for using gateway endpoints`. No hourly fee, no per-GB fee. On a data-heavy setup pulling terabytes from S3 out of private subnets, that single change drops the NAT line by hundreds of dollars a month. It's the first thing I set up on an audit, because the effort-to-payoff ratio is indecent.

!

Classic trap: the gateway endpoint is regional. If your instance in eu-west-1 reads a bucket in us-east-1, traffic goes back through the NAT and cross-region egress. Keep buckets and tables in the same region as the VPC, otherwise the endpoint buys you nothing.

S3 / DynamoDBGateway endpoint — free, bypasses the NAT, one route to add
ECR / Secrets / SSMInterface endpoint (PrivateLink) — hourly + per-GB, but often < NAT once the volume is there
Inter-AZCo-locate chatty services; cross-AZ is billed in both directions
Public / statiqueCloudFront in front: the cache absorbs egress and is cheaper than direct data-out

For ECR, Secrets Manager, SSM or internal AWS APIs, those are interface endpoints (PrivateLink) — billed, but the moment a cluster pulls images all day, the endpoint cost stays under the NAT it replaces. I always run the math first: monthly volume × $0.045 on the NAT side, versus the endpoint's hourly flat fee. Below a certain throughput, keeping the NAT is still the smarter call.

05

Storage and logs: the silent wins

gp2 → gp3: 20% in one command, no downtime

gp3 costs up to 20% less per GB than gp2, with a guaranteed baseline of 3,000 IOPS and 125 MiB/s regardless of size. That's the real lever: on gp2 you over-provision the volume just to scrape IOPS (IOPS is tied to size). On gp3 you decouple IOPS and throughput from storage — so you can often shrink the volume and keep the performance. AWS shows a 2 TB gp2 volume at $200/month replaced by a 1 TB gp3 at equivalent performance for $100: 50% off, not 20. Migration runs through Elastic Volumes, live, no detach and no instance restart.

My rule: every new volume is born gp3, and I batch-migrate the existing ones. The only case where I slow down is a volume already past 16,000 provisioned IOPS — there you re-compute, otherwise default gp3 will underperform.

CloudWatch Logs: infinite retention is the real cost

By default a log group keeps its logs forever — nobody checks that box at creation, and that's exactly the problem. Two levers: first set retention on EVERY log group (7, 30, 90 days depending on use), then switch eligible groups to the Infrequent Access class, which halves the ingestion price ($0.25/GB versus $0.50/GB Standard). Since early 2026, IA supports full Logs Insights queries, so for application logs that don't need real-time metric filters, that's the default I recommend.

set-retention.shcopy
# Poser une rétention 30j sur tous les log groups qui n'en ont pas
# Set 30-day retention on every log group that has none
aws logs describe-log-groups \
--query "logGroups[?retentionInDays==null].logGroupName" \
--output text | tr '\t' '\n' | while read lg; do
aws logs put-retention-policy \
--log-group-name "\${lg}" \
--retention-in-days 30
done

The guardrail that catches what you didn't anticipate

Snapshots, detached volumes, log groups without retention: you can hunt them all once. But the next leak comes from what you're not watching yet. So I turn on AWS Cost Anomaly Detection, which runs an ML model on net cost and alerts by email or SNS (relayable to Slack) the moment a line drifts, ranking the cause by service, account, region or usage type. It's free, runs ~3 times a day, and needs ~10 days of history to calibrate. One blind spot to know: Marketplace products, including third-party LLMs on Bedrock, aren't covered — for those, an AWS Budget takes over.

06

Sources & further reading

01AWS — Gateway endpoints (S3 & DynamoDB)Official doc: gateway endpoints bypass the NAT and are free. The foundation for cutting needless egress.02AWS Storage Blog — Migrate EBS gp2 to gp3 (save up to 20%)The gp2→gp3 savings math, the 2 TB/1 TB example, and the live migration via Elastic Volumes.03AWS — Migrate EBS volumes from gp2 to gp3 (Prescriptive Guidance)The step-by-step guide for bulk migration, with the EBS savings calculator.04AWS — Analyzing, optimizing, and reducing CloudWatch costsRetention, Infrequent Access class, ingestion: where log cost hides and how to trim it.05AWS — Detecting unusual spend with Cost Anomaly DetectionThe free ML guardrail: email/SNS alerts, cause ranked by service/account/region.06AWS — Automate EBS snapshots with Data Lifecycle ManagerDLM: automatic retention policies so you stop paying for years of dead snapshots. Free.07AWS — Amazon VPC pricing (data transfer)The NAT rate card (hourly + per-GB processed) and transfer pricing: the reference to price every leak.

These five lines don't headline your bill, but stacked together they often weigh more than compute itself. Hunt them once, set the guardrails, and they don't come back. The full playbook is here: [cut an AWS bill in half](art:finops-cut).