Skip to content

A Lambda-Based AWS Cost Anomaly Detector with Slack Alerts

TL;DR: I built a Lambda function that checks AWS Cost Explorer daily, detects spending anomalies by comparing against rolling averages, forecasts monthly spend, and sends a formatted Slack report every morning.

The Problem

AWS bills are full of surprises. A forgotten NAT Gateway running at $32/day, an accidentally provisioned large RDS instance, a Lambda function in a retry loop -- these things silently drain budget for days before anyone notices. The native AWS Cost Anomaly Detection service exists but is limited in customization and alerting flexibility. I wanted daily cost intelligence in Slack, with anomaly detection tuned to my thresholds.

What I Built

aws-cost-optimizer is a Python Lambda function triggered daily by EventBridge at 8 AM UTC. It pulls the last 7 days of spending from AWS Cost Explorer (grouped by service), computes a rolling average per service, flags any service that exceeds its average by a configurable threshold, forecasts the current month's total, and posts a detailed report to Slack.

  • Daily cost breakdown -- top services by spend over the trailing 7-day window, formatted as a clean Slack message
  • Anomaly detection -- compares each service's latest daily cost against its rolling average; configurable percentage threshold (default: 30%)
  • Monthly forecasting -- uses Cost Explorer's forecast API to project end-of-month spend and compares it against a budget target
  • Slack alerts -- formatted messages with service-by-service breakdown, flagged anomalies, forecast vs. budget status, and trend indicators
  • Fully IaC -- Terraform deploys the Lambda, EventBridge rule, IAM role, and CloudWatch log group

Tech Stack

Python, AWS Lambda, AWS Cost Explorer, EventBridge, Slack Webhooks, Terraform, CloudWatch

Usage

# Deploy
cat > terraform/terraform.tfvars <<EOF
slack_webhook_url     = "https://hooks.slack.com/services/XXX/YYY/ZZZ"
monthly_budget        = 500
anomaly_threshold_pct = 30
EOF

cd terraform && terraform init && terraform apply

The Lambda runs automatically each morning. To test manually:

aws lambda invoke --function-name aws-cost-optimizer \
  --payload '{}' response.json
cat response.json

Results

The first week caught a $28/day NAT Gateway that had been running unused for two months. Monthly forecasting flagged a projected 40% budget overrun mid-month, giving enough lead time to right-size resources. The daily Slack report became the team's morning cost standup -- a two-second glance that replaces logging into the AWS console and navigating to Cost Explorer.


GitHub: https://github.com/basel5001/aws-cost-optimizer