{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "AWS CloudFormation Sample Template Config: This template demonstrates the usage of AWS Config resources. **WARNING** You will be billed for the AWS resources used if you create a stack from this template.", "Parameters": { "Ec2VolumeAutoEnableIO": { "Type": "String", "Default": "false", "AllowedValues": ["false", "true"] }, "Ec2VolumeTagKey": { "Type": "String", "Default": "CostCenter" } }, "Resources": { "Ec2Volume": { "Type": "AWS::EC2::Volume", "Properties": { "AutoEnableIO": {"Ref": "Ec2VolumeAutoEnableIO"}, "Size": "5", "AvailabilityZone": {"Fn::Select": [0, {"Fn::GetAZs": ""}]}, "Tags": [{ "Key": {"Ref": "Ec2VolumeTagKey"}, "Value": "Ec2VolumeTagValue" }] } }, "ConfigRecorder": { "Type": "AWS::Config::ConfigurationRecorder", "Properties": { "Name": "default", "RecordingGroup": { "ResourceTypes": ["AWS::EC2::Volume"] }, "RoleARN": {"Fn::GetAtt": ["ConfigRole", "Arn"]} } }, "DeliveryChannel": { "Type": "AWS::Config::DeliveryChannel", "Properties": { "ConfigSnapshotDeliveryProperties": { "DeliveryFrequency": "Six_Hours" }, "S3BucketName": {"Ref": "ConfigBucket"}, "SnsTopicARN": {"Ref": "ConfigTopic"} } }, "ConfigBucket": { "Type": "AWS::S3::Bucket" }, "ConfigTopic": { "Type": "AWS::SNS::Topic" }, "ConfigTopicPolicy": { "Type": "AWS::SNS::TopicPolicy", "Properties": { "PolicyDocument": { "Id": "ConfigTopicPolicy", "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": "config.amazonaws.com"}, "Action": "SNS:Publish", "Resource": "*" }] }, "Topics": [{"Ref": "ConfigTopic"}] } }, "ConfigRuleForVolumeTags": { "Type": "AWS::Config::ConfigRule", "Properties": { "InputParameters": {"tag1Key": "CostCenter"}, "Scope": { "ComplianceResourceTypes": ["AWS::EC2::Volume"] }, "Source": { "Owner": "AWS", "SourceIdentifier": "REQUIRED_TAGS" } }, "DependsOn": "ConfigRecorder" }, "ConfigRuleForVolumeAutoEnableIO": { "Type": "AWS::Config::ConfigRule", "Properties": { "ConfigRuleName": "ConfigRuleForVolumeAutoEnableIO", "Scope": { "ComplianceResourceId": {"Ref": "Ec2Volume"}, "ComplianceResourceTypes": ["AWS::EC2::Volume"] }, "Source": { "Owner": "CUSTOM_LAMBDA", "SourceDetails": [{ "EventSource": "aws.config", "MessageType": "ConfigurationItemChangeNotification" }], "SourceIdentifier": {"Fn::GetAtt": ["VolumeAutoEnableIOComplianceCheck", "Arn"]} } }, "DependsOn": ["ConfigPermissionToCallLambda", "ConfigRecorder"] }, "ConfigPermissionToCallLambda": { "Type": "AWS::Lambda::Permission", "Properties": { "FunctionName": {"Fn::GetAtt": ["VolumeAutoEnableIOComplianceCheck", "Arn"]}, "Action": "lambda:InvokeFunction", "Principal": "config.amazonaws.com" } }, "VolumeAutoEnableIOComplianceCheck": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "ZipFile": {"Fn::Join": ["\n", [ "var aws = require('aws-sdk');", "var config = new aws.ConfigService();", "var ec2 = new aws.EC2();", "exports.handler = function(event, context) {", " compliance = evaluateCompliance(event, function(compliance, event) {", " var configurationItem = JSON.parse(event.invokingEvent).configurationItem;", " var putEvaluationsRequest = {", " Evaluations: [{", " ComplianceResourceType: configurationItem.resourceType,", " ComplianceResourceId: configurationItem.resourceId,", " ComplianceType: compliance,", " OrderingTimestamp: configurationItem.configurationItemCaptureTime", " }],", " ResultToken: event.resultToken", " };", " config.putEvaluations(putEvaluationsRequest, function(err, data) {", " if (err) context.fail(err);", " else context.succeed(data);", " });", " });", "};", "function evaluateCompliance(event, doReturn) {", " var configurationItem = JSON.parse(event.invokingEvent).configurationItem;", " var status = configurationItem.configurationItemStatus;", " if (configurationItem.resourceType !== 'AWS::EC2::Volume' || event.eventLeftScope || (status !== 'OK' && status !== 'ResourceDiscovered'))", " doReturn('NOT_APPLICABLE', event);", " else ec2.describeVolumeAttribute({VolumeId: configurationItem.resourceId, Attribute: 'autoEnableIO'}, function(err, data) {", " if (err) context.fail(err);", " else if (data.AutoEnableIO.Value) doReturn('COMPLIANT', event);", " else doReturn('NON_COMPLIANT', event);", " });", "}" ]]} }, "Handler": "index.handler", "Runtime": "nodejs", "Timeout": "30", "Role": {"Fn::GetAtt": ["LambdaExecutionRole", "Arn"]} } }, "LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["lambda.amazonaws.com" ]}, "Action": ["sts:AssumeRole"] }] }, "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": ["logs:*", "config:PutEvaluations", "ec2:DescribeVolumeAttribute"], "Resource": "*" }] } }] } }, "ConfigRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Principal": {"Service": ["config.amazonaws.com"]}, "Action": ["sts:AssumeRole" ] }] }, "ManagedPolicyArns": ["arn:aws:iam::aws:policy/service-role/AWSConfigRole"], "Policies": [{ "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [{ "Effect": "Allow", "Action": "s3:GetBucketAcl", "Resource": {"Fn::Join": ["", ["arn:aws:s3:::", {"Ref":"ConfigBucket"}]]} }, { "Effect": "Allow", "Action": "s3:PutObject", "Resource": {"Fn::Join": ["", ["arn:aws:s3:::", {"Ref":"ConfigBucket"}, "/AWSLogs/", {"Ref":"AWS::AccountId"}, "/*"]]}, "Condition": {"StringEquals": {"s3:x-amz-acl": "bucket-owner-full-control"}} }, { "Effect": "Allow", "Action": "config:Put*", "Resource": "*" }] } }] } } }, "Outputs": { "ConfigRuleForVolumeTagsArn": { "Value": {"Fn::GetAtt": ["ConfigRuleForVolumeTags", "Arn"]} }, "ConfigRuleForVolumeTagsConfigRuleId": { "Value": {"Fn::GetAtt": ["ConfigRuleForVolumeTags", "ConfigRuleId"]} }, "ConfigRuleForVolumeAutoEnableIOComplianceType": { "Value": {"Fn::GetAtt": ["ConfigRuleForVolumeAutoEnableIO", "Compliance.Type"]} } } }