open atlas
↑ Back to track
AWS, hands-on AWS · 07 · 05

Cost governance: budgets, anomaly alerts, and the surprise bill

The AWS bill arrives a month after the spend, so a runaway resource burns silently for weeks. Governance beats optimization: Budgets and Anomaly Detection turn the delay into a same-day signal, allocation tags assign an owner, SCP guardrails stop spend before it starts.

AWS Senior ◷ 19 min
Level
FoundationsJuniorMiddleSenior

On the third of the month, finance forwards an invoice that is forty thousand dollars over plan. Nobody recognizes the line. You dig: three weeks ago an ML engineer spun up a fleet of GPU instances for “a quick experiment,” the experiment finished, the fleet did not — it ran around the clock in a forgotten account, billing thousands a day, for nineteen days before the invoice made it visible. There was no bug. The instances did exactly what they were told. The failure is structural: AWS bills in arrears, so the only place that runaway spend was ever going to surface was an invoice that lands a month after the meter started turning. Right-sizing the fleet now saves nothing — the money is already gone. The team that gets the next surprise bill is the one that still has no budget alert, no anomaly monitor, and no tag that would have named an owner on day one.

By the end of this lesson you will be able to wire up the controls that would have caught the Hook’s GPU fleet within a day — and explain why optimization alone can never do that.

The surprise bill: a month-long blind spot, not a billing error

The single most expensive property of AWS billing is its latency. You are metered continuously, but the invoice is monthly and arrives in arrears — so the feedback loop between “a resource started costing money” and “a human can see it on the bill” is up to 30+ days wide. Cost Explorer refreshes more often than the invoice, but unless someone is actively looking, nothing pushes the signal at you. That gap is the whole problem. A forgotten dev environment, a recursive Lambda that invokes itself, a cross-account data-egress loop, a leaked access key spinning up crypto-mining instances, or the Hook’s idle GPU fleet all share the same shape: a steady burn that nobody attributed, running for weeks before the number becomes visible.

The math is brutal because cloud spend is a rate, not a one-time charge. A single mis-sized resource at $2,000/day is $60,000 by the time the monthly invoice exposes it. A leaked key launching the largest GPU instances in every Region can clear five figures in a day. Optimization — the levers from lesson 01, Savings Plans and right-sizing and egress hygiene — is the wrong tool here, because optimization is retrospective: it reduces the cost of things you already know you’re running. It does nothing about the thing you don’t know you’re running. The fix for the surprise bill is not a cheaper resource; it is a shorter feedback loop plus guardrails that block the spend before it happens. Everything below is one of those two.

Why this works

Why does the billing delay hurt so much more in the cloud than in a data center? In a colo you bought the hardware once; a forgotten server wastes the capital you already sank, but the marginal cost of leaving it on is just power. In the cloud every running second is a fresh charge against next month’s invoice, and you can provision near-unlimited capacity in seconds with a single API call — so the blast radius of “forgot to turn it off” scales with how much you could have launched, not how much you meant to. The delay converts a small mistake (a launch you forgot) into a large one (a launch you forgot, times 30 days, times whatever instance size the API happily granted). Speed of provisioning is the feature; the lagging invoice is the unpriced risk that rides along with it.

Budgets and Anomaly Detection: collapse 30 days into one

The first job of governance is to make the spend visible the day it starts, not the day it’s invoiced. Two services do this.

AWS Budgets lets you define a cost, usage, RI/Savings-Plans-coverage, or utilization budget and fire alerts when actual or forecasted spend crosses a threshold — the standard pattern is alarms at 80% (warning), 100% (breached), and a forecasted-to-exceed alert that warns you mid-month that the trend will blow the cap even though you haven’t hit it yet. The forecast alert is the one that buys you the most time. Critically, a budget can also carry a budget action: when the threshold trips, AWS applies an IAM policy, an SCP, or a target action (stop EC2/RDS) automatically — turning a budget from a passive notice into an enforced ceiling.

{
  "Budget": {
    "BudgetName": "team-payments-monthly",
    "BudgetType": "COST",
    "TimeUnit": "MONTHLY",
    "BudgetLimit": { "Amount": "8000", "Unit": "USD" },
    "CostFilters": { "TagKeyValue": ["user:team$payments"] }
  },
  "NotificationsWithSubscribers": [
    {
      "Notification": { "NotificationType": "FORECASTED", "ComparisonOperator": "GREATER_THAN", "Threshold": 100 },
      "Subscribers": [{ "SubscriptionType": "SNS", "Address": "arn:aws:sns:us-east-1:111122223333:cost-alerts" }]
    }
  ]
}

Budgets answer a threshold you set. AWS Cost Anomaly Detection answers the spend you didn’t predict: it builds an ML baseline of normal spend per service, per account, or per cost-allocation-tag dimension, and alerts when a service’s daily spend deviates sharply from that baseline — catching the recursive Lambda or the new GPU fleet within roughly a day of the spike, with no threshold to maintain. Use both: Budgets enforce known limits; anomaly detection catches the unknown unknowns. The sharp tradeoff is granularity. A single account-wide budget that fires at “you spent too much this month” tells you nothing actionable — no service, no team, no owner. To be useful, budgets and anomaly monitors must be scoped per team or per service, which is only possible if your spend is attributed — which is the next section.

Allocation and accountability: you cannot govern what you cannot attribute

An alert that says “spend is up $40k” is useless if no one can answer “whose $40k?” Attribution is the load-bearing prerequisite for every other governance control. Three mechanisms build it. Cost allocation tags (team, env, service, cost-center) let you slice the bill by who owns what in Cost Explorer. AWS Organizations consolidated billing rolls many member accounts into one payer while preserving per-account breakdown — so each team’s account is a cost dimension. Together they enable showback (every team sees its own spend) and, a step further, chargeback (every team’s spend is billed back to its own ledger, so it shows up in their budget, not a shared pool).

