Last active
June 14, 2019 15:48
-
-
Save robertsosinski/4c56330614f66b71722d79af24e8f3d0 to your computer and use it in GitHub Desktop.
Example AWS Config Custom Rule Lambda
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
AWSTemplateFormatVersion: 2010-09-09 | |
Description: Configure Config Rules | |
Resources: | |
ConfigS3BucketPublicReadProhibitedRule: | |
Type: AWS::Config::ConfigRule | |
Properties: | |
ConfigRuleName: s3-bucket-public-read-prohibited | |
Description: Checks that your Amazon S3 buckets do not allow public read access. The rule checks the Block Public Access settings, the bucket policy, and the bucket access control list (ACL). | |
MaximumExecutionFrequency: TwentyFour_Hours | |
Source: | |
Owner: AWS | |
SourceIdentifier: S3_BUCKET_PUBLIC_READ_PROHIBITED | |
ConfigS3BucketPublicWriteProhibitedRule: | |
Type: AWS::Config::ConfigRule | |
Properties: | |
ConfigRuleName: s3-bucket-public-write-prohibited | |
Description: Checks that your Amazon S3 buckets do not allow public write access. The rule checks the Block Public Access settings, the bucket policy, and the bucket access control list (ACL). | |
MaximumExecutionFrequency: TwentyFour_Hours | |
Source: | |
Owner: AWS | |
SourceIdentifier: S3_BUCKET_PUBLIC_WRITE_PROHIBITED |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* Checks if account has more then a specified number of AWS resources. | |
* @param {string} ResourceType - The AWS resource, e.g. "AWS::S3::Bucket" | |
* @param {number} MaxCount - The max number of the specified ResourceType | |
* @param {string} [ExecutionRole] - The ARN of the ExecutionRole, required if running from another account | |
* | |
* Note: Valid resource types can be found here: https://docs.aws.amazon.com/config/latest/APIReference/API_ListDiscoveredResources.html#config-ListDiscoveredResources-request-resourceType | |
*/ | |
let COMPLIANCE_STATES = { | |
COMPLIANT: "COMPLIANT", | |
NON_COMPLIANT: "NON_COMPLIANT", | |
NOT_APPLICABLE: "NOT_APPLICABLE", | |
}; | |
// Checks whether the invoking event is ScheduledNotification | |
function isScheduledNotification(invokingEvent) { | |
return (invokingEvent.messageType === "ScheduledNotification"); | |
} | |
// Evaluates the configuration items in the snapshot and returns the compliance value to the handler. | |
function evaluateCompliance(maxCount, actualCount) { | |
return (actualCount > maxCount) ? COMPLIANCE_STATES.NON_COMPLIANT : COMPLIANCE_STATES.COMPLIANT; | |
} | |
function countResourceTypes(config, applicableResourceType, nextToken, count, callback) { | |
config.listDiscoveredResources({ resourceType: applicableResourceType, nextToken }, (err, data) => { | |
console.log("Discovered Resources:", err, data); | |
if (err) { | |
return callback(err); | |
} | |
let updated = count + data.resourceIdentifiers.length; | |
if (data.nextToken) { | |
countResourceTypes(config, applicableResourceType, data.nextToken, updated, callback); | |
} else { | |
callback(null, updated); | |
} | |
}); | |
} | |
exports.handler = (event, _context, callback) => { | |
let AWS = require("aws-sdk"); // Loads the AWS SDK for JavaScript. | |
console.log("Lambda Event:", event); | |
// Parses the invokingEvent and ruleParameters values, which contain JSON objects passed as strings. | |
let invokingEvent = JSON.parse(event.invokingEvent); | |
let ruleParameters = JSON.parse(event.ruleParameters); | |
let resourceCount = 0; | |
// Use cross-account ExecutionRole if one is provided | |
if (ruleParameters.ExecutionRole) { | |
let creds = new AWS.TemporaryCredentials({RoleArn: ruleParameters.ExecutionRole}); | |
console.log("Temporary Credentials:", creds); | |
AWS.config.credentials = creds; | |
} | |
let config = new AWS.ConfigService({}); | |
if (isScheduledNotification(invokingEvent)) { | |
countResourceTypes(config, ruleParameters.ResourceType, "", resourceCount, (err, count) => { | |
if (err) { | |
return callback(err); | |
} | |
// Initializes the request that contains the evaluation results. | |
let putEvaluationsRequest = { | |
Evaluations: [{ | |
// Applies the evaluation result to the AWS account published in the event. | |
Annotation: `Max ${ruleParameters.ResourceType} count is "${ruleParameters.MaxCount}" and found "${count}".`, | |
ComplianceResourceType: "AWS::::Account", | |
ComplianceResourceId: event.accountId, | |
ComplianceType: evaluateCompliance(ruleParameters.MaxCount, count), | |
OrderingTimestamp: new Date(), | |
}], | |
ResultToken: event.resultToken, | |
}; | |
console.log("Evaluations:", putEvaluationsRequest); | |
// Sends the evaluation results to AWS Config. | |
config.putEvaluations(putEvaluationsRequest, (putErr, data) => { | |
if (putErr) { | |
return callback(putErr); | |
} | |
if (data.FailedEvaluations.length > 0) { | |
// Ends the function execution if any evaluation results are not successfully reported | |
return callback(JSON.stringify(data)); | |
} | |
callback(null, data); | |
}); | |
}); | |
} else { | |
callback("Invoked for a notification other than Scheduled Notification... Ignoring."); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment