Skip to content

Instantly share code, notes, and snippets.

@cktricky
Created January 12, 2017 04:13
Show Gist options
  • Save cktricky/8f4e9912f757d1ccdcd00ad8e8630620 to your computer and use it in GitHub Desktop.
Save cktricky/8f4e9912f757d1ccdcd00ad8e8630620 to your computer and use it in GitHub Desktop.
Lambda Function to Alert (Slack) of Unauthorized IAM Attempt
var AWS = require('aws-sdk');
var url = require('url');
var https = require('https');
var hookUrl, kmsEncyptedHookUrl, slackChannel;
kmsEncyptedHookUrl = 'abcd1234'; // Enter the base-64 encoded, encrypted key (CiphertextBlob)
slackChannel = 'example_channel'; // Enter the Slack channel to send a message to
var postMessage = function(message, callback) {
var body = JSON.stringify(message);
var options = url.parse(hookUrl);
options.method = 'POST';
options.headers = {
'Content-Type': 'application/json',
'Content-Length': Buffer.byteLength(body),
};
var postReq = https.request(options, function(res) {
var chunks = [];
res.setEncoding('utf8');
res.on('data', function(chunk) {
return chunks.push(chunk);
});
res.on('end', function() {
var body = chunks.join('');
if (callback) {
callback({
body: body,
statusCode: res.statusCode,
statusMessage: res.statusMessage
});
}
});
return res;
});
postReq.write(body);
postReq.end();
};
var processEvent = function(event, context) {
var slackMessage = {
channel: slackChannel,
text: '```' + event.detail.errorMessage + '\n' + 'Event ID: ' + event.detail.eventID + '\n' + 'AWS Account: <Enter Your AWS Account Nameg\n' + "Source IP: " + event.detail.sourceIPAddress + "\nUsername: " + event.detail.userIdentity.userName + "```",
};
postMessage(slackMessage, function(response) {
if (response.statusCode < 400) {
console.info('Message posted successfully');
context.succeed();
} else if (response.statusCode < 500) {
console.error("Error posting message to Slack API: " + response.statusCode + " - " + response.statusMessage);
context.succeed(); // Don't retry because the error is due to a problem with the request
} else {
// Let Lambda retry
context.fail("Server error when processing message: " + response.statusCode + " - " + response.statusMessage);
}
});
};
exports.handler = function(event, context) {
// Print the incoming Amazon CloudWatch Events event.
console.log('Received event:', JSON.stringify(event, null, 2));
console.log('Event code:', JSON.stringify(event.detail.errorCode, null, 2));
// If the event is not because of unauthorized activity, do nothing.
if ((event.detail.errorCode != 'AccessDenied') && (event.detail.errorCode != 'Client.UnauthorizedOperation' )) {
console.log('No unauthorized activity');
context.done();
} else {
console.log('Unauthorized activity');
// Get the user name from the event.
var userName = event.detail.userIdentity.userName;
if (hookUrl) {
// Container reuse, simply process the event with the key in memory
processEvent(event, context);
} else if (kmsEncyptedHookUrl && kmsEncyptedHookUrl !== '') {
var encryptedBuf = new Buffer(kmsEncyptedHookUrl, 'base64');
var cipherText = { CiphertextBlob: encryptedBuf };
var kms = new AWS.KMS();
kms.decrypt(cipherText, function(err, data) {
if (err) {
console.log("Decrypt error: " + err);
context.fail(err);
} else {
hookUrl = "https://" + data.Plaintext.toString('ascii');
processEvent(event, context);
}
});
} else {
context.fail(event);
context.fail('Hook URL has not been set.');
}
}
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment