A configuration package to monitor Amazon Machine Images (AMIs) creation and modifications as well as ensure the compliance and security of AMIs available in the account. The package includes:
AWSTemplateFormatVersion: '2010-09-09'
Description: ''
Resources:
S3SharedBucket:
Type: 'AWS::S3::Bucket'
Properties:
LoggingConfiguration: {}
BucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
VersioningConfiguration:
Status: Suspended
AccessControl: LogDeliveryWrite
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
BucketPolicy:
Type: 'AWS::S3::BucketPolicy'
Properties:
Bucket:
Ref: S3SharedBucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Principal:
Service:
- cloudtrail.amazonaws.com
- config.amazonaws.com
Action:
- 's3:GetBucketAcl'
Resource:
- 'Fn::GetAtt':
- S3SharedBucket
- Arn
Effect: Allow
Condition: {}
- Principal:
Service:
- cloudtrail.amazonaws.com
- config.amazonaws.com
Action:
- 's3:PutObject'
Resource:
- 'Fn::Join':
- ''
- - ''
- 'Fn::GetAtt':
- S3SharedBucket
- Arn
- /*
Effect: Allow
Condition:
StringEquals:
's3:x-amz-acl': bucket-owner-full-control
DependsOn: S3SharedBucket
CloudTrail:
Type: 'AWS::CloudTrail::Trail'
Properties:
TrailName: ManagementEventsTrail
IsLogging: true
EnableLogFileValidation: true
EventSelectors:
- IncludeManagementEvents: true
ReadWriteType: All
IsMultiRegionTrail: true
IncludeGlobalServiceEvents: true
S3BucketName:
Ref: S3SharedBucket
CloudWatchLogsLogGroupArn:
'Fn::GetAtt':
- CWLogGroupForCloudTrail
- Arn
CloudWatchLogsRoleArn:
'Fn::GetAtt':
- IamRoleForCwLogsCloudTrail
- Arn
DependsOn:
- BucketPolicy
IamRoleForCwLogsCloudTrail:
Type: 'AWS::IAM::Role'
Properties:
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: cloudtrail.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: allow-access-to-cw-logs
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 'logs:CreateLogStream'
- 'logs:PutLogEvents'
Resource: '*'
CWLogGroupForCloudTrail:
Type: 'AWS::Logs::LogGroup'
Properties:
LogGroupName: CloudTrailLogs
RetentionInDays: 90
ConfigurationRecorder:
Type: 'AWS::Config::ConfigurationRecorder'
Properties:
RoleARN:
'Fn::GetAtt':
- IamRoleForAwsConfig
- Arn
RecordingGroup:
AllSupported: true
IncludeGlobalResourceTypes: true
DeliveryChannel:
Type: 'AWS::Config::DeliveryChannel'
Properties:
S3BucketName:
Ref: S3SharedBucket
IamRoleForAwsConfig:
Type: 'AWS::IAM::Role'
Properties:
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/service-role/AWS_ConfigRole'
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: ''
Effect: Allow
Principal:
Service: config.amazonaws.com
Action: 'sts:AssumeRole'
Policies:
- PolicyName: allow-access-to-config-s3-bucket
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- 's3:PutObject'
Resource:
- 'Fn::Join':
- ''
- - 'Fn::GetAtt':
- S3SharedBucket
- Arn
- /*
Condition:
StringLike:
's3:x-amz-acl': bucket-owner-full-control
- Effect: Allow
Action:
- 's3:GetBucketAcl'
Resource:
'Fn::GetAtt':
- S3SharedBucket
- Arn
RoleName: iamRoleForAWSConfig
SnsTopic1:
Type: 'AWS::SNS::Topic'
Properties:
Subscription:
- Endpoint: email@example.com
Protocol: email
TopicName: sns-topic
ConfigRule1:
Type: 'AWS::Config::ConfigRule'
Properties:
ConfigRuleName: ami_outdated_check
Scope:
ComplianceResourceTypes:
- 'AWS::EC2::Instance'
Description: A config rule that checks whether all private AMIs are not older than X days.
InputParameters:
NumberOfDays: '90'
WhitelistedAmis: ' '
WhitelistedInstances: ' '
Source:
Owner: CUSTOM_LAMBDA
SourceIdentifier:
'Fn::GetAtt':
- LambdaFunctionForConfigRule1
- Arn
SourceDetails:
- EventSource: aws.config
MessageType: ScheduledNotification
MaximumExecutionFrequency: TwentyFour_Hours
DependsOn:
- ConfigurationRecorder
LambdaInvokePermissionsConfigRule1:
Type: 'AWS::Lambda::Permission'
Properties:
FunctionName:
'Fn::GetAtt':
- LambdaFunctionForConfigRule1
- Arn
Action: 'lambda:InvokeFunction'
Principal: config.amazonaws.com
LambdaFunctionForConfigRule1:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: LambdaForami_outdated_check
Handler: index.lambda_handler
Role:
'Fn::GetAtt':
- LambdaIamRoleConfigRule1
- Arn
Runtime: python3.9
Code:
S3Bucket:
'Fn::Sub':
- 'asecure-cloud-cf-aux-${Region}'
- Region:
Ref: 'AWS::Region'
S3Key: AMI_OUTDATED_CHECK.zip
Timeout: 300
DependsOn: LambdaIamRoleConfigRule1
LambdaIamRoleConfigRule1:
Type: 'AWS::IAM::Role'
Properties:
RoleName: IAMRoleForami_outdated_checkOut
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess'
- 'arn:aws:iam::aws:policy/service-role/AWSConfigRulesExecutionRole'
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
ConfigRule2:
Type: 'AWS::Config::ConfigRule'
Properties:
ConfigRuleName: ami_not_public
Scope:
ComplianceResourceTypes:
- 'AWS::::Account'
Description: A config rule that checks whether the Amazon Machine Images are not publicly accessible. The rule is NON_COMPLIANT if one or more Amazon Machine Images are publicly accessible.
Source:
Owner: CUSTOM_LAMBDA
SourceIdentifier:
'Fn::GetAtt':
- LambdaFunctionForConfigRule2
- Arn
SourceDetails:
- EventSource: aws.config
MessageType: ScheduledNotification
MaximumExecutionFrequency: TwentyFour_Hours
DependsOn:
- ConfigurationRecorder
LambdaInvokePermissionsConfigRule2:
Type: 'AWS::Lambda::Permission'
Properties:
FunctionName:
'Fn::GetAtt':
- LambdaFunctionForConfigRule2
- Arn
Action: 'lambda:InvokeFunction'
Principal: config.amazonaws.com
LambdaFunctionForConfigRule2:
Type: 'AWS::Lambda::Function'
Properties:
FunctionName: LambdaForami_not_public
Handler: index.lambda_handler
Role:
'Fn::GetAtt':
- LambdaIamRoleConfigRule2
- Arn
Runtime: python3.9
Code:
S3Bucket:
'Fn::Sub':
- 'asecure-cloud-cf-aux-${Region}'
- Region:
Ref: 'AWS::Region'
S3Key: AMI_NOT_PUBLIC_CHECK.zip
Timeout: 300
DependsOn: LambdaIamRoleConfigRule2
LambdaIamRoleConfigRule2:
Type: 'AWS::IAM::Role'
Properties:
RoleName: IAMRoleForami_not_publicMJg
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action:
- 'sts:AssumeRole'
ManagedPolicyArns:
- 'arn:aws:iam::aws:policy/AmazonEC2ReadOnlyAccess'
- 'arn:aws:iam::aws:policy/service-role/AWSConfigRulesExecutionRole'
- 'arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole'
CwEvent1:
Type: 'AWS::Events::Rule'
Properties:
Name: detect-config-rule-compliance-changes
Description: A CloudWatch Event Rule that detects changes to AWS Config Rule compliance status and publishes change events to an SNS topic for notification.
State: ENABLED
Targets:
- Arn:
Ref: SnsTopic1
Id: target-id1
EventPattern:
detail-type:
- Config Rules Compliance Change
source:
- aws.config
SnsTopicPolicyCwEvent1:
Type: 'AWS::SNS::TopicPolicy'
Properties:
PolicyDocument:
Statement:
- Sid: __default_statement_ID
Effect: Allow
Principal:
AWS: '*'
Action:
- 'SNS:GetTopicAttributes'
- 'SNS:SetTopicAttributes'
- 'SNS:AddPermission'
- 'SNS:RemovePermission'
- 'SNS:DeleteTopic'
- 'SNS:Subscribe'
- 'SNS:ListSubscriptionsByTopic'
- 'SNS:Publish'
- 'SNS:Receive'
Resource:
Ref: SnsTopic1
Condition:
StringEquals:
'AWS:SourceOwner':
Ref: 'AWS::AccountId'
- Sid: TrustCWEToPublishEventsToMyTopic
Effect: Allow
Principal:
Service: events.amazonaws.com
Action: 'sns:Publish'
Resource:
Ref: SnsTopic1
Topics:
- Ref: SnsTopic1
CwAlarm1:
Type: 'AWS::CloudWatch::Alarm'
Properties:
AlarmName: ami_create
AlarmDescription: A CloudWatch Alarm that triggers when new AMIs (Amazon Machine Images) are created or registered in the account.
MetricName: AmiCreateEventCount
Namespace: CloudTrailMetrics
Statistic: Sum
Period: '300'
EvaluationPeriods: '1'
Threshold: '1'
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- Ref: SnsTopic1
TreatMissingData: notBreaching
MetricFilter1:
Type: 'AWS::Logs::MetricFilter'
Properties:
LogGroupName:
Ref: CWLogGroupForCloudTrail
FilterPattern: '{ ($.eventName = RegisterImage) || ($.eventName = CreateImage) }'
MetricTransformations:
- MetricValue: '1'
MetricNamespace: CloudTrailMetrics
MetricName: AmiCreateEventCount
CwAlarm2:
Type: 'AWS::CloudWatch::Alarm'
Properties:
AlarmName: ami_modification
AlarmDescription: 'A CloudWatch Alarm that triggers when existing AMIs (Amazon Machine Images) are modified, deleted, copied or shared with other AWS accounts.'
MetricName: AmiModificationEventCount
Namespace: CloudTrailMetrics
Statistic: Sum
Period: '300'
EvaluationPeriods: '1'
Threshold: '1'
ComparisonOperator: GreaterThanOrEqualToThreshold
AlarmActions:
- Ref: SnsTopic1
TreatMissingData: notBreaching
MetricFilter2:
Type: 'AWS::Logs::MetricFilter'
Properties:
LogGroupName:
Ref: CWLogGroupForCloudTrail
FilterPattern: '{ ($.eventName = DeregisterImage) || ($.eventName = CopyImage) || ($.eventName = ModifyImageAttribute) }'
MetricTransformations:
- MetricValue: '1'
MetricNamespace: CloudTrailMetrics
MetricName: AmiModificationEventCount
Parameters: {}
Metadata: {}
Conditions: {}