Cloud bills grow quietly. Nobody decides to spend an extra 40% a month; it happens one forgotten volume, one chatty NAT gateway and one oversized instance at a time. Cost control is mostly visibility: knowing who spends what, getting told early when something changes, and reviewing on a schedule.
State of AWS on this date. AWS Cost Anomaly Detection became generally available in late 2020. Cost Explorer shows the past 12 months and supports daily and hourly granularity (hourly is paid). Cost allocation tags only appear in reports after you activate them, and only for usage after activation.
The cost loop
flowchart TB
T[Tag every resource<br/>owner project env] --> A[Activate cost allocation tags]
A --> CE[Cost Explorer views<br/>by service tag account]
CE --> BU[Budgets with alerts<br/>per project and total]
CE --> AN[Anomaly detection monitors]
BU --> NT[Notify owners by email or chat]
AN --> NT
NT --> RV[Weekly 15 minute review]
RV --> AC[Actions - delete, right-size, schedule, commit]
AC --> T
1. Tagging that works
Pick a small, enforced set: owner (a person or team), project, env (prod, stage, dev) and optionally cost-center. Apply them at creation through IaC and launch templates.
aws ec2 create-tags --resources i-0abc123 vol-0def456 --tags Key=owner,Value=ravi Key=project,Value=shop Key=env,Value=dev
aws resourcegroupstaggingapi get-resources --tag-filters Key=env,Values=dev --query 'ResourceTagMappingList[].ResourceARN'
aws resourcegroupstaggingapi get-resources --resources-per-page 100 --query 'ResourceTagMappingList[?Tags==`[]`].ResourceARN' # untagged
Then activate the tag keys under Billing, Cost allocation tags. Use AWS Config’s required-tags rule or a tag policy (AWS Organizations) to flag resources that miss tags. Tags do not cover everything (some data transfer and support charges are untaggable), so keep an “unallocated” bucket in view.
2. Look at the right reports
In Cost Explorer:
- Group by Service to see the top five; most bills are dominated by EC2, data transfer, RDS, S3 and NAT.
- Group by Usage type inside a service (for example
NatGateway-Bytes,APS3-DataTransfer-Out-Bytes) to find what drives it. - Group by Tag: project to charge back or question owners.
- Compare month to month, and view daily costs to catch a jump on a specific date.
aws ce get-cost-and-usage --time-period Start=2021-03-01,End=2021-04-01 --granularity MONTHLY \
--metrics UnblendedCost --group-by Type=DIMENSION,Key=SERVICE \
--query 'ResultsByTime[0].Groups[].[Keys[0],Metrics.UnblendedCost.Amount]' --output text | sort -k2 -nr | head
3. Budgets and anomaly alerts
aws budgets create-budget --account-id 111111111111 --budget '{
"BudgetName":"shop-monthly","BudgetType":"COST","TimeUnit":"MONTHLY",
"BudgetLimit":{"Amount":"500","Unit":"USD"},
"CostFilters":{"TagKeyValue":["user:project$shop"]}}' \
--notifications-with-subscribers '[{"Notification":{"NotificationType":"FORECASTED","ComparisonOperator":"GREATER_THAN","Threshold":100,"ThresholdType":"PERCENTAGE"},
"Subscribers":[{"SubscriptionType":"EMAIL","Address":"ops@example.com"}]}]'
Use both actual (80%, 100%) and forecasted (100%) alerts; the forecast warns before you overspend. Create a Cost Anomaly Detection monitor (by service or by linked account) with a daily or immediate alert threshold, such as impact above $20.
4. The usual suspects
| Finding | Typical fix |
|---|---|
| Unattached EBS volumes and old snapshots | List with aws ec2 describe-volumes --filters Name=status,Values=available; snapshot then delete |
| Idle or oversized EC2 and RDS | Right-size using CloudWatch CPU and memory trends; Compute Optimizer gives suggestions |
| Dev and test running 24x7 | Stop outside working hours (Instance Scheduler, or an EventBridge rule and Lambda) |
| NAT gateway data processing | Add S3 and DynamoDB gateway endpoints; check what talks to the internet |
| Unused Elastic IPs and load balancers | Release or delete |
| S3 data never expiring | Lifecycle rules, Intelligent-Tiering, delete incomplete multipart uploads |
| Data transfer between AZs and out to the internet | Keep chatty components together, use CloudFront for public content |
| Log groups with no retention | Set retention (CloudWatch Logs charges for storage) |
| gp2 volumes | Convert to gp3 where it saves money |
5. Commitments, last
Once usage is stable and tagged, Savings Plans and Reserved Instances cut steady usage by roughly 30 to 70% depending on term and type. Commit only to what you are sure to run, start with one year and no upfront or partial upfront, and cover 60 to 70% of baseline usage, not everything.
Routine
- Weekly, 15 minutes: top-five services, anomalies, untagged resources.
- Monthly: budget review with owners, delete or justify every idle resource.
- Quarterly: right-sizing and commitments review.
- Always: new projects start with tags, a budget and an owner.