Joe Attwood

Joe Attwood

DevOps, Platform & infrastructure engineering, London

Open to Senior / Staff
Notice 3 months
CV (PDF)

/projects/cost-anomaly-detection

Cost anomaly detection module

A reusable Terraform module that turns AWS Cost Anomaly Detection into Slack-and-email alerts teams actually see, without each account reinventing the wiring.

  • Terraform
  • AWS Cost Explorer
  • SNS
  • Lambda
  • Slack

The problem

AWS Cost Anomaly Detection is useful only if someone notices. The default platform monitor sends a weekly email above a fixed threshold to the account address — easy to ignore, hard to route to the team that owns the spend, and not something you want every tribe to re-implement with slightly different SNS and Lambda glue.

I wanted a module you drop into a Terragrunt unit: point it at the existing Cost Explorer monitor, set percentage and absolute thresholds, and choose email or Slack. Same shape in every account.

What it does

The module creates an aws_ce_anomaly_subscription against a monitor ARN the platform already provisions on account creation. Thresholds are both relative and absolute — percentage alone fires on noise for small services; absolute alone misses slow creep on large ones.

Delivery is either:

  • Email, for daily/weekly digests (what Cost Explorer expects for those frequencies), or
  • SNS → Slack, for immediate alerts, using a shared SNS module and the open-source notify-slack Lambda path.

Naming had to respect AWS length limits on subscription and topic names, so subscriber identifiers are truncated and sanitised rather than stuffed with full email local-parts.

Design decisions

Reuse the platform DefaultServiceMonitor. Creating a second monitor per team duplicates Cost Explorer state and drifts from what FinOps already configured. The module only owns the subscription and the notification path.

Thresholds as a pair. Both ANOMALY_TOTAL_IMPACT_PERCENTAGE and ANOMALY_TOTAL_IMPACT_ABSOLUTE must match. That is stricter than either alone and cuts false positives without making the module opinionated about a single magic number.

Slack is SNS, not a custom webhook in the CE API. Cost Anomaly’s immediate path wants SNS. Keeping Slack behind SNS means email and Slack share the same topic lifecycle and KMS story.

What I’d do differently

The KMS key lookup for SNS encryption is region-keyed in the module. That works until a region is missing from the map. Preferring a data source or an explicit variable would have been cleaner than a hard-coded region table.

Status

Deployed across multiple accounts via Terragrunt units. Module lives in a versioned registry; consumers pass thresholds, tags, and Slack or email targets.

My cat, extremely close to the camera, unimpressed

resource "cat" "whiskers" {
  mood    = "unbothered"
  consent = false
}
Apply complete. 1 added, 0 changed, 0 destroyed.