Alex Chesters


Creating an AWS Budget with alarms

Keeping track of your AWS costs is one of the most overlooked aspects of using the platform. I’ve lost track of the amount of time I’ve seen forum posts, Reddit questions etc from people who have woke up one morning with a huge invoice that’s taken them by surprise. Whilst you can (and should) create a billing alarm at the account level , this post will cover using AWS Budgets to monitor your spending.

Why AWS Budgets?

A common approach to AWS account management is to have two or three separate AWS accounts - separate development and production accounts with an optional sandbox account. As each account will likely contain multiple independent services, how do you keep track of how much an individual service is costing? That’s where AWS Budgets comes in.

AWS Budgets allow you to set up custom budgets that can easily alert you when you reach or exceed any of your pre-defined thresholds. These thresholds can be relative as well as absolute values and AWS Budgets also allows you to monitor your EC2 Reserved Instances usage.

How to create a budget

I’m a big believer in Infrastructure as Code , so this post will show you how to create a budget with AWS CloudFormation . In order to create our budget (and alarm) we’ll need to create a CloudFormation template that has three resources: an SNS topic , an SNS topic policy and a budget .

SNS topic

The CloudFormation syntax for an SNS topic is pretty self-explanatory so I won’t go into too much detail on it; if you need it, you can read more information on the docs . The below example creates an SNS topic with a single subscription - Billy Bob’s email address.

{
  "Type": "AWS::SNS::Topic",
  "Properties": {
    "Subscription": [
      {
        "Endpoint": "bill.bob@gmail.com",
        "Protocol": "email"
      }
    ]
  }
}

SNS topic policy

An SNS topic policy provides a convenient way to associate an IAM policy to an SNS topic. Again, the CloudFormation syntax for an SNS topic policy is fairly simple so I won’t explain it in detail in this post. This example policy allows AWS Budgets (budgets.amazonaws.com) to publish a message to an SNS topic (EmailTopic).

{
  "Type": "AWS::SNS::TopicPolicy",
  "Properties": {
    "PolicyDocument": {
      "Statement": [
        {
          "Effect": "Allow",
          "Principal": {
            "Service": "budgets.amazonaws.com"
          },
          "Action": "sns:Publish",
          "Resource": {
            "Ref": "EmailTopic"
          }
        }
      ]
    },
    "Topics": [
      {
        "Ref": "EmailTopic"
      }
    ]
  }
}

Budget

This is our main resource so I’ll explain it in a bit more depth. Our budget resource is going to contain two aspects - the budget itself and our notifications (these can essentially be thought of as alarms). The example we’ll use below will create a monthly budget of $100 and we’ll create an alarm to alert us if we’re ever forecast to exceed that.

{
  "Type": "AWS::Budgets::Budget",
  "Properties": {
    "NotificationsWithSubscribers": [
      {
        "Subscribers": [
          {
            "SubscriptionType": "SNS",
            "Address": {
              "Ref": "EmailTopic"
            }
          }
        ],
        "Notification": {
          "ComparisonOperator": "GREATER_THAN",
          "NotificationType": "FORECASTED",
          "Threshold": "100",
          "ThresholdType": "PERCENTAGE"
        }
      }
    ],
    "Budget": {
      "BudgetName": "my-first-budget",
      "BudgetLimit": {
        "Amount": "100",
        "Unit": "USD"
      },
      "TimeUnit": "MONTHLY",
      "BudgetType": "COST",
      "CostFilters": {
        "TagKeyValue": [
          "user:<TAG_NAME>$<TAG_VALUE>"
        ]
      }
    }
  }
}

The CostFilters property is where we can focus our budget on what we really want to monitor. I tag all resources (S3 bucket, CloudFront etc) associated with this website like so:

{
  "Key": "ComponentName",
  "Value": "alexchestersdotcom"
}

I can then use this tag in a CostFilter to monitor the costs on my personal website:

{
  "TagKeyValue": [
    "user:ComponentName$alexchestersdotcom"
  ]
}

Further reading

One thing I’ve noticed whilst creating budget alarms is the documentation around the CostFilters property is pretty lacking - the best I’ve found so far is actually in the Terraform documentation .

So there we go - hopefully you’ve learnt something new about how to keep track of your AWS costs. If you find it useful I’ve created a gist showing an example CloudFormation template that you can use.

If you have any thoughts, especially if you are doing something differently to monitor your billing, do leave a comment below.