Skip to content

Instantly share code, notes, and snippets.

@richadams
Created February 9, 2018 22:55
Show Gist options
  • Star 8 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save richadams/3f51b617dc4051563fe358d7b0d40fe2 to your computer and use it in GitHub Desktop.
Save richadams/3f51b617dc4051563fe358d7b0d40fe2 to your computer and use it in GitHub Desktop.
PagerDuty Custom Event Transformer for handling AWS Config compliance events from SNS. Raising incidents if a resource goes non-compliant, and resolving the incident if they go compliant again (or are deleted).
// Parses AWS Config events from SNS and will raise PagerDuty incidents if resources
// go non-compliant, resolving the incident when they return to compliant.
//
// This file is intended to be used with a PagerDuty Custom Event Transformer.
// https://www.pagerduty.com/docs/guides/custom-event-transformer/
//
// Create a new Custom Event Transformer integration in PagerDuty, and subscribe it's
// Integration URL on the SNS Topic that you send AWS Config events to.
//
// You can see all the different notifications Config sends here:
// http://docs.aws.amazon.com/config/latest/developerguide/notifications-for-AWS-Config.html
//
// Note that there is currently no way to filter on the AWS side, so we have to
// do it here instead. All of then have the same "Type" field, so we need to look
// at the actual contents to determine if it's an event we care about.
//
// Compliance events will have a "newEvaluationResult" field, and resource information.
// If it lacks those, then it's not compliance related.
// You can see an example notification format here:
// http://docs.aws.amazon.com/config/latest/developerguide/example-config-rule-compliance-notification.html
//
// PD.fail(...) is used for any error cases. You will only see these messages if you have
// debug mode enabled in the event transformer, otherwise they are suppressed.
// Parse the rawBody into a JSON structure
var body = JSON.parse(PD.inputRequest.rawBody)
// If it's an SNS subscription confirmation, allow it through.
if (typeof body.SubscribeURL != "undefined")
{
var normalized_event = {
incident_key: "sns-subscription",
event_type: PD.Trigger,
description: "SNS topic subscription confirmation",
details: body.SubscribeURL
};
PD.emitGenericEvents([normalized_event]);
}
// Message is double JSON encoded, so we need to parse it again.
var message = JSON.parse(body.Message);
// Extract resource information, this will be our incident key and identifier.
var resourceType = message.resourceType;
var resourceId = message.resourceId;
var resourceKey = resourceType + "/" + resourceId;
// If resource information is missing, then it's not an event we care about.
if (typeof resourceType == "undefined") { PD.fail("resourceType missing.") }
if (typeof resourceId == "undefined") { PD.fail("resourceId missing.") }
// If we don't have any new evaluation results, then this wasn't a compliance
// event, and was likely another type of message.
if (typeof message.newEvaluationResult == "undefined") { PD.fail("newEvaluationResult missing.") }
// Our action is based on the compliance type of the new result.
switch(message.newEvaluationResult.complianceType)
{
// Has become non-compliant, raise an incident.
// (We don't check oldEvaluationResult, as it could be a brand new resource without one)
case "NON_COMPLIANT":
var normalized_event = {
incident_key: resourceKey,
event_type: PD.Trigger,
description: "Non-compliant AWS resource: " + resourceKey,
details: message
};
PD.emitGenericEvents([normalized_event]);
break;
// Has become compliant, resolve any open incident for it.
case "COMPLIANT":
var normalized_event = {
incident_key: resourceKey,
event_type: PD.Resolve,
description: "Compliant AWS resource: " + resourceKey,
details: message
};
PD.emitGenericEvents([normalized_event]);
break;
// Resource was deleted, if there's an open incident, we should resolve it.
case "NOT_APPLICABLE":
var normalized_event = {
incident_key: resourceKey,
event_type: PD.Resolve,
description: "AWS resource deleted: " + resourceKey,
details: message
};
PD.emitGenericEvents([normalized_event]);
break;
// If there's insufficient data, then we also do nothing.
case "INSUFFICIENT_DATA":
PD.fail("Insufficient data to determine compliance.");
break;
// Catch-all
default:
PD.fail("Unknown compliance state: " + newResult);
}
@AClarkie
Copy link

AClarkie commented Apr 14, 2021

On line 41 needed to be changed to the following to get this to work for me:
var message = JSON.parse(body.Message).detail;

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