Skip to content

iam-adnan/aws-finops-cost-alert

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 

Repository files navigation

💰 AWS FinOps Real-Time Cost Alert

Instant Slack notifications whenever a billable AWS resource is created — with who created it, estimated daily cost, and estimated monthly cost.

AWS Lambda Python EventBridge CloudTrail Slack FinOps


📋 Table of Contents


What This Does

Every time someone in your AWS account creates a resource that costs money, this tool:

  1. Detects it in real time via CloudTrail + EventBridge
  2. Identifies who created it — IAM user name, SSO role session, or flags ROOT account usage
  3. Estimates the cost — daily and monthly based on on-demand pricing
  4. Sends a Slack alert with full details, severity badge, and direct links to Cost Explorer

No more surprise AWS bills. No more "who spun up that m5.4xlarge and forgot about it."


How It Works

Someone creates an AWS resource
          │
          ▼
   AWS CloudTrail
   (logs the API call)
          │
          ▼
   Amazon EventBridge
   (matches Create* events)
          │
          ▼
   AWS Lambda Function
   (Python 3.12)
          │
    ┌─────┴──────┐
    │  Extracts  │
    │  • Service │
    │  • Who     │
    │  • Config  │
    │  • Cost    │
    └─────┬──────┘
          │
          ▼
   Slack Webhook
   (instant notification)

The Lambda function runs in under 500ms and uses zero external dependencies — pure Python standard library only. No pip install needed.


Architecture

┌─────────────────────────────────────────────────────────────────────┐
│                        AWS Account                                  │
│                                                                     │
│  User/Role creates resource                                         │
│         │                                                           │
│         ▼                                                           │
│  ┌─────────────────┐                                                │
│  │  AWS CloudTrail │  ← Logs every API call                        │
│  │  (Management    │                                                │
│  │   Events)       │                                                │
│  └────────┬────────┘                                                │
│           │ Create* events                                          │
│           ▼                                                         │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │              Amazon EventBridge                             │   │
│  │                                                             │   │
│  │  Rule: finops-resource-creation-alert                       │   │
│  │  Pattern: 26 Create events across 18 AWS services           │   │
│  └───────────────────────┬─────────────────────────────────────┘   │
│                          │ Invoke                                   │
│                          ▼                                          │
│  ┌─────────────────────────────────────────────────────────────┐   │
│  │              AWS Lambda Function                            │   │
│  │              finops-cost-alert                              │   │
│  │              Python 3.12 | 256MB | 30s timeout              │   │
│  │                                                             │   │
│  │  1. Parse CloudTrail event detail                           │   │
│  │  2. Identify who created the resource                       │   │
│  │  3. Look up pricing (26 services, 100+ instance types)      │   │
│  │  4. Calculate daily + monthly cost estimate                 │   │
│  │  5. Build rich Slack Block Kit message                      │   │
│  │  6. POST to Slack webhook                                   │   │
│  └───────────────────────┬─────────────────────────────────────┘   │
│                          │                                          │
└──────────────────────────┼──────────────────────────────────────────┘
                           │
                           ▼
              ┌────────────────────────┐
              │    Slack Channel       │
              │  #aws-cost-alerts      │
              │                        │
              │  🔴 HIGH SPEND         │
              │  New EC2 m5.4xlarge    │
              │  Created by: john.doe  │
              │  Est: $4.61/day        │
              │  Est: $138.24/month    │
              └────────────────────────┘

Supported AWS Services

The Lambda has a built-in pricing database covering 26 resource types across 18 AWS services:

Compute

Service Event Detected Pricing Model
EC2 RunInstances Per instance-hour (100+ instance types)
AWS Lambda CreateFunction Per request + GB-second
SageMaker CreateNotebookInstance, CreateEndpoint Per instance-hour

Database

Service Event Detected Pricing Model
RDS CreateDBInstance Per instance-hour + storage
Aurora CreateDBCluster Per instance-hour (Multi-AZ aware)
ElastiCache CreateCacheCluster, CreateReplicationGroup Per node-hour
DynamoDB CreateTable Per request or provisioned capacity
Redshift CreateCluster Per node-hour
OpenSearch CreateDomain Per instance-hour

Storage

Service Event Detected Pricing Model
EBS CreateVolume Per GB-month (gp2/gp3/io1/io2/st1/sc1)
S3 CreateBucket Per GB-month + requests
EFS CreateFileSystem Per GB-month

Networking

