{ "AWSTemplateFormatVersion": "2010-09-09", "Description": "(SO0022) - CRR Monitor: Cross-Region Replication monitor for S3. This template should be deployed in a single region per account, and requires Lambda, SNS, SQS and DynamoDB.", "Parameters": { "ArchiveToS3": { "Description": "Do you want to archive the DynamoDB data to S3?. Deploy in KinesisFirehose supported region", "Type": "String", "Default": "No", "AllowedValues": [ "Yes", "No" ] }, "S3ArchiveBucket": { "Description": "The name of the S3 bucket that contains the archive data from Dynamo DB", "Type": "String" }, "remoteAccounts": { "Description": "A list of accounts that will be monitored. Each must have had crr-agent.template deployed.", "Type": "CommaDelimitedList" } }, "Mappings": { "Function": { "CustomResourceTrailAlarm": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/CRRMonitorTrailAlarm.zip", "Description": "crr: CloudFormation custom resource function invoked during CloudFormation create, update, and delete stack operations." }, "CustomResourceMonitor": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/CRRMonitor.zip", "Description": "crr: CloudFormation custom resource function invoked during CloudFormation create, update, and delete stack operations." }, "CustomResourceHousekeeping": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/CRRMonitorHousekeeping.zip", "Description": "crr: CloudFormation custom resource function invoked during CloudFormation create, update, and delete stack operations." }, "CustomResourceHourlyMaint": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/CRRHourlyMaint.zip", "Description": "crr: CloudFormation custom resource function invoked during CloudFormation create, update, and delete stack operations." }, "CustomResourceDeployAgent": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/CRRdeployagent.zip", "Description": "crr: CloudFormation custom resource function invoked during CloudFormation create, update, and delete stack operations." }, "SolutionHelperFunction": { "S3Bucket": "CODE_BUCKET", "S3Key": "SOLUTION_NAME/SOLUTION_VERSION/solution-helper.zip", "Description": "crr: CloudFormation custom resource function for generating UUID." } }, "Send" : { "AnonymousUsage" : { "Data" : "Yes" } } }, "Conditions": { "SingleAccnt": { "Fn::Not": [ { "Fn::Equals": [ { "Fn::Join": [ "", { "Ref": "remoteAccounts" } ] }, "" ] } ] }, "StreamToKinesis": { "Fn::Equals": [ { "Ref": "ArchiveToS3" }, "Yes" ] } }, "Resources": { "CRRMonitorRole": { "Type": "AWS::IAM::Role", "Properties": { "RoleName": "CRRMonitorRole", "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "CRRMonitorPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "DynamoDBPerms", "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:dynamodb:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":table/CRRMonitor*" ] ] } ] }, { "Sid": "CloudTrailLogPerms", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":*" ] ] } }, { "Sid": "LambdaPerms", "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:lambda:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":function:CRRMonitor" ] ] } }, { "Sid": "SQSQueuePerms", "Effect": "Allow", "Action": [ "sqs:ReceiveMessage", "sqs:DeleteMessage", "sqs:ChangeMessageVisibility", "sqs:DeleteMessageBatch", "sqs:GetQueueUrl", "sqs:GetQueueAttributes" ], "Resource": [ "arn:aws:sqs:*:*:CRRMonitor*" ] }, { "Sid": "S3ListPerms", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetReplicationConfiguration", "s3:GetObject" ], "Resource": [ "arn:aws:s3:::*", "arn:aws:s3:::*/*" ] }, { "Sid": "S3Perms", "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:HeadBucket" ], "Resource": "*" }, { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "arn:aws:iam:::role/CRRMonitorRole" }, { "Effect": "Allow", "Action": "kms:Decrypt", "Resource": { "Fn::GetAtt": ["CRRMonitorKey", "Arn"] } } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "The cloudwatch:ListMetrics,s3:ListAllMyBuckets action requires the wildcard ('*') resource identifier to function properly.Supporting documentation available at (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/iam-identity-based-access-control-cw.html) and (https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html)" }, { "id": "W28", "reason": "CRRMonitor Role name has been specified to assume role" } ] } } }, "CRRMonitorDeployRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "CRRMonitorDeployPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "CloudTrailLogPerms", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":log-group:*" ] ] } ] }, { "Sid": "DeploySNS", "Effect": "Allow", "Action": [ "sns:CreateTopic", "sns:DeleteTopic", "sns:Subscribe", "sns:Unsubscribe", "sns:SetTopicAttributes" ], "Resource": [ "arn:aws:sns:*:*:CRRMonitor*" ] }, { "Sid": "S3ListPerms", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetReplicationConfiguration" ], "Resource": [ "arn:aws:s3:::*", "arn:aws:s3:::*/*" ] }, { "Sid": "S3Perms", "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:HeadBucket" ], "Resource": "*" }, { "Sid": "DeployAgentEC2Perms", "Effect": "Allow", "Action": [ "ec2:DescribeRegions" ], "Resource": "*" }, { "Sid": "PutEventsPerms", "Effect": "Allow", "Action": [ "events:PutPermission" ], "Resource": "*" }, { "Sid": "EventsPerms", "Effect": "Allow", "Action": [ "events:PutRule", "events:PutTargets", "events:DeleteRule", "events:EnableRule", "events:RemoveTargets" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:events:*:", { "Ref": "AWS::AccountId" }, ":rule/CRR*" ] ] } ] } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "The s3:ListAllMyBuckets,ec2:DescribeRegions,events:PutPermission action requires the wildcard ('*') resource identifier to function properly.Supporting documentation available at (https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html),(https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ExamplePolicies_EC2.html) and (https://docs.aws.amazon.com/AmazonCloudWatch/latest/events/permissions-reference-cwe.html)" } ] } } }, "CRRFirehoseRole": { "Type": "AWS::IAM::Role", "Condition": "StreamToKinesis", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "firehose.amazonaws.com" , "lambda.amazonaws.com" ] }, "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "sts:ExternalId": { "Ref" : "AWS::AccountId" } } } } ] }, "Policies": [ { "PolicyName": "CRRFirehosePolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "S3Perms", "Effect": "Allow", "Action": [ "s3:AbortMultipartUpload", "s3:GetBucketLocation", "s3:GetObject", "s3:ListBucket", "s3:ListBucketMultipartUploads", "s3:PutObject" ], "Resource": [ { "Fn::Join" : [ "", [ "arn:aws:s3:::", { "Ref" : "S3ArchiveBucket" } ] ] }, { "Fn::Join" : [ "", [ "arn:aws:s3:::", { "Ref" : "S3ArchiveBucket" }, "/*"] ] } ] }, { "Sid": "LambdaPerms", "Effect": "Allow", "Action": [ "lambda:InvokeFunction", "lambda:GetFunctionConfiguration" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:lambda:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":function:CRR*" ] ] } } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "Requires the S3 Archive Bucket folder access" } ] } } }, "CRRMonitorHouseKeepingRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "CRRMonitorHouseKeepingPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "DynamoDBPerms", "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:dynamodb:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":table/CRRMonitor*" ] ] } ] }, { "Sid": "CloudTrailLogPerms", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":log-group:*" ] ] } }, { "Sid": "CloudWatchMetrics", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricAlarm", "cloudwatch:DeleteAlarms", "cloudwatch:EnableAlarmActions" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:cloudwatch:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":*" ] ] } }, { "Sid": "CloudWatchMetricsPerms", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricData", "cloudwatch:ListMetrics" ], "Resource": "*" }, { "Sid": "FirehosePerm", "Effect": "Allow", "Action": [ "firehose:PutRecord" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:firehose:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":deliverystream/CRRMonitorDeliveryStream" ] ] } } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "The cloudwatch:ListMetrics action requires the wildcard ('*') resource identifier to function properly.Supporting documentation available at (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/iam-identity-based-access-control-cw.html)" } ] } } }, "CRRHourlyMaintRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "CRRHourlyMaintPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "DynamoDBPerms", "Effect": "Allow", "Action": [ "dynamodb:DescribeTable", "dynamodb:DeleteItem", "dynamodb:GetItem", "dynamodb:Scan", "dynamodb:UpdateItem" ], "Resource": [ { "Fn::Join": [ "", [ "arn:aws:dynamodb:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":table/CRRMonitor*" ] ] } ] }, { "Sid": "S3ListPerms", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetReplicationConfiguration" ], "Resource": [ "arn:aws:s3:::*", "arn:aws:s3:::*/*" ] }, { "Sid": "S3Perms", "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:HeadBucket" ], "Resource": "*" }, { "Sid": "LogPermissions", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":log-group:/aws/lambda/CRRHourlyMaint:*" ] ] } } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "The cloudwatch:ListMetrics,s3:ListAllMyBuckets action requires the wildcard ('*') resource identifier to function properly.Supporting documentation available at (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/iam-identity-based-access-control-cw.html) and (https://docs.aws.amazon.com/AmazonS3/latest/dev/using-with-s3-actions.html)" } ] } } }, "CRRMonitorTrailRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "CRRMonitorTrailPolicy", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "CloudTrailLogPerms", "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents", "logs:DescribeLogStreams" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":*" ] ] } }, { "Sid": "LambdaPerms", "Effect": "Allow", "Action": [ "lambda:InvokeFunction" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:lambda:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":function:CRRMonitor" ] ] } }, { "Sid": "CloudWatchMetrics", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricAlarm", "cloudwatch:DeleteAlarms", "cloudwatch:EnableAlarmActions" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:cloudwatch:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":*" ] ] } }, { "Sid": "CloudWatchMetricsPerms", "Effect": "Allow", "Action": [ "cloudwatch:PutMetricData", "cloudwatch:ListMetrics" ], "Resource": "*" }, { "Sid": "CloudTrailPerms", "Effect": "Allow", "Action": [ "cloudtrail:PutEventSelectors", "cloudtrail:StopLogging", "cloudtrail:StartLogging", "cloudtrail:DeleteTrail", "cloudtrail:UpdateTrail", "cloudtrail:CreateTrail" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:cloudtrail:", "*", ":", { "Ref": "AWS::AccountId" }, ":*" ] ] } }, { "Sid": "S3ListPerms", "Effect": "Allow", "Action": [ "s3:ListBucket", "s3:GetReplicationConfiguration" ], "Resource": [ "arn:aws:s3:::*", "arn:aws:s3:::*/*" ] }, { "Sid": "S3Perms", "Effect": "Allow", "Action": [ "s3:ListAllMyBuckets", "s3:HeadBucket" ], "Resource": "*" } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "The cloudwatch:ListMetrics action requires the wildcard ('*') resource identifier to function properly.Supporting documentation available at (https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/iam-identity-based-access-control-cw.html)" } ] } } }, "CRRMonitorLambda": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "CustomResourceMonitor", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "CustomResourceMonitor", "S3Key" ] } }, "Handler": "CRRMonitor.queue_handler", "FunctionName": "CRRMonitor", "Environment" : { "Variables": { "maxtask" : "1800" , "maxspawn" : "20", "AnonymousUsage": { "Fn::FindInMap": [ "Send", "AnonymousUsage", "Data" ] }, "UUID": { "Fn::GetAtt": [ "UUIDGenerator", "UUID" ] }, "SolutionVersion": "SOLUTION_VERSION" } }, "Role": { "Fn::GetAtt": [ "CRRMonitorRole", "Arn" ] }, "Runtime": "python3.8", "Timeout": 300 } }, "MonitorTimer": { "Type": "AWS::Events::Rule", "Properties": { "Description": "Runs CRRMonitor every 1 minute.", "ScheduleExpression": "rate(1 minute)", "State": "ENABLED", "Targets": [ { "Id": "CRRMonitor", "Arn": { "Fn::GetAtt": [ "CRRMonitorLambda", "Arn" ] } } ] } }, "MonitorTimerPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:invokeFunction", "FunctionName": { "Ref": "CRRMonitorLambda" }, "Principal": "events.amazonaws.com", "SourceArn": { "Fn::GetAtt": [ "MonitorTimer", "Arn" ] } }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W24", "reason": "Lambda permission requires InvokeFunction" } ] } } }, "HousekeepingLambda": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "CustomResourceHousekeeping", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "CustomResourceHousekeeping", "S3Key" ] } }, "Handler": "CRRMonitorHousekeeping.lambda_handler", "Environment" : { "Variables": { "stream_to_kinesis": { "Ref" : "ArchiveToS3" }, "kinesisfirestream": { "Fn::If" : [ "StreamToKinesis", {"Ref" : "CRRMonitorKinesisDeliveryStream"}, {"Ref" : "AWS::NoValue"} ] }, "stack_name" : { "Ref" : "AWS::StackName"}, "purge_thresh": "24" } }, "FunctionName": "CRRMonitorHousekeeping", "Role": { "Fn::GetAtt": [ "CRRMonitorHouseKeepingRole", "Arn" ] }, "Runtime": "python3.8", "Timeout": 300 }, "DependsOn": [ "CRRMonitorRole" ] }, "HousekeepingTimer": { "Type": "AWS::Events::Rule", "Properties": { "Description": "Runs the housekeeper every 5 minutes.", "ScheduleExpression": "rate(5 minutes)", "State": "ENABLED", "Targets": [ { "Id": "Housekeeper", "Arn": { "Fn::GetAtt": [ "HousekeepingLambda", "Arn" ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W24", "reason": "Lambda permission requires InvokeFunction" } ] } } }, "HousekeepingPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:invokeFunction", "FunctionName": { "Ref": "HousekeepingLambda" }, "Principal": "events.amazonaws.com", "SourceArn": { "Fn::GetAtt": [ "HousekeepingTimer", "Arn" ] } }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W24", "reason": "Lambda permission requires InvokeFunction" } ] } } }, "MaintLambda": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "CustomResourceHourlyMaint", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "CustomResourceHourlyMaint", "S3Key" ] } }, "Handler": "CRRHourlyMaint.lambda_handler", "FunctionName": "CRRHourlyMaint", "Role": { "Fn::GetAtt": [ "CRRHourlyMaintRole", "Arn" ] }, "Runtime": "python3.8", "Timeout": 300 }, "DependsOn": [ "CRRMonitorRole" ], "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W24", "reason": "Lambda permission requires InvokeFunction" } ] } } }, "MaintTimer": { "Type": "AWS::Events::Rule", "Properties": { "Description": "Runs the maintenance tasks every hour.", "ScheduleExpression": "rate(1 hour)", "State": "ENABLED", "Targets": [ { "Id": "CRRMaint", "Arn": { "Fn::GetAtt": [ "MaintLambda", "Arn" ] } } ] } }, "MaintPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:invokeFunction", "FunctionName": { "Ref": "MaintLambda" }, "Principal": "events.amazonaws.com", "SourceArn": { "Fn::GetAtt": [ "MaintTimer", "Arn" ] } }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W24", "reason": "Lambda permission requires InvokeFunction" } ] } } }, "CRRMonitorQueue": { "Type": "AWS::SQS::Queue", "Properties": { "QueueName": { "Fn::Join": [ "", [ "CRRMonitor", "Queue" ] ] }, "KmsMasterKeyId": { "Ref": "CRRMonitorKey" }, "RedrivePolicy": { "deadLetterTargetArn": {"Fn::GetAtt" : [ "CRRMonitorDeadLetterQueue" , "Arn" ]}, "maxReceiveCount": 10 } } }, "CRRMonitorQueuePolicy": { "Type": "AWS::SQS::QueuePolicy", "Properties": { "PolicyDocument": { "Id": "CRRMonitorQueuePolicy", "Statement": [ { "Sid": "SQSQueuePermission", "Effect": "Allow", "Principal": "*", "Action": [ "SQS:SendMessage", "SQS:ReceiveMessage", "SQS:DeleteMessage" ], "Resource": [ { "Fn::GetAtt": [ "CRRMonitorQueue", "Arn" ] } ], "Condition": { "ArnEquals": { "aws:SourceArn": { "Fn::Join" : [ ":", [ "arn:aws:sns", "*", { "Ref": "AWS::AccountId" } , "*" ] ] } } } } ] }, "Queues": [ { "Ref": "CRRMonitorQueue" } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "F21", "reason": "This is required for remote accounts to send messages to queue." } ] } } }, "CRRMonitorDeadLetterQueue": { "Type": "AWS::SQS::Queue", "Properties": { "KmsMasterKeyId": { "Ref": "CRRMonitorKey" } } }, "CRRMonitorKinesisDeliveryStream": { "Type" : "AWS::KinesisFirehose::DeliveryStream", "Condition": "StreamToKinesis", "Properties" : { "DeliveryStreamName" : "CRRMonitorDeliveryStream", "S3DestinationConfiguration" : { "BucketARN" : { "Fn::Join" : [ ":", [ "arn:aws:s3::", { "Ref" : "S3ArchiveBucket" } ] ] }, "BufferingHints" : { "IntervalInSeconds" : 60, "SizeInMBs" : 5 }, "CompressionFormat" : "GZIP", "Prefix" : "CRRMonitorArchive", "RoleARN" : { "Fn::GetAtt": [ "CRRFirehoseRole", "Arn" ] }, "CloudWatchLoggingOptions" : { "Enabled" : true, "LogGroupName" : "deliverystream", "LogStreamName" : "s3Backup" } } } }, "CRRDeployAgentLambda": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "CustomResourceDeployAgent", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "CustomResourceDeployAgent", "S3Key" ] } }, "Handler": "CRRdeployagent.handler", "FunctionName": "CRRDeployAgent", "Role": { "Fn::GetAtt": [ "CRRMonitorDeployRole", "Arn" ] }, "Runtime": "python3.8", "Timeout": 300 }, "DependsOn": [ "CRRMonitorRole" ] }, "CustomDeploy": { "Type": "Custom::DeployAgent", "Properties": { "ServiceToken": { "Fn::GetAtt": [ "CRRDeployAgentLambda", "Arn" ] }, "Topic": "CRRMonitor", "CRRQueueArn": { "Fn::GetAtt": [ "CRRMonitorQueue", "Arn" ] }, "AgentAccounts": {"Fn::If": ["SingleAccnt", {"Ref": "remoteAccounts"}, [{"Ref": "AWS::AccountId"}]]} }, "DependsOn": [ "CRRMonitorLambda" ] }, "CRRMonitorDDB": { "Type": "AWS::DynamoDB::Table", "Properties": { "AttributeDefinitions": [ { "AttributeName": "ETag", "AttributeType": "S" } ], "BillingMode": "PAY_PER_REQUEST", "KeySchema": [ { "AttributeName": "ETag", "KeyType": "HASH" } ], "TableName": "CRRMonitor", "TimeToLiveSpecification": { "AttributeName": "TimeToLive", "Enabled": true } }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W28", "reason": "Requires the resource name table name CRRMonitor" } ] } } }, "CRRMonitorStatisticsDDB": { "Type": "AWS::DynamoDB::Table", "Properties": { "AttributeDefinitions": [ { "AttributeName": "OriginReplicaBucket", "AttributeType": "S" } ], "BillingMode": "PAY_PER_REQUEST", "KeySchema": [ { "AttributeName": "OriginReplicaBucket", "KeyType": "HASH" } ], "TableName": "CRRMonitorStatistics" }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W28", "reason": "Requires the resource name table name CRRMonitorStatistics" } ] } } }, "CloudMetricsNotificationTopic" : { "Type" : "AWS::SNS::Topic", "Properties" : { "DisplayName" : "CRRMonitorMetricsTopic", "TopicName" : "CRRMonitorMetricsTopic", "KmsMasterKeyId": { "Fn::Sub": "arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns" } } }, "logBucket": { "Type": "AWS::S3::Bucket", "DeletionPolicy": "Retain", "Properties" : { "BucketEncryption" : { "ServerSideEncryptionConfiguration" : [ { "ServerSideEncryptionByDefault" : { "SSEAlgorithm" : "AES256" } } ] }, "PublicAccessBlockConfiguration" : { "BlockPublicAcls" : true, "BlockPublicPolicy" : true, "IgnorePublicAcls" : true, "RestrictPublicBuckets" : true } }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W35", "reason": "S3 Bucket should have access logging suppressed" } ] } } }, "logBucketPolicy" : { "Type" : "AWS::S3::BucketPolicy", "Properties" : { "Bucket" : {"Ref" : "logBucket"}, "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Sid": "AWSCloudTrailAclCheck20150319", "Effect": "Allow", "Principal": { "Service": "cloudtrail.amazonaws.com" }, "Action": "s3:GetBucketAcl", "Resource": { "Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref" : "logBucket" } ] ] } }, { "Sid": "AWSCloudTrailWrite20150319", "Effect": "Allow", "Principal": { "Service": "cloudtrail.amazonaws.com" }, "Action": "s3:PutObject", "Resource": { "Fn::Join": [ "", [ "arn:aws:s3:::", {"Ref" : "logBucket" }, "/AWSLogs/", { "Ref" : "AWS::AccountId"} , "/*"] ] }, "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } } } ] } } }, "CRRMonitorTrailAlarm": { "Type": "AWS::Lambda::Function", "Properties": { "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "CustomResourceTrailAlarm", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "CustomResourceTrailAlarm", "S3Key" ] } }, "Handler": "CRRMonitorTrailAlarm.handler", "FunctionName": "CRRMonitorTrailAlarm", "Role": { "Fn::GetAtt": [ "CRRMonitorTrailRole", "Arn" ] }, "Runtime": "python3.8", "Timeout": 300 }, "DependsOn": [ "CRRMonitorRole", "CloudMetricsNotificationTopic" ] }, "CustomTrailAlarm": { "Type": "Custom::TrailAlarm", "Properties": { "ServiceToken": { "Fn::GetAtt": [ "CRRMonitorTrailAlarm", "Arn" ] }, "trail_name" : "CRRMonitor_trail", "trail_log_bucket" : { "Ref" : "logBucket"}, "sns_topic_arn" : { "Ref" : "CloudMetricsNotificationTopic"} }, "DependsOn" : [ "logBucketPolicy" ] }, "SolutionHelperRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": "sts:AssumeRole" } ] }, "Path": "/", "Policies": [ { "PolicyName": "Custom_Solution_Helper_Permissions", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents" ], "Resource": { "Fn::Join": [ "", [ "arn:aws:logs:", { "Ref": "AWS::Region" }, ":", { "Ref": "AWS::AccountId" }, ":log-group:/aws/lambda/*" ] ] } } ] } } ] }, "Metadata": { "cfn_nag": { "rules_to_suppress": [ { "id": "W11", "reason": "Requires log-group level access :log-group:/aws/lambda/*" } ] } } }, "SolutionHelper": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "solution-helper.lambda_handler", "Role": { "Fn::GetAtt": [ "SolutionHelperRole", "Arn" ] }, "Description": "This function creates a CloudFormation custom lambda resource that creates custom lambda functions by finding and replacing specific values from existing lambda function code.", "Code": { "S3Bucket": { "Fn::Join": [ "", [ { "Fn::FindInMap": [ "Function", "SolutionHelperFunction", "S3Bucket" ] }, "-", { "Ref": "AWS::Region" } ] ] }, "S3Key": { "Fn::FindInMap": [ "Function", "SolutionHelperFunction", "S3Key" ] } }, "Runtime": "python3.8", "Timeout": 300 } }, "UUIDGenerator": { "Type": "Custom::UUIDGenerator", "Properties": { "ServiceToken": { "Fn::GetAtt": [ "SolutionHelper", "Arn" ] }, "Region": { "Ref": "AWS::Region" } } }, "CRRMonitorKey": { "Type" : "AWS::KMS::Key", "Properties" : { "Description" : "Key used to encrypt SNS/SQS messages for CRR Monitor solution", "Enabled": true, "EnableKeyRotation": true, "KeyPolicy": { "Statement": [ { "Sid": "Allow root user to administer the key", "Effect": "Allow", "Principal": { "AWS": { "Fn::Sub": "arn:${AWS::Partition}:iam::${AWS::AccountId}:root" } }, "Action": [ "kms:*" ], "Resource": [ "*" ] }, { "Sid": "Allow Amazon SNS to use this key", "Effect": "Allow", "Principal": { "Service": "sns.amazonaws.com" }, "Action": [ "kms:Decrypt", "kms:GenerateDataKey*" ], "Resource": "*" } ] } } }, "CRRMonitorKeyAlias": { "Type": "AWS::KMS::Alias", "Properties": { "AliasName": "alias/crr-monitor-encryption-key", "TargetKeyId": { "Ref": "CRRMonitorKey" } } } }, "Outputs": { "QueueURL": { "Description": "URL of newly created SQS Queue", "Value": { "Ref": "CRRMonitorQueue" } }, "QueueARN": { "Description": "ARN of newly created SQS Queue", "Value": { "Fn::GetAtt": [ "CRRMonitorQueue", "Arn" ] } }, "QueueName": { "Description": "Name newly created SQS Queue", "Value": { "Fn::GetAtt": [ "CRRMonitorQueue", "QueueName" ] } }, "MetricsNotificationTopic": { "Description": "Cloud Metrics Notification Topic", "Value": { "Fn::GetAtt": [ "CloudMetricsNotificationTopic", "TopicName" ] } }, "UUID": { "Description": "Newly created random UUID.", "Value": { "Fn::GetAtt": [ "UUIDGenerator", "UUID" ] } } }, "Metadata": { "AWS::CloudFormation::Interface": { "ParameterGroups": [ { "Label": { "default": "DynamoDB" }, "Parameters": [ "ArchiveToS3", "S3ArchiveBucket" ] }, { "Label": { "default": "Accounts" }, "Parameters": [ "remoteAccounts" ] } ], "ParameterLabels" : { "ArchiveToS3" : { "default" : "Archive to S3"}, "S3ArchiveBucket" : { "default" : "Archive Bucket" }, "remoteAccounts" : { "default" : "Remote Accounts" } } } } }