Skip to content

Instantly share code, notes, and snippets.

@robertsosinski
Last active June 14, 2019 15:48
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save robertsosinski/4c56330614f66b71722d79af24e8f3d0 to your computer and use it in GitHub Desktop.
Save robertsosinski/4c56330614f66b71722d79af24e8f3d0 to your computer and use it in GitHub Desktop.
Example AWS Config Custom Rule Lambda
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
/**
* 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