Service Event Detected Pricing Model
NAT Gateway CreateNatGateway Per hour + per GB processed
ALB / NLB CreateLoadBalancer Per hour + LCU/NLCU
CloudFront CreateDistribution Per request + data transfer
VPN CreateVpnConnection Per hour

Analytics & Messaging

Service Event Detected Pricing Model
Kinesis CreateStream Per shard-hour
Glue CreateJob Per DPU-hour
SNS CreateTopic Per request
SQS CreateQueue Per request

Security & DevOps

Service Event Detected Pricing Model
Secrets Manager CreateSecret Per secret per month
EKS CreateCluster Per cluster-hour

Slack Notification Preview

╔══════════════════════════════════════════════════════════╗
║  🖥️  New AWS Resource Created — Amazon EC2               ║
╠══════════════════════════════════════════════════════════╣
║                                                          ║
║  Service          Amazon EC2                             ║
║  Severity         🔴 HIGH SPEND                          ║
║  Resource ID      i-0abc123def456789a, i-0abc123def...   ║
║  Configuration    2x `m5.xlarge`                         ║
║  Region           us-east-1                              ║
║  Event            RunInstances                           ║
║  Account          Production (123456789012)              ║
║  Time (UTC)       2026-03-20T10:30:00Z                   ║
║                                                          ║
╠══════════════════════════════════════════════════════════╣
║  👤 Created By                                           ║
║     Name:  john.doe                                      ║
║     Type:  IAM User                                      ║
║     ARN:   arn:aws:iam::123456789012:user/john.doe        ║
╠══════════════════════════════════════════════════════════╣
║  💰 Estimated Cost                                       ║
║     Per day:   ~$9.22                                    ║
║     Per month: ~$276.48                                  ║
║     • EBS: ~$0.64/mo per 8GB gp3 root volume (default)  ║
║                                                          ║
║  ⚠️  These are estimates based on on-demand pricing      ║
║     in us-east-1. Actual charges depend on usage,        ║
║     data transfer, snapshots, and licensing. Check       ║
║     AWS Cost Explorer for actuals once billing           ║
║     data is available (~24-48h).                         ║
╠══════════════════════════════════════════════════════════╣
║  📊 View in Cost Explorer  |  📋 View in CloudTrail      ║
║  🏷️  Tag your resources to track costs by team/project   ║
╚══════════════════════════════════════════════════════════╝

Severity levels based on estimated monthly cost:

  • 🔴 HIGH SPEND — more than $500/month
  • 🟠 MEDIUM SPEND — $20–$500/month
  • 🟡 LOW SPEND — under $20/month
  • 🔵 PAY-PER-USE — no fixed cost (S3, Lambda, DynamoDB)

Project Structure

aws-finops-cost-alert/
│
├── lambda_function.py          # Main Lambda handler — all logic in one file
│                               # No external dependencies — pure Python stdlib
│
├── setup/
│   ├── iam-policy.json         # IAM policy for Lambda execution role
│   ├── eventbridge-pattern.json # EventBridge rule event pattern
│   └── deploy.sh               # One-script CLI deployment
│
├── tests/
│   └── test_events/
│       ├── ec2_test.json       # Sample EC2 RunInstances event
│       ├── rds_test.json       # Sample RDS CreateDBInstance event
│       └── s3_test.json        # Sample S3 CreateBucket event
│
└── README.md

Prerequisites

  • AWS account with CloudTrail enabled
  • AWS CLI configured (aws configure)
  • Slack workspace with an Incoming Webhook URL
  • Lambda function already created with the code uploaded

Deployment Guide

Step 1 — Upload Lambda code

In the AWS Console go to Lambda → finops-cost-alert → Code and paste the contents of lambda_function.py, then click Deploy.

Or via CLI:

zip finops_cost_alert.zip lambda_function.py
aws lambda update-function-code \
  --function-name finops-cost-alert \
  --zip-file fileb://finops_cost_alert.zip

Step 2 — Set environment variables

In Lambda → Configuration → Environment variables add:

Key Value
SLACK_WEBHOOK_URL https://hooks.slack.com/services/YOUR/WEBHOOK/URL
ACCOUNT_NAME Production (or whatever your account name is)

Step 3 — Run the complete setup script

Copy and paste this entire block into your terminal:

# Auto-detect account and region
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=$(aws configure get region)
LAMBDA_ARN=$(aws lambda get-function \
  --function-name finops-cost-alert \
  --query 'Configuration.FunctionArn' \
  --output text)

echo "Account: $ACCOUNT_ID | Region: $REGION"

# Create IAM policy
aws iam create-policy \
  --policy-name finops-cost-alert-policy \
  --policy-document '{
    "Version":"2012-10-17",
    "Statement":[
      {"Effect":"Allow","Action":["logs:CreateLogGroup","logs:CreateLogStream","logs:PutLogEvents"],"Resource":"arn:aws:logs:*:*:*"},
      {"Effect":"Allow","Action":["cloudtrail:LookupEvents","cloudtrail:GetTrailStatus"],"Resource":"*"},
      {"Effect":"Allow","Action":["pricing:GetProducts","pricing:DescribeServices"],"Resource":"*"},
      {"Effect":"Allow","Action":"sts:GetCallerIdentity","Resource":"*"}
    ]
  }'

# Attach policy to Lambda role
LAMBDA_ROLE=$(aws lambda get-function-configuration \
  --function-name finops-cost-alert \
  --query 'Role' --output text | cut -d'/' -f2)

aws iam attach-role-policy \
  --role-name $LAMBDA_ROLE \
  --policy-arn arn:aws:iam::$ACCOUNT_ID:policy/finops-cost-alert-policy

# Create EventBridge rule
aws events put-rule \
  --name finops-resource-creation-alert \
  --description "FinOps Slack alert on billable resource creation" \
  --event-pattern '{"source":["aws.ec2","aws.rds","aws.s3","aws.elasticloadbalancing","aws.elasticache","aws.eks","aws.kinesis","aws.es","aws.redshift","aws.efs","aws.secretsmanager","aws.cloudfront","aws.glue","aws.sagemaker","aws.lambda","aws.dynamodb","aws.sns","aws.sqs"],"detail-type":["AWS API Call via CloudTrail"],"detail":{"eventName":["RunInstances","CreateDBInstance","CreateDBCluster","CreateNatGateway","CreateLoadBalancer","CreateVolume","CreateBucket","CreateFunction","CreateFunction20150331","CreateCacheCluster","CreateReplicationGroup","CreateCluster","CreateStream","CreateDomain","CreateFileSystem","CreateSecret","CreateTable","CreateDistribution","CreateDistribution2020_05_31","CreateJob","CreateNotebookInstance","CreateEndpoint","CreateTopic","CreateQueue","CreateVpnConnection","CreateVpnGateway"]}}' \
  --state ENABLED \
  --region $REGION

# Add Lambda as target
aws events put-targets \
  --rule finops-resource-creation-alert \
  --targets "Id=FinOpsLambdaTarget,Arn=$LAMBDA_ARN" \
  --region $REGION

# Grant EventBridge permission to invoke Lambda
RULE_ARN=$(aws events describe-rule \
  --name finops-resource-creation-alert \
  --region $REGION \
  --query 'Arn' --output text)

aws lambda add-permission \
  --function-name finops-cost-alert \
  --statement-id EventBridgeInvokeFinOps \
  --action lambda:InvokeFunction \
  --principal events.amazonaws.com \
  --source-arn $RULE_ARN

echo "✅ Setup complete!"

Step 4 — Test it

ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
REGION=$(aws configure get region)

aws lambda invoke \
  --function-name finops-cost-alert \
  --payload "{
    \"version\":\"0\",
    \"source\":\"aws.ec2\",
    \"account\":\"$ACCOUNT_ID\",
    \"region\":\"$REGION\",
    \"detail-type\":\"AWS API Call via CloudTrail\",
    \"detail\":{
      \"eventName\":\"RunInstances\",
      \"eventSource\":\"ec2.amazonaws.com\",
      \"awsRegion\":\"$REGION\",
      \"recipientAccountId\":\"$ACCOUNT_ID\",
      \"eventTime\":\"2026-03-20T10:30:00Z\",
      \"userIdentity\":{
        \"type\":\"IAMUser\",
        \"arn\":\"arn:aws:iam::$ACCOUNT_ID:user/test-user\",
        \"userName\":\"test-user\"
      },
      \"requestParameters\":{
        \"instanceType\":\"m5.xlarge\",
        \"instancesSet\":{\"maxCount\":2}
      },
      \"responseElements\":{
        \"instancesSet\":{
          \"items\":[{\"instanceId\":\"i-0abc123test456789\"}]
        }
      }
    }
  }" \
  --cli-binary-format raw-in-base64-out \
  --output json \
  response.json && cat response.json

Check your Slack channel — you should see a notification within seconds.


