Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help


title: “AWS Budgets — Cost Controls & Budget Actions” created: 2026-08-09 updated: 2026-08-09 type: knowledge tags:

  • aws
  • budgets
  • cost-management
  • iam
  • monitoring
  • certification

AWS Budgets — Cost Controls & Budget Actions

What It Is

AWS Budgets is the native service for monitoring and reacting to spending on an AWS account. It allows you to define monthly cost thresholds and trigger alerts or automatic actions (Budget Actions) when those thresholds are reached.

Why It Matters

AWS does not offer a hard cap that automatically shuts down all services when a spending amount is reached. This is by design (availability > cost protection). You must configure your own guardrails.

Key Concepts

What AWS Budgets Can Do

FeatureDescription
Email alertsNotification when X% of the budget is consumed
Budget Actions — IAM PolicyAttach a deny policy that blocks creation of new resources
Budget Actions — SCPApply a Service Control Policy (requires AWS Organizations)
Budget Actions — Stop instancesTarget specific EC2/RDS instances

What AWS Budgets Cannot Do Natively

  • Automatically stop all running resources
  • Guarantee an absolute monthly cost maximum (already-consumed data is still billed)
  • Block storage charges (EBS, S3) and network charges (NAT Gateway, data transfer)

Budget Controls for AWS (Open-Source Solution)

An AWS Labs solution that goes beyond native Budgets:

  • Tag BudgetControlAction: Stop → stops resources at 90% of budget
  • Tag BudgetControlAction: Terminate → deletes resources (irreversible)
  • Supports EC2, RDS Aurora, SageMaker, OpenSearch
  • GitHub: https://github.com/awslabs/budget-controls-for-aws

How Budget Actions Work — Architecture

┌─────────────────────────────────────────────────────────────────────────┐
│                           AWS Account                                    │
│                                                                         │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │                         AWS BUDGETS                               │  │
│  │                                                                   │  │
│  │  ┌─────────────────────────────────┐                              │  │
│  │  │  Budget (monthly, $X)           │                              │  │
│  │  └────────────┬────────────────────┘                              │  │
│  │               │                                                   │  │
│  │               │ triggers at configured thresholds                 │  │
│  │               ▼                                                   │  │
│  │  ┌─────────────────────────────────┐                              │  │
│  │  │  📧 Email Alerts                │                              │  │
│  │  └─────────────────────────────────┘                              │  │
│  │                                                                   │  │
│  │               │ triggers at 100%                                  │  │
│  │               ▼                                                   │  │
│  │  ┌─────────────────────────────────────────────────────────────┐  │  │
│  │  │  Budget Action (AUTOMATIC)                                  │  │  │
│  │  │  Type: APPLY_IAM_POLICY                                     │  │  │
│  │  └────────────┬────────────────────────────────────────────────┘  │  │
│  │               │                                                   │  │
│  └───────────────┼───────────────────────────────────────────────────┘  │
│                  │ assumes                                               │
│                  ▼                                                       │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │  IAM Role: Execution Role                                         │  │
│  │  Trust: budgets.amazonaws.com                                     │  │
│  │  Permissions: iam:AttachRolePolicy, iam:DetachRolePolicy          │  │
│  └────────────┬──────────────────────────────────────────────────────┘  │
│               │ attaches/detaches                                       │
│               ▼                                                         │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │  IAM Policy: Deny Policy                                          │  │
│  │  Effect: DENY                                                     │  │
│  │  Actions: ec2:RunInstances, rds:CreateDBInstance, etc.            │  │
│  └────────────┬──────────────────────────────────────────────────────┘  │
│               │ attached to (when budget exceeded)                      │
│               ▼                                                         │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │  IAM Role: Your SSO Role                                          │  │
│  │  (assumed by your Identity Center user)                           │  │
│  │                                                                   │  │
│  │  Normally: AdministratorAccess (Allow *)                          │  │
│  │  When budget exceeded: + Deny Policy (Deny > Allow → blocked)     │  │
│  └───────────────────────────────────────────────────────────────────┘  │
│                  ▲                                                       │
│                  │ assumes via SSO                                       │
│                  │                                                       │
│  ┌───────────────────────────────────────────────────────────────────┐  │
│  │  IAM Identity Center User                                         │  │
│  └───────────────────────────────────────────────────────────────────┘  │
│                                                                         │
└─────────────────────────────────────────────────────────────────────────┘