The blind spot is untagged resources — they land in an unattributable bucket and silently erode your allocation coverage until “miscellaneous” is the biggest line on the bill. The fix is to enforce tagging rather than request it: an Organizations tag policy defines required keys and allowed values, and an SCP can outright deny resource creation when a mandatory tag is absent, so allocation stays near-100% because an untagged resource can’t exist. The tradeoff between showback and chargeback is cultural, not technical: chargeback drives the hardest accountability (real money in each team’s budget) but adds finance process and friction; showback is lighter-weight and politically easier but relies on teams choosing to act on what they see.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyRunInstancesWithoutTeamTag",
    "Effect": "Deny",
    "Action": "ec2:RunInstances",
    "Resource": "arn:aws:ec2:*:*:instance/*",
    "Condition": { "Null": { "aws:RequestTag/team": "true" } }
  }]
}

Preventive guardrails and commitment hygiene: stop spend before it starts

The fastest signal still trails the spend by a day. The cheapest dollar is the one never charged, so the top tier of governance is preventive: org-wide Service Control Policies that block the expensive thing before it can run. An SCP can deny launching oversized or GPU instance families outside an approved allow-list, deny operating in Regions you don’t use (shrinking the leaked-key blast radius to zero in those Regions), and deny creating public S3 buckets or public AMIs. A guardrail is strictly better than an alert for known-bad patterns: the alert tells you the GPU fleet is burning money; the SCP means it was never allowed to launch.

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "DenyExpensiveAndGpuInstanceTypes",
    "Effect": "Deny",
    "Action": "ec2:RunInstances",
    "Resource": "arn:aws:ec2:*:*:instance/*",
    "Condition": {
      "ForAnyValue:StringLike": { "ec2:InstanceType": ["p4d.*", "p5.*", "x2*", "u-*"] }
    }
  }]
}

The second half of hygiene is the ongoing review of the commitments lesson 01 introduced. Lesson 01 taught which purchase option to buy; governance is the routine that keeps those purchases earning their discount, watched through two distinct metrics. Coverage asks “what fraction of eligible usage is covered by a commitment?” — low coverage means you’re paying On-Demand for steady baseline you could have committed (overpay). Utilization asks “what fraction of what I committed am I actually using?” — low utilization means you bought capacity you’re not consuming (waste). The classic failure mode is buying a 3-year Savings Plan or RI, then changing architecture — migrating off the instance family, moving to Fargate, or shrinking the fleet — and paying every month for committed capacity that no longer matches reality. Compute Optimizer and Cost Explorer’s coverage/utilization reports turn this into a monthly cadence: under-coverage and under-utilization are both review triggers, and neither is visible unless someone owns the check.

Pick the best fit

A 60-account Organization keeps getting surprise bills weeks after a runaway resource started — last month a forgotten GPU fleet, this month a recursive Lambda. You want the earliest possible signal on the next one, scoped enough to name an owner. Pick the primary control to stand up first.

Quiz

A leaked access key launches large GPU instances. Your team has a single account-wide monthly cost Budget set at 100% of last month's total. When does the runaway most plausibly become visible, and what would have caught it sooner?

Recall before you leave
  1. 01
    Why does a runaway AWS resource burn money for weeks before anyone notices, and what two kinds of control fix that?
  2. 02
    Walk through how allocation, accountability, and preventive guardrails fit together in cost governance.
Recap

AWS bills in arrears, so the most expensive property of the bill is its latency: you’re metered every second but the invoice is monthly and lands after the fact, leaving a 30-plus-day blind spot in which a forgotten GPU fleet, a recursive Lambda, an egress loop, or a leaked key mining crypto burns at a steady rate — a $2,000/day resource is $60,000 by the time anyone sees it. Optimization can’t help, because it only lowers the cost of things you already know you run; the surprise bill needs a shorter feedback loop and guardrails. Now when you spin up a new account or project, before writing a single line of code, ask: is there a budget with a forecasted-to-exceed alert, and does every resource carry a tag that names an owner? Shorten the loop with AWS Budgets (cost, usage, coverage, or utilization budgets alerting at 80%, 100%, and forecasted-to-exceed, optionally with a budget action that auto-applies an IAM/SCP restriction or stops the resource) and AWS Cost Anomaly Detection (ML baselines per service, account, or tag that flag a spike within about a day with no threshold to maintain) — Budgets enforce known limits, anomaly detection catches the unknown unknowns, and both must be scoped per team/service via tags to be actionable rather than just ‘you spent too much.’ Make them actionable by attributing spend first: cost allocation tags plus Organizations consolidated billing enable showback and chargeback, untagged resources are the blind spot, and a tag policy plus an SCP that denies create-without-tags keeps allocation near-100%. Then prevent the worst spend outright with SCPs that block expensive and GPU instance families, unused Regions, and public resources org-wide, and keep commitments earning their discount through ongoing coverage (low = overpay) and utilization (low = waste) review — because buying a 3-year commitment and then changing architecture, or running with no budget and no anomaly monitor at all, is exactly how the surprise bill comes back.

Practice

Start at the top. Tasks go easiest → hardest: recall a fact, apply it to a case, then a senior-level stretch. Open one, attempt it, then reveal.

recallapplystretch0 of 5 done

Something unclear?

Ask a question about this lesson. Questions are anonymous and go straight to the author to make the lesson better.

shortcuts expand
search
K
prev piece
k
next piece
j
cycle tier
t
this menu
?
sources3
expand
  1. 01
  2. 02
  3. 03

Trademarks belong to their respective owners. Editorial reference only.