Environment Variables

Variable Required Description Example
SLACK_WEBHOOK_URL ✅ Yes Slack incoming webhook URL https://hooks.slack.com/services/T.../B.../xxx
ACCOUNT_NAME Optional Friendly account name shown in alerts Production
CURRENCY Optional Currency symbol (default: USD) USD

IAM Permissions Required

The Lambda execution role needs:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "cloudtrail:LookupEvents",
        "cloudtrail:GetTrailStatus"
      ],
      "Resource": "*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "pricing:GetProducts",
        "pricing:DescribeServices"
      ],
      "Resource": "*"
    }
  ]
}

EventBridge Rule Pattern

The rule listens for 26 specific Create events across 18 AWS services. CloudTrail must be enabled for management events (enabled by default in all accounts).

Important: EventBridge uses CloudTrail events which may have a delay of 5–15 minutes between resource creation and notification delivery. This is a CloudTrail limitation, not a Lambda limitation.


Cost Pricing Database

The Lambda contains an offline pricing database with:

  • 100+ EC2 instance types from t2.nano to p4d.24xlarge
  • 30+ RDS instance types across db.t3, db.m5, db.m6i, db.r5, db.r6g families
  • ElastiCache, OpenSearch, Redshift, SageMaker instance pricing
  • Storage pricing for gp2, gp3, io1, io2, st1, sc1 EBS volumes
  • Network pricing for NAT Gateway, ALB, NLB, CloudFront, VPN
  • Serverless pricing models for Lambda, S3, DynamoDB, Glue, SNS, SQS

All prices are us-east-1 on-demand rates. Reserved instance, Savings Plans, and Spot pricing are not included — actual costs will be lower if you use those.


Testing

Test with a real resource

Create a small EC2 instance or S3 bucket and watch Slack. Note there is a 5–15 minute delay due to CloudTrail event delivery time.

Test immediately with Lambda test event

In Lambda console go to Test → Create new test event and use this payload:

{
  "version": "0",
  "source": "aws.ec2",
  "account": "123456789012",
  "region": "us-east-1",
  "detail-type": "AWS API Call via CloudTrail",
  "detail": {
    "eventName": "RunInstances",
    "eventSource": "ec2.amazonaws.com",
    "awsRegion": "us-east-1",
    "recipientAccountId": "123456789012",
    "eventTime": "2026-03-20T10:30:00Z",
    "userIdentity": {
      "type": "IAMUser",
      "arn": "arn:aws:iam::123456789012:user/your-name",
      "userName": "your-name"
    },
    "requestParameters": {
      "instanceType": "m5.4xlarge",
      "instancesSet": { "maxCount": 3 }
    },
    "responseElements": {
      "instancesSet": {
        "items": [{ "instanceId": "i-0test123456789abc" }]
      }
    }
  }
}

Verify CloudWatch logs

aws logs tail /aws/lambda/finops-cost-alert --follow

Why This Matters

The problem this solves

AWS bills arrive at the end of the month. By then it is too late — someone spun up a p3.8xlarge GPU instance for a test two weeks ago and forgot to terminate it. That is $12,240/month running silently.

Real-world scenarios this catches

  • Developer spins up an oversized RDS instance for testing → immediate alert
  • CI/CD pipeline accidentally creates a NAT Gateway in every deploy → caught instantly
  • New team member creates resources without tagging → flagged with their identity
  • Root account used to create resources → ⚠️ warning sent immediately
  • Accidental Multi-AZ RDS in dev environment → double cost detected

FinOps best practices this enables

  • Real-time visibility — know about costs as they happen, not at month end
  • Accountability — every resource is tied to the person who created it
  • Tagging enforcement — the alert reminds teams to tag resources
  • Budget awareness — teams see the cost impact of their decisions immediately

Contributing

Pull requests welcome. When adding a new service:

  1. Add the hourly/monthly price to the pricing database at the top
  2. Add an estimator function following the pattern of existing ones
  3. Register the event name in EVENT_MAP
  4. Add a test event JSON in tests/test_events/

Author

Adnan — FinOps and Cloud Infrastructure Engineer


Prices are based on AWS on-demand rates for us-east-1 as of March 2026. Always verify current pricing at aws.amazon.com/pricing.

About

Real-time Slack alerts when billable AWS resources are created — shows who created it, estimated daily cost, and estimated monthly cost. Powered by Lambda + EventBridge + CloudTrail. Supports 26 resource types across 18 AWS services.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages