Skip to main content

CloudWatch Alarms β†’ Slack Integration Reference

πŸ“Š Architecture Overview

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  CloudWatch     β”‚
β”‚  Alarms         β”‚
β”‚  (RDS/ALB)      β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”‚ 1. Alarm Triggers
         β”‚    (State: OK β†’ ALARM)
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚   SNS Topic     β”‚
β”‚  (PROD_Default_ β”‚
β”‚   CloudWatch_   β”‚
β”‚  Alarms_Topic)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”‚ 2. Publishes Message
         β”‚    (JSON Format)
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚ Lambda Function β”‚
β”‚ (CloudWatch-    β”‚
β”‚  Alarms-To-     β”‚
β”‚  Slack)         β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”¬β”€β”€β”€β”€β”€β”€β”€β”€β”˜
         β”‚
         β”‚ 3. Formats & Sends
         β”‚    (HTTP POST)
         β–Ό
β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Slack Channel  β”‚
β”‚  (via Webhook)  β”‚
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

πŸ”„ Step-by-Step Flow

Step 1: CloudWatch Alarm Triggers

When: CPU > 80% for 15 minutes (3 consecutive 5-min periods)
What: CloudWatch changes alarm state from OK β†’ ALARM
Action: Sends notification to SNS Topic
Example Alarm Configuration:
resource "aws_cloudwatch_metric_alarm" "rds_cpu" {
  alarm_name     = "CW-RDS-AppName-prod-rds-db-CPUUtilization"
  alarm_actions  = [var.sns_topic_arn]  # ← Sends to SNS
  # ...
}

Step 2: SNS Topic Receives & Publishes

SNS Topic ARN: arn:aws:sns:ap-south-1:3AWS-Account-ID-NO5:PROD_Default_CloudWatch_Alarms_Topic
SNS Message Format (JSON):
{
  "Records": [
    {
      "Sns": {
        "Type": "Notification",
        "MessageId": "abc-123-xyz",
        "TopicArn": "arn:aws:sns:ap-south-1:3AWS-Account-ID-NO5:PROD_Default_CloudWatch_Alarms_Topic",
        "Subject": "ALARM: CW-RDS-AppName-prod-rds-db-CPUUtilization",
        "Message": "{...CloudWatch alarm details...}",
        "Timestamp": "2026-01-12T10:30:00.000Z"
      }
    }
  ]
}
SNS has a subscription:
resource "aws_sns_topic_subscription" "lambda_subscription" {
  topic_arn = var.sns_topic_arn
  protocol  = "lambda"
  endpoint  = aws_lambda_function.slack_notifier.arn
}
This tells SNS: β€œWhenever you receive a message, invoke this Lambda function”

Step 3: Lambda Function Processes

Function: CloudWatch-Alarms-To-Slack
Runtime: Python 3.11
Timeout: 30 seconds
Lambda receives the SNS event and:
  1. Extracts the CloudWatch alarm details from SNS message
  2. Parses alarm information (name, state, reason, metrics)
  3. Formats into a beautiful Slack message with colors and emojis
  4. Sends HTTP POST to Slack webhook URL
Lambda Code Flow:
def lambda_handler(event, context):
    # 1. Parse SNS message
    sns_message = json.loads(event['Records'][0]['Sns']['Message'])
    
    # 2. Extract alarm details
    alarm_name = sns_message['AlarmName']
    new_state = sns_message['NewStateValue']
    
    # 3. Format Slack message
    slack_message = format_slack_message(sns_message)
    
    # 4. Send to Slack
    response = requests.post(SLACK_WEBHOOK_URL, json=slack_message)
    
    return {'statusCode': 200}

Step 4: Slack Receives Notification

Slack Message Format:
🚨 CloudWatch Alarm: ALARM

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

πŸ“Œ Alarm Name:
   CW-RDS-AppName-prod-rds-db-CPUUtilization

πŸ”„ State Change:
   OK β†’ ALARM

πŸ“ Reason:
   Threshold Crossed: 3 datapoints [85.0, 87.2, 89.5] 
   were greater than the threshold (80.0)

πŸ“Š Metric Details:
   β€’ Metric: CPUUtilization
   β€’ Namespace: AWS/RDS
   β€’ Threshold: > 80.0
   β€’ DBInstance: AppName-prod-rds-db

🌍 Region: ap-south-1
⏰ Time: 2026-01-12 10:30:00 UTC

━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

πŸ” Permissions & Security

Lambda IAM Role Permissions

# Lambda needs:
1. Basic Lambda execution (write to CloudWatch Logs)
2. NO other AWS permissions needed (just HTTP to Slack)

resource "aws_iam_role" "lambda_slack_role" {
  # Trust policy: Allow Lambda service to assume this role
  assume_role_policy = {
    "Effect": "Allow",
    "Principal": { "Service": "lambda.amazonaws.com" },
    "Action": "sts:AssumeRole"
  }
}

SNS β†’ Lambda Permission

# Allow SNS to invoke Lambda
resource "aws_lambda_permission" "allow_sns" {
  statement_id  = "AllowExecutionFromSNS"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.slack_notifier.function_name
  principal     = "sns.amazonaws.com"
  source_arn    = var.sns_topic_arn
}
This permission says: β€œSNS topic can trigger this Lambda function”

