Skip to content

Instantly share code, notes, and snippets.

@rantav
Last active January 14, 2021 03:18
Show Gist options
  • Save rantav/c096294f6f35c45155b4 to your computer and use it in GitHub Desktop.
Save rantav/c096294f6f35c45155b4 to your computer and use it in GitHub Desktop.
CloudWatch Events to Slack

Sends Cloudwatch Event notifications to Slack

Setup:

  1. Create a slack incoming webhook and get your token
  2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token' Example:
  $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
  {
   "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
   "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
  }
  1. Create a Lambda function and replace all the const with the required data Function name: cloudwatch-event-to-slack You may use the attached test data to test this function (right after you finish the next item)
  2. Give your function's role permission for the kms:Decrypt action. Example:
     {
       "Version": "2012-10-17",
       "Statement": [
         {
           "Effect": "Allow",
           "Action": [
             "kms:Decrypt"
           ],
           "Resource": [
             "<your KMS key ARN>"
           ]
         }
       ]
     }
  1. Create a new CloudWatch Event Rule to send EC2 events to this lambda function Screenshot: http://jmp.sh/uBi6dV8
  2. You may test this by terminating and lanching an EC2 instance. Example output on Slack: aws.ec2 (us-west-2): i-531a188a is shutting-down
  3. Prosper
//
// Sends Cloudwatch Event notifications to Slack
//
//
// Setup:
//
// 1. Create a slack incoming webhook and get your token
// 2. Encrypt this token with KMS and paste the CiphertextBlob at 'Replace with your KMS token'
// Example:
// $ aws kms encrypt --key-id 22e06448-f73c-42c4-b18f-74f91eb7bc1a --plaintext "your slack token"
// {
// "KeyId": "arn:aws:kms:us-west-2:xxxxxxxxxx:key/22e06448-f73c-42c4-b18f-74f91eb7bc1a",
// "CiphertextBlob": "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
// }
// 3. Create a Lambda function and replace all the const with the required data
// Function name: cloudwatch-event-to-slack
// You may use the attached test data to test this function (right after you finish the next item)
// 4. Give your function's role permission for the kms:Decrypt action.
// Example:
// {
// "Version": "2012-10-17",
// "Statement": [
// {
// "Effect": "Allow",
// "Action": [
// "kms:Decrypt"
// ],
// "Resource": [
// "<your KMS key ARN>"
// ]
// }
// ]
// }
//
// 5. Create a new CloudWatch Event Rule to send EC2 events to this lambda function
// Screenshot: http://jmp.sh/uBi6dV8
// 6. You may test this by terminating and lanching an EC2 instance
//
const SLACK_URL = 'https://<your organization>.slack.com/services/hooks/incoming-webhook'; // Replace
const SLACK_CHANNEL_NAME = "#updates-dev"; // Replace with yout own channel name
const SLACK_USERNAME = "webhookbot";
const kmsEncyptedToken = 'Replace with your KMS token'; // Replace
console.log('Loading function');
const AWS = require('aws-sdk');
const url = require('url');
const https = require('https');
const qs = require('querystring');
exports.handler = function(event, context) {
var token = null;
var slackReqOpts = null;
if (token) {
// Container reuse, simply process the event with the key in memory
processEvent(event, context, slackReqOpts);
} else {
const encryptedBuf = new Buffer(kmsEncyptedToken, 'base64');
const cipherText = {CiphertextBlob: encryptedBuf};
const kms = new AWS.KMS();
kms.decrypt(cipherText, function (err, data) {
if (err) {
console.log("Decrypt error: " + err);
context.fail(err);
} else {
token = data.Plaintext.toString('ascii');
const slackUrl = SLACK_URL;
slackReqOpts = url.parse(slackUrl + '?token=' + token);
slackReqOpts.method = 'POST';
slackReqOpts.headers = {'Content-Type': 'application/json'};
processEvent(event, context, slackReqOpts);
}
});
}
};
var processEvent = function(event, context, slackReqOpts) {
var source = event.source;
var region = event.region;
var detail = event.detail;
var instanceId = detail['instance-id'];
var state = detail.state;
var text = [];
text.push(source);
text.push(' (' + region + ')');
text.push(': ');
text.push(instanceId);
text.push(' is ');
text.push(state);
var req = https.request(slackReqOpts, function (res) {
if (res.statusCode === 200) {
context.succeed('posted to slack');
} else {
context.fail('status code: ' + res.statusCode);
}
});
req.on('error', function(e) {
console.log('problem with request: ' + e.message);
context.fail(e.message);
});
req.write(JSON.stringify({
channel: SLACK_CHANNEL_NAME,
username: SLACK_USERNAME,
text: text.join(''),
icon_emoji: ":ghost:"
}));
req.end();
}
{
"version": "0",
"id": "7b14d7de-3adb-4fac-9b90-6dc5019727e3",
"detail-type": "EC2 Instance State-change Notification",
"source": "aws.ec2",
"account": "xxxxxxxxxx",
"time": "2016-01-17T11:03:34Z",
"region": "us-west-2",
"resources": [
"arn:aws:ec2:us-west-2:xxxxxxxxxx:instance/i-531a188a"
],
"detail": {
"instance-id": "i-531a188a",
"state": "shutting-down"
}
}
@jbz
Copy link

jbz commented Nov 3, 2016

Ugh, had such high hopes for this, until I found out there's no AWS Lambda in us-west-1, so cloudwatch can't be configured to send to that. :-/ Sigh, further down the rabbithole...maybe I can ship via SQS...

@nathanleiby
Copy link

In case anyone else is visiting, lambda in us-west-1 was launched Nov 21, 2016 (https://aws.amazon.com/about-aws/whats-new/2016/11/aws-lambda-available-in-us-west-n-california/)

@jeremykoerber
Copy link

Does this still work? When I create an Incoming Webhook in Slack I don't get a token, just a URL:
https://hooks.slack.com/services/TXXXXXX5R/XXXXXX6EA/7se4DXXXXXXXXXXXhWXXKCgWX

@weisiada
Copy link

weisiada commented Dec 3, 2018

how can I create a lambda that recive information from CloudWatch events, change the instance Id for the instance name and then send it to sns service?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment