Skip to content

Manage Subscription Budgets

The engineer's guide to subscription budgets and cost alerts. Use this runbook to:

  • Change a subscription's monthly budget.
  • Change who receives budget and cost anomaly alerts.
  • Respond to a budget or anomaly alert.

For how budgets, FinOpsId and the monthly review fit together, see Budgets and Cost Allocation.

A budget alerts, it doesn't stop anything

Azure budgets send email. They don't stop resources, block deployments or cap spend. Someone has to read the alert and act.

What every subscription gets

Vending creates two cost resources on every subscription, from the same two inputs in its <name>.tf:

Resource Name Fires when
Budget budget-<name>-monthly Actual spend passes 80%; actual spend passes 100%; forecast spend for the month passes 100%
Cost anomaly alert caa-<name> Azure's anomaly detection sees unusual daily spend

Budget alerts go to budget_alert_emails and to anyone holding Owner or Contributor on the subscription at that moment. Anomaly alerts go to budget_alert_emails only.

The amount is in the billing account's currency (EUR) and resets on the 1st of each month.

The projects

Project Lane Holds
subscription-vending-workload B budget_amount and budget_alert_emails in each workload subscription's <name>.tf. CI applies on merge.
subscription-vending-platform A The same inputs for platform subscriptions. You apply with ./apply.ps1.
terraform-azurerm-subscription-budget — The thresholds and contact roles. Change these here only if every subscription should change.

Change the budget amount

📁 subscription-vending-*: 📃 <name>.tf

  budget_amount       = 150
  budget_alert_emails = ["neil@grinntec.net"]

Set it to what the workload should cost in a normal month, plus a margin, not to what it cost last month. If the budget is set at the bill, the 80% alert fires every month and people learn to ignore it.

A rough way to size it:

  1. Cost Management → Cost analysis, scoped to the subscription, last 3 months, grouped by month.
  2. Take the normal month, remove anything that was a one-off, and add any change the team has planned.
  3. Round up by about 20%.

Open an MR and say in the description why the amount changed. The plan should show one in-place update to azurerm_consumption_budget_subscription changing amount, and nothing else. Merge (and for a platform subscription, apply).


Change who gets alerts

  budget_alert_emails = ["payments-team@grinntec.net", "neil@grinntec.net"]

Use a team mailbox or distribution list rather than a person, so the alert still lands when someone leaves. At least one address is required.

The plan should show in-place updates to the budget (every notification block's contact_emails) and to azurerm_cost_anomaly_alert.


Respond to an alert

Alert What it means Do this
Forecast 100% At the current rate, the month will end over budget Look now, while there's time to act. Find what changed (below).
Actual 80% Most of the month's budget is spent Check the date. On the 25th, it's probably fine. On the 10th, find what changed.
Actual 100% Over budget Find what changed. Either fix it, or raise the budget with a reason.
Anomaly One day's spend was unusual for this subscription Find the resource. Anomalies often catch a mistake (a VM left on, a log level left at verbose) days before the budget does.

To find what changed:

  1. Cost Management → Cost analysis, scoped to the subscription.
  2. View Daily costs, grouped by Resource, for this month.
  3. Find the day the line jumped and the resource behind it.
  4. Check that resource's Activity log for who changed it and when. It's also in the central Log Analytics workspace, log-platform-prod:

    AzureActivity
    | where SubscriptionId == "<sub-id>"
    | where TimeGenerated > ago(14d)
    | where OperationNameValue endswith "/write" and ActivityStatusValue == "Success"
    | project TimeGenerated, Caller, OperationNameValue, ResourceGroup, _ResourceId
    | order by TimeGenerated desc
    
  5. Tell the workload owner (the WorkloadOwner tag). Record what you found and what was done in the alert's ticket.


Check it worked

az consumption budget list --subscription <sub-id> \
  --query "[].{name:name, amount:amount, spent:currentSpend.amount}" -o table

In the portal: Cost Management → Budgets, scoped to the subscription, shows budget-<name>-monthly with the new amount. Cost Management → Cost alerts → Anomaly alert rules shows caa-<name> with the new emails.


When it fails

Symptom Cause Fix
Plan wants to replace the budget Someone set budget_start_date on an existing budget, or the budget module changed the name Remove budget_start_date. It's only read when the budget is first created. If the name changed, read the module's release notes before applying.
Azure rejects the budget's start date on a new subscription budget_start_date is before the current month Leave it null. The module uses the 1st of the current month.
Nobody got the alert The email is a person who left, or the mail went to junk Change budget_alert_emails to a team mailbox. Allow azure-noreply@microsoft.com.
The budget shows €0 spent for a new subscription Cost data takes 8–24 hours to appear Wait a day.
Alerts come every month The budget is set at the normal monthly bill Re-size it as in Change the budget amount.