So I wanted to have a better alarm system for when AWS hits us with unexpected costs. Itβs better to know thereβs something wrong rather quickly and not suffer hundreds of dollars costs for something you donβt really need or want.
The AWS provided alarm checks for hikes on a monthly basis. Hereβs the doc they published. So thatβs an alarm that sounds when your estimated bill is going to be higher than the budgeted amount, or what you had in mind in the first place. Not very useful honestly in our case. It will just be too late.
The only alternative I found was creating a daily check, that will compare yesterdayβs costs against a max_amount set by default. Letβs say you want to have your daily bill not exceed 5$US.
For ease of use and maintainability, Iβm using a lambda function triggered by a cron (EventBridge rule) for the daily checks. And Iβm sending the Alarm using an SNS topic, this way I can subscribe to it by email, or send it to our Mattermost channel, etc.
Hereβs the code:
import os
import json
import boto3
from datetime import datetime, timedelta
def lambda_handler(event, context):
yesterday = datetime.strftime(datetime.now() - timedelta(1), '%Y-%m-%d')
twodaysago = datetime.strftime(datetime.now() - timedelta(2), '%Y-%m-%d')
cost_metric = os.environ.get('cost_metric')
max_amount = os.environ.get('max_amount')
ce = boto3.client('ce')
sns = boto3.client('sns')
result = ce.get_cost_and_usage(
TimePeriod={'Start': twodaysago, 'End': yesterday},
Granularity='DAILY',
Metrics=[cost_metric]
)
total_amount = result['ResultsByTime'][0]
.get('Total').get(cost_metric).get('Amount')
if total_amount > max_amount:
sns_topic = sns.create_topic(Name='BillingAlert')
sns.publish(
TopicArn=sns_topic.get('TopicArn'),
Message='Total cost "{} USD" exceeded max_amount rate: {}'
.format(total_amount, max)
)
return {
'statusCode': 200,
'body': json.dumps('cost check: {}'.format(total_amount))
}
Note that you will need to add a couple of environment variables to Lambda: cost_metric
and max_amount
.
And add the following permissions to the role used by the lambda function: ce:GetCostAndUsage
, sns:Publish
and sns:CreateTopic
. Something like this:
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "VisualEditor0",
"Effect": "Allow",
"Action": "ce:GetCostAndUsage",
"Resource": "*"
},
{
"Sid": "VisualEditor1",
"Effect": "Allow",
"Action": [
"logs:CreateLogStream",
"sns:Publish",
"sns:CreateTopic",
"logs:PutLogEvents"
],
"Resource": [
"arn:aws:logs:us-east-1:*:log-group:/aws/lambda/checkDailyCosts:*",
"arn:aws:sns:*:*:*"
]
},
{
"Sid": "VisualEditor2",
"Effect": "Allow",
"Action": "logs:CreateLogGroup",
"Resource": "arn:aws:logs:us-east-1:*:*"
}
]
}
After thatβs setup, go to your SNS topic (created by Lambda if it doesnβt exist) and subscribe to it. There you go, daily checks and an alarm if the bill is higher than expected.
Top comments (0)