πŸ“¦ Resources Created

ResourceNamePurpose
IAM RoleCloudWatch-Alarms-To-Slack-RoleLambda execution role
Lambda FunctionCloudWatch-Alarms-To-SlackProcesses alarms & sends to Slack
CloudWatch Log Group/aws/lambda/CloudWatch-Alarms-To-SlackLambda execution logs
SNS Subscription(auto-generated)Connects SNS β†’ Lambda
Lambda PermissionAllowExecutionFromSNSAllows SNS to invoke Lambda

πŸ§ͺ Testing Flow

Test 1: Slack Webhook (Direct)

curl -X POST https://hooks.slack.com/services/T09CNE15C4E/B09E3K0JLTA/... \
  -H 'Content-Type: application/json' \
  -d '{"text": "Test from curl"}'
βœ… Verifies: Slack webhook URL is valid

Test 2: Lambda Function (Direct)

aws lambda invoke \
  --function-name CloudWatch-Alarms-To-Slack \
  --payload '{"Records":[{"Sns":{"Message":"..."}}]}' \
  output.json
βœ… Verifies: Lambda can parse messages and send to Slack

Test 3: SNS Topic β†’ Lambda

aws sns publish \
  --topic-arn arn:aws:sns:ap-south-1:3AWS-Account-ID-NO5:PROD_Default_CloudWatch_Alarms_Topic \
  --message '{"AlarmName":"TEST",...}'
βœ… Verifies: SNS β†’ Lambda integration works

Test 4: CloudWatch Alarm β†’ SNS

# Trigger a real alarm by breaching threshold
# Or use AWS Console to set alarm to ALARM state
βœ… Verifies: Complete end-to-end flow

🎨 Message Formatting

Color Coding

πŸ”΄ ALARM   β†’ Red (#ff0000)    - Critical issue
🟒 OK      β†’ Green (#36a64f)  - All good
🟑 INSUFFICIENT_DATA β†’ Yellow (#ffcc00) - Not enough data

Emojis Used

🚨 - Alert header
πŸ“Œ - Alarm name
πŸ”„ - State change
πŸ“ - Reason
πŸ“Š - Metric details
🌍 - Region
⏰ - Timestamp

Message Structure

1. Header with emoji + state
2. Separator line
3. Alarm name (bold)
4. State transition (with arrow)
5. Detailed reason
6. Metric information
7. Dimensions (RDS instance, ALB name, etc.)
8. Region and timestamp
9. Footer separator

πŸ”§ Configuration

Environment Variables

environment {
  variables = {
    SLACK_WEBHOOK_URL = "https://hooks.slack.com/services/..."
  }
}

Customization Options

Change Slack Channel:
  • Generate new webhook URL from Slack
  • Update slack_webhook_url in locals block
Modify Message Format:
  • Edit lambda_function.py
  • Update the format_slack_message() function
Add More Details:
  • Parse additional fields from CloudWatch alarm JSON
  • Add to Slack message payload
Filter Alarms:
  • Add logic in Lambda to filter by alarm name prefix
  • Only send specific alarms to Slack

πŸ“Š Monitoring & Troubleshooting

CloudWatch Logs

# View Lambda logs
aws logs tail /aws/lambda/CloudWatch-Alarms-To-Slack --follow

# Search for errors
aws logs filter-log-events \
  --log-group-name /aws/lambda/CloudWatch-Alarms-To-Slack \
  --filter-pattern "ERROR"

Common Issues

❌ Slack message not appearing:
  • Check Lambda logs: /aws/lambda/CloudWatch-Alarms-To-Slack
  • Verify webhook URL is correct
  • Check Lambda execution errors
❌ Lambda not triggered:
  • Verify SNS subscription is β€œConfirmed” (not Pending)
  • Check Lambda permission for SNS
  • Verify alarm has SNS topic in alarm_actions
❌ Message format broken:
  • Check CloudWatch alarm JSON structure
  • Verify Lambda Python code syntax
  • Test with sample alarm JSON

πŸ’° Cost Estimation

Monthly Costs (Approximate)

Lambda Invocations: 
  - 1000 alarms/month Γ— $0.20 per 1M requests = ~$0.0002

Lambda Compute:
  - 1000 invocations Γ— 1 second Γ— 256MB = ~$0.0001

CloudWatch Logs:
  - 1 GB ingestion = ~$0.50
  - Storage (14 days retention) = ~$0.03

SNS:
  - 1000 notifications = ~$0.0005

Total: ~$0.50 - $1.00/month (for moderate alarm volume)

πŸ“š References

πŸš€ Deployment Checklist

  • Slack webhook URL configured
  • Lambda function code created (lambda_function.py)
  • Terraform configuration created (SLACK-ALARMS.tf)
  • Variables configured (variables.tf)
  • Run terraform plan to preview changes
  • Run terraform apply to deploy
  • Test Lambda function manually
  • Verify SNS subscription is confirmed
  • Trigger a test alarm to verify end-to-end flow
  • Monitor CloudWatch Logs for any errors