How can I configure a Lambda function to automatically trigger when the budget for an AWS account exceeds a specific threshold?

0

I've created a Lambda script that monitors the budget and triggers when it exceeds a certain range. However, I want the Lambda function to be triggered automatically when the budget exceeds a specific threshold. How can I achieve this using AWS services or configurations?

2 Answers
1
profile picture
EXPERT
answered 2 months ago
profile picture
EXPERT
reviewed 2 months ago
0

Please, check Terraform and CloudFormation stacks here: https://hands-on.cloud/aws-solutions/aws-budget-sqs-lambda-trigger/. Change the Lambda function based on your needs.

Terraform

# Terraform backend
# Replace to your own configuration:
# https://github.com/hands-on-cloud/cloudformation-templates/tree/master/terraform-remote-state-infrastructure
terraform {
  backend "s3" {
    bucket  = "hands-on-cloud-terraform-remote-state-s3"
    key     = "budget-lambda-trigger-demo.tfstate"
    region  = "us-west-2"
    encrypt = "true"
    dynamodb_table = "hands-on-cloud-terraform-remote-state-dynamodb"
  }
}


provider "aws" {
  region = "us-east-1"
}

locals {
  prefix = "budget-lambda-trigger-demo"
}

data "archive_file" "lambda_zip" {
  type        = "zip"
  source_file = "${path.module}/lambda_function.py"
  output_path = "${path.module}/lambda_function.zip"
}

resource "aws_lambda_function" "budget_alert_lambda" {
  filename         = data.archive_file.lambda_zip.output_path
  function_name    = "${local.prefix}-lambda"
  role             = aws_iam_role.lambda_exec_role.arn
  handler          = "lambda_function.lambda_handler"
  source_code_hash = data.archive_file.lambda_zip.output_base64sha256
  runtime          = "python3.11"
}

resource "aws_iam_role" "lambda_exec_role" {
  name = "${local.prefix}-lambda-exec-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [
      {
        Action = "sts:AssumeRole"
        Effect = "Allow"
        Principal = {
          Service = "lambda.amazonaws.com"
        }
      },
    ]
  })
}

resource "aws_sns_topic" "budget_alert_topic" {
  name = "${local.prefix}-budget-alert-topic"
}

resource "aws_sns_topic_subscription" "budget_alert_subscription" {
  topic_arn = aws_sns_topic.budget_alert_topic.arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.budget_alert_lambda.arn
}

resource "aws_lambda_permission" "allow_sns_to_call_lambda" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.budget_alert_lambda.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = aws_sns_topic.budget_alert_topic.arn
}

resource "aws_budgets_budget" "account" {
  name              = "${local.prefix}-budget-aws-monthly"
  budget_type       = "COST"
  limit_amount      = "10"
  limit_unit        = "USD"
  time_period_end   = "2087-06-15_00:00"
  time_period_start = "2024-01-01_00:00"
  time_unit         = "MONTHLY"

  notification {
    comparison_operator        = "GREATER_THAN"
    threshold                  = 90
    threshold_type             = "PERCENTAGE"
    notification_type          = "FORECASTED"
    subscriber_sns_topic_arns = [ aws_sns_topic.budget_alert_topic.arn ]
  }
}

CloudFormation

AWSTemplateFormatVersion: '2010-09-09'
Description: An AWS CloudFormation stack to trigger a Lambda function on AWS budget alerts.
Resources:
  AccountBudget:
    Type: AWS::Budgets::Budget
    Properties:
      Budget:
        BudgetName: budget-lambda-trigger-demo-budget-aws-monthly
        BudgetLimit:
          Amount: 10
          Unit: USD
        TimeUnit: MONTHLY
        BudgetType: COST
        TimePeriod:
          Start: '1609459200' # Equivalent to 2024-01-01_00:00 in epoch seconds
          End: '3666288000'   # Equivalent to 2087-06-15_00:00 in epoch seconds
      NotificationsWithSubscribers:
        - Notification:
            NotificationType: FORECASTED
            ComparisonOperator: GREATER_THAN
            Threshold: 90
            ThresholdType: PERCENTAGE
          Subscribers:
            - SubscriptionType: SNS
              Address: !Ref BudgetAlertTopic

  BudgetAlertLambda:
    Type: AWS::Lambda::Function
    Properties:
      Handler: index.lambda_handler
      Role: !GetAtt LambdaExecutionRole.Arn
      Runtime: python3.8
      Code:
        ZipFile: |
          import json
          def lambda_handler(event, context):
              message = json.loads(event['Records'][0]['Sns']['Message'])
              print(f"Budget Alert: {message}")
              return {
                  'statusCode': 200,
                  'body': json.dumps('Budget alert processed.')
              }
      Timeout: 10

  LambdaExecutionRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: lambda.amazonaws.com
            Action: sts:AssumeRole
      Policies:
        - PolicyName: LambdaLoggingPolicy
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - logs:CreateLogGroup
                  - logs:CreateLogStream
                  - logs:PutLogEvents
                Resource: arn:aws:logs:*:*:*

  BudgetAlertTopic:
    Type: AWS::SNS::Topic

  LambdaInvokePermission:
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName: !Ref BudgetAlertLambda
      Action: lambda:InvokeFunction
      Principal: sns.amazonaws.com
      SourceArn: !Ref BudgetAlertTopic

  BudgetAlertSubscription:
    Type: AWS::SNS::Subscription
    Properties:
      Protocol: lambda
      TopicArn: !Ref BudgetAlertTopic
      Endpoint: !GetAtt BudgetAlertLambda.Arn
answered 2 months ago

You are not logged in. Log in to post an answer.

A good answer clearly answers the question and provides constructive feedback and encourages professional growth in the question asker.

Guidelines for Answering Questions