Step-by-Step Explanation

Setting up a Budget Action requires 4 steps in sequence. Each builds on the previous one.

Step 1           Step 2               Step 3               Step 4
─────────        ─────────            ─────────            ─────────
 BUDGET     →    DENY POLICY    →    EXECUTION ROLE   →   BUDGET ACTION
 (the watcher)   (the weapon)        (the arm)            (the link)

 "monitors       "here's what        "here's who is       "when X happens,
  spending"       we forbid"          allowed to act"      use the arm to
                                                           apply the weapon"

Step 1 — Create the Budget

Creates a counter that monitors monthly spending and sends email alerts.

IAM concept: None. This is passive monitoring only.


Step 2 — Create the Deny Policy

Creates a JSON “rules document” stored in IAM. The document says: “whoever has this policy attached cannot do ec2:RunInstances, rds:CreateDBInstance, etc.”

IAM concept: A Policy is just a JSON document. It does nothing until it’s attached to someone (user, group, or role). It’s like a “forbidden” sign sitting in a drawer — it forbids nothing until you hang it somewhere.


Step 3 — Create the Execution Role

Two sub-steps:

  • 3a: Create a role that only the budgets.amazonaws.com service can assume. This is the “trust policy” — it answers “WHO can become this role?”
  • 3b: Give this role permission to attach and detach policies on other roles. This is the “permissions policy” — it answers “WHAT can this role do once assumed?”

IAM concept: A Role has two faces:

┌─────────────────────────────────────────────────────┐
│  IAM Role                                           │
│                                                     │
│  ┌─────────────────────────┐                        │
│  │  Trust Policy           │  ← WHO can assume it   │
│  │  (assume-role-policy)   │     (here: Budgets)    │
│  └─────────────────────────┘                        │
│                                                     │
│  ┌─────────────────────────┐                        │
│  │  Permissions Policy     │  ← WHAT it can do      │
│  │  (inline or managed)    │     (here: attach/     │
│  │                         │      detach policies)  │
│  └─────────────────────────┘                        │
│                                                     │
└─────────────────────────────────────────────────────┘

Analogy: It’s like a car key. The trust policy says “only the restaurant valet can use this key”. The permissions policy says “this key only allows starting the engine and moving 10m” (not taking the highway).


Step 4 — Create the Budget Action

Links everything together. This is the “recipe” that tells AWS Budgets:

  • When: budget reaches 100%
  • How: assume the Execution Role
  • What: attach the Deny Policy
  • On whom: your SSO Role
  • Approval: automatic (no human approval needed)

Why Deny Wins Over Allow

AWS evaluates permissions in this order:

  1. Is there an explicit DENY?  ──→ YES → DENIED (stop)
                                      │
                                     NO
                                      │
  2. Is there an explicit ALLOW? ──→ YES → ALLOWED
                                      │
                                     NO
                                      │
  3. Denied by default (implicit deny)

Even if AdministratorAccess grants Allow * (everything is allowed), a single explicit Deny on ec2:RunInstances is enough to block it. Deny always wins.

How to Lift the Block

When the budget is exceeded and the action fires, you have 3 options:

  1. CLI — detach the deny policy from the SSO role (aws iam detach-role-policy)
  2. Console — IAM → Roles → find SSO role → Permissions → remove the deny policy
  3. Budgets reverse — aws budgets execute-budget-action ... --execution-type REVERSE_ACTION

After lifting the block, if spending is still > 100%, the action will re-trigger after a few hours. Fix the cost source first, or temporarily increase the budget.

Gotchas

  • Budget Actions do not stop already-running resources — they only block future creations
  • NAT Gateways cost ~$0.045/h even with no traffic — destroy them after each lab
  • Alerts have a delay (a few hours) because AWS Budgets relies on billing data which is not real-time
  • Free Tier is not covered by budgets — a free resource that exits Free Tier will start billing without prior alert
  • Budget Actions require an execution role (IAM Role) with permission to attach policies

See Also

  • [[../../aws/aws-budgets-config]] — actual configuration and source commands for our account
  • [[../security/README]]