The CFO flagged it in a board deck: AWS costs had tripled in eighteen months while revenue had doubled. The engineering team assumed this was just the cost of growth. We assumed it wasn't. We were right.
The company was a Series B SaaS platform — 40 engineers, 12,000 customers, $28,200/month in AWS spend. Six weeks after we started, the bill was $9,200/month. No new architecture. No application changes. Pure infrastructure hygiene.
The audit: where the money was going
Before touching anything, we spent a week in AWS Cost Explorer, Trusted Advisor, and their account's resource inventory. The breakdown was uncomfortable:
- EC2 instances: $11,400/month — all on-demand, many oversized, several running at under 5% CPU utilization
- RDS: $6,800/month — multi-AZ on-demand for three databases, one of which was a staging environment running a db.r5.2xlarge
- EBS snapshots: $3,100/month — automated daily snapshots accumulating since 2022 with no retention policy, totaling 47TB across decommissioned and active instances alike
- Data transfer: $2,900/month — the largest surprise, traced to logs being shipped from us-east-1 to a third-party monitoring tool in eu-west-1
- Elastic IPs and orphaned load balancers: $1,200/month — resources left behind after migrations, attached to nothing, accruing charges nobody noticed
- S3 storage: $2,800/month — all Standard tier, including 8TB of application logs older than 90 days
The most expensive finding wasn't any single line item. It was the pattern: no one had looked at this systematically since the company had three engineers. Infrastructure had been provisioned under pressure, never revisited, and the default was always to provision bigger to avoid being paged at 3am.
What we fixed and how
1. EC2 right-sizing and Reserved Instances
We pulled 30 days of CloudWatch CPU and memory metrics for every instance. Anything averaging under 20% CPU with consistent load patterns was a right-sizing candidate. For instances with bursty patterns, we moved to T4g (Graviton) burstable types at significantly lower cost for the same average throughput.
After right-sizing, we purchased 1-year Reserved Instances (Standard, no upfront) for every instance running predictable workloads. The commitment is lower-risk than it sounds when you've already right-sized — you're not locking into oversized capacity. The combined saving from right-sizing plus reservations was $6,200/month on EC2 alone.
2. RDS: right-size staging, reserve production
The staging database was running on the same instance class as production — a db.r5.2xlarge at $890/month. Staging ran at near-zero utilization except during test runs. We moved it to a db.t4g.medium ($62/month), configured it to stop automatically at 10pm and restart at 8am (Aurora serverless-style scheduling for RDS), and dropped the snapshot retention from 35 days to 7.
For production databases, same approach as EC2: right-size first, then purchase 1-year reserved capacity. Total RDS saving: $3,800/month.
3. EBS snapshot retention policy
This one had the worst cost-to-fix ratio we've ever seen. Three hours of work to write a Data Lifecycle Manager policy eliminating 44TB of snapshot accumulation. We kept 7 daily, 4 weekly, 3 monthly — enough for any realistic recovery scenario. Monthly saving: $2,600. The snapshots had been accumulating at roughly $150/month longer than the company had existed.
4. Data transfer: log shipping architecture
Shipping logs cross-region was the hardest to fix because it required a brief architecture change — but not an application change. We deployed a Fluent Bit DaemonSet in the same region as the application, buffered logs to S3 in us-east-1 first, and had the third-party monitoring tool pull from S3 rather than receiving a live stream over the public internet cross-region. Cross-region data transfer dropped by 94%. Monthly saving: $2,700.
5. Orphaned resources cleanup
We wrote a short Python script using boto3 to list all Elastic IPs not associated with running instances, load balancers with no registered targets, and NAT Gateways in subnets with no routing. The script runs in dry-run mode first (prints what it would delete), then with a confirmation flag to actually release. This is now part of their monthly ops checklist. One-time recovery: $1,200/month, ongoing maintenance: near zero.
6. S3 storage tiering
Eight terabytes of application logs in Standard tier is just a policy misconfiguration. We added lifecycle rules: Standard for the first 30 days, Standard-IA from 30–90 days, Glacier Instant Retrieval for 90 days to 1 year, then expire. For backup archives, we moved to Glacier Deep Archive at $0.00099/GB/month. Monthly saving: $1,400.
The results
- Total monthly spend: $28,200 → $9,200 (67% reduction)
- Annual savings: $228,000
- Time to implement: 6 weeks (1 week audit, 5 weeks implementation)
- Engineering hours required: ~40 hours of client engineering time for change review and sign-off
- Application downtime: Zero — all changes were infrastructure-level with rolling restarts where needed
"We'd been treating the AWS bill like a tax — something that just grows as you scale and you can't do much about. Turns out it was a symptom of not having anyone whose job it was to look at it."
What usually drives cloud waste
After running this kind of audit across dozens of companies, the patterns are consistent. Cloud waste concentrates in the same four places every time:
- Provisioning under deadline pressure — instances get sized up to avoid incidents, never resized down
- No retention policies on snapshots and logs — the default is keep-everything-forever, and the default is expensive
- Forgotten dev/staging resources — environments provisioned for a sprint, left running indefinitely
- On-demand everything — reserved capacity pricing assumes commitment, and teams avoid commitment when they're uncertain; but for any resource that's been running for six months, the uncertainty is gone
None of this is negligence. It's the natural result of teams optimizing for shipping product instead of optimizing infrastructure. The fix is a one-time audit followed by automated guardrails — not ongoing manual review.
The guardrails we leave in place: monthly cost anomaly alerts via AWS Budgets, a quarterly right-sizing review as a recurring calendar item, and the orphan-resource script running as a Lambda on the first of each month. The audit happens once; the discipline is what makes it last.