AWSTemplateFormatVersion: 2010-09-09 Metadata: AWS::CloudFormation::Interface: ParameterGroups: - Label: default: "S3 for Code" Parameters: - CodeS3BucketPrefix - CodeS3Key - Label: defualt: "Resources to Protect" Parameters: - ProtectedResources - Label: default: "Health Check Keys" Parameters: - HealthCheckRegions - HealthCheckKey - ALBHealthCheckKey - CloudfrontHealthCheckKey - EIPEC2HealthCheckKey - NLBHealthCheckKey - Label: default: "Regions" Parameters: - PrimaryRegion - Label: default: "Tags" Parameters: - CheckTags - CheckTagsALB - CheckTagsCF - CheckTagsEIP - CheckTagsNLB - Label: default: "CloudFront Metrics" Parameters: - CloudFrontForceEnableEnhancedMetrics - Label: default: "Alerting" Parameters: - snsTopicDetails - snsCalculation Parameters: CodeS3BucketPrefix: Type: String CodeS3Key: Type: String Default: lambda.zip Remediation: Type: String Default: True AllowedValues: - True - False ALBHealthCheckKey: Type: String Default: code/route53/healthChecks/alb-health-check.yaml CloudfrontHealthCheckKey: Type: String Default: code/route53/healthChecks/cf-health-check.yaml EIPEC2HealthCheckKey: Type: String Default: code/route53/healthChecks/eip-health-check.yaml NLBHealthCheckKey: Type: String Default: code/route53/healthChecks/nlb-health-check.yaml CloudFrontForceEnableEnhancedMetrics: Type: String Default: Yes Description: If a protected CloudFront distribution does not have additional metrics enabled, create a monitoring subscription. This is mandatory if using default metrics for CloudFront alarms to have data. AllowedValues: - Yes - No HealthCheckRegions: Type: String Default: us-east-1,us-west-2,eu-west-1 Description: "Comma separated list of regions to complete Route 53 health checks from list of us-east-1, us-west-1, us-west-2, eu-west-1, ap-southeast-1, ap-southeast-2, ap-northeast-1, sa-east-1" CheckTags: Type: String Default: '[]' ProtectedResources: Type: String Default: alb,instance,cf,nlb Description: "Specify a comma separated list of resources that should be evaluated, allowed values include comma separated string containing: alb | ec2eip | nlb | cf" AllowedPattern: (alb|instance|cf|nlb)(,(alb|instance|cf|nlb))*$ snsTopicDetails: Type: String Description: "Specify to not enable SNS Notification of DDoS events. If snsCalculation is CentralAccount, the expected input is 111111111111|mytopic where 111111111111 is the central account ID, and mytopic is the name of the SNS Topic in each region. If snsCalculation is LocalAccount, specify only the SNS topic name that is present in each account" AllowedPattern: ([0-9]{11,12}\|[a-zZ-Z0-9\-\_]{0,200}|\|[a-zZ-Z0-9\-\_]{0,200}) Default: snsCalculation: Type: String Default: CentralAccount AllowedValues: - CentralAccount - LocalAccount PrimaryRegion: Type: String Default: us-east-1 Description: Controls where the ssm remediation role is created. specificy if this role will already exist outside of this deployment MessagesToBeProcessed: Type: Number Default: 5 Description: Number of messages to be processed by the CFNStackManage lambda Conditions: PrimaryRegionOnly: !Equals [!Ref "AWS::Region", !Ref "PrimaryRegion"] Resources: LambdaEvaluateRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / LambdaEvaluateRolePolicy: Type: 'AWS::IAM::Policy' Metadata: cfn_nag: rules_to_suppress: - id: W12 reason: "Wildcard resources required for statement1 actions, except config, all are read only" - id: W58 reason: "Permissions are granted, cfn-nag does not recognize" - id: W89 reason: "VPC bound lambda is not appropiate for this use case" - id: W92 reason: "Reserved concurrency is not appropiate for this use case" Properties: PolicyName: Policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "arn:aws:logs:*:*:*" - Effect: Allow Action: - "config:PutEvaluations" - "config:GetResourceConfigHistory" - "cloudfront:ListTagsForResource" - "ec2:DescribeAddresses" - "ec2:DescribeTags" - "ec2:DescribeInstances" - "ec2:DescribeNetworkInterfaces" - "elasticloadbalancing:DescribeTags" - "elasticloadbalancing:DescribeLoadBalancers" - "globalaccelerator:ListTagsForResource" - "shield:DescribeProtection" - "shield:ListProtections" - "route53:GetHealthCheck" - "xray:PutTraceSegments" - "xray:PutTelemetryRecords" Resource: "*" - Effect: Allow Action: - "kms:Decrypt" - "kms:GenerateDataKey" Resource: - !GetAtt "KMSKey.Arn" - Effect: Allow Action: - "sqs:GetQueueUrl" - "sqs:SendMessage" - "sqs:ListQueueTags" - "sqs:SetQueueAttributes" Resource: - !GetAtt "RemediateSQSQueue.Arn" Roles: - !Ref LambdaEvaluateRole LambdaRemediateRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / LambdaRemediateRolePolicy: Type: 'AWS::IAM::Policy' Metadata: cfn_nag: rules_to_suppress: - id: W12 reason: "Wildcard resources required for statement1 actions, except config, all are read only" - id: W58 reason: "Permissions are granted, cfn-nag does not recognize" - id: W89 reason: "VPC bound lambda is not appropiate for this use case" - id: W92 reason: "Reserved concurrency is not appropiate for this use case" - id: W76 reason: "Policy is involved but cannot be avoided or simplified" Properties: PolicyName: Policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: "*" - Effect: Allow Action: - "cloudfront:GetDistribution" - "cloudfront:ListTagsForResource" - "cloudfront:GetMonitoringSubscription" - "cloudfront:CreateMonitoringSubscription" - "config:GetResourceConfigHistory" - "ec2:DescribeAddresses" - "ec2:DescribeInstances" - "ec2:DescribeNetworkInterfaces" - "elasticloadbalancing:DescribeLoadBalancers" - "elasticloadbalancing:DescribeTags" - "shield:AssociateHealthCheck" - "shield:DisassociateHealthCheck" - "shield:DescribeProtection" - "shield:ListProtections" - "route53:GetHealthCheck" - "route53:CreateHealthCheck" - "route53:UpdateHealthCheck" - "route53:DeleteHealthCheck" - "route53:ChangeTagsForResource" - "cloudwatch:DescribeAlarms" - "cloudwatch:PutMetricAlarm" - "cloudwatch:DeleteAlarms" - "xray:PutTraceSegments" - "xray:PutTelemetryRecords" Resource: "*" - Effect: Allow Action: - "lambda:InvokeFunction" Resource: - !ImportValue "Route53ShieldProtectionManageLambdaFunctionArn" - Effect: Allow Action: - "kms:Decrypt" - "kms:GenerateDataKey" Resource: - !GetAtt "KMSKey.Arn" - Effect: Allow Action: - "cloudformation:CreateStack" - "cloudformation:DeleteStack" - "cloudformation:UpdateStack" - "cloudformation:DescribeStacks" Resource: - !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/HealthChecks-*/*" - Effect: Allow Action: - "s3:GetObject" Resource: - !Sub "arn:aws:s3:::${CodeS3BucketPrefix}-${AWS::Region}/*" - Effect: Allow Action: - "sqs:GetQueueUrl" - "sqs:SendMessage" - "sqs:ListQueueTags" - "sqs:SetQueueAttributes" Resource: - !GetAtt RemediateSQSQueue.Arn Roles: - !Ref LambdaRemediateRole LambdaCFNStackManageRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / LambdaCFNStackManageRolePolicy: Type: 'AWS::IAM::Policy' Metadata: cfn_nag: rules_to_suppress: - id: W12 reason: "IAM actions with * are required based on solution use case" - id: W76 reason: "IAM actions with * are required based on solution use case" Properties: PolicyName: Policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "*" - Effect: Allow Action: - "cloudformation:Create*" - "cloudformation:Delete*" - "cloudformation:Update*" - "cloudformation:Describe*" - "cloudformation:List*" - "cloudformation:UntagResource" - "cloudformation:TagResource" Resource: - !Sub "arn:aws:cloudformation:${AWS::Region}:${AWS::AccountId}:stack/HealthChecks-*/*" - Effect: Allow Action: - "cloudformation:ListStacks" Resource: "*" - Effect: Allow Action: - "s3:GetObject" Resource: - !Sub "arn:aws:s3:::${CodeS3BucketPrefix}-${AWS::Region}/*" - Effect: Allow Action: - "lambda:InvokeFunction" Resource: - !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:config-proactive-engagement-*" - Effect: Allow Action: - "cloudfront:GetDistribution" - "cloudfront:ListTagsForResource" - "cloudfront:GetMonitoringSubscription" - "cloudfront:CreateMonitoringSubscription" - "ec2:DescribeAddresses" - "ec2:DescribeInstances" - "ec2:DescribeNetworkInterfaces" - "elasticloadbalancing:DescribeLoadBalancers" - "elasticloadbalancing:DescribeTags" - "shield:AssociateHealthCheck" - "shield:DisassociateHealthCheck" - "shield:DescribeProtection" - "shield:ListProtections" - "shield:TagResource" - "shield:UntagResource" - "route53:GetHealthCheck" - "route53:CreateHealthCheck" - "route53:UpdateHealthCheck" - "route53:DeleteHealthCheck" - "route53:ChangeTagsForResource" - "cloudwatch:DescribeAlarms" - "cloudwatch:PutMetricAlarm" - "cloudwatch:DeleteAlarms" - "xray:PutTraceSegments" - "xray:PutTelemetryRecords" Resource: "*" - Effect: Allow Action: - "kms:Decrypt" Resource: - !GetAtt "KMSKey.Arn" - Effect: Allow Action: - "sqs:DeleteMessage" - "sqs:GetQueueUrl" - "sqs:ChangeMessageVisibility" - "sqs:PurgeQueue" - "sqs:ReceiveMessage" - "sqs:GetQueueAttributes" - "sqs:ListQueueTags" Resource: - !GetAtt RemediateSQSQueue.Arn Roles: - !Ref LambdaCFNStackManageRole ConfigPermissionToCallLambda: Type: AWS::Lambda::Permission Properties: FunctionName: Fn::GetAtt: - ConfigRuleEvaluateLambdaFunction - Arn Action: "lambda:InvokeFunction" Principal: "config.amazonaws.com" ConfigRuleEvaluateLambdaFunction: Type: AWS::Lambda::Function DependsOn: LambdaEvaluateRolePolicy Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: "Permissions are granted, cfn-nag does not recognize" - id: W89 reason: "VPC bound lambda is not appropiate for this use case" - id: W92 reason: "Reserved concurrency is not appropiate for this use case" Properties: TracingConfig: Mode: Active Code: S3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" S3Key: !Ref CodeS3Key Handler: "route53/config-proactive-engagement/lambda/check-compliance/index.lambda_handler" Runtime: python3.8 Timeout: 14 Environment: Variables: AccountId: !Ref "AWS::AccountId" SQS_QUEUE_URL: !GetAtt "RemediateSQSQueue.QueueUrl" checkTags: !Ref "CheckTags" ProtectedResources: !Ref "ProtectedResources" SNSTopicDetails: !Ref "snsTopicDetails" CodeS3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" CloudFrontForceEnableEnhancedMetrics: !Ref "CloudFrontForceEnableEnhancedMetrics" Role: Fn::GetAtt: - LambdaEvaluateRole - Arn RemediateLambdaFunction: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: "Permissions are granted, cfn-nag does not recognize" - id: W89 reason: "VPC bound lambda is not appropiate for this use case" - id: W92 reason: "Reserved concurrency is not appropiate for this use case" Properties: TracingConfig: Mode: Active Code: S3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" S3Key: !Ref CodeS3Key Handler: "route53/config-proactive-engagement/lambda/remediate/index.lambda_handler" Runtime: python3.9 Timeout: 693 ReservedConcurrentExecutions: 1 Environment: Variables: AccountId: !Ref "AWS::AccountId" CodeS3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" HC_Regions: !Ref "HealthCheckRegions" snsTopicDetails: !Ref "snsTopicDetails" SNSCalculation: !Ref "snsCalculation" ALBHealthCheckKey: !Ref "ALBHealthCheckKey" CloudfrontHealthCheckKey: !Ref "CloudfrontHealthCheckKey" EIPEC2HealthCheckKey: !Ref "EIPEC2HealthCheckKey" NLBHealthCheckKey: !Ref "NLBHealthCheckKey" CloudFrontForceEnableEnhancedMetrics: !Ref "CloudFrontForceEnableEnhancedMetrics" # SQS_QUEUE_URL: !Sub "https://sqs.${AWS::Region}.amazonaws.com/${AWS::AccountId/${SQSQName}" SQS_QUEUE_URL: !GetAtt "RemediateSQSQueue.QueueUrl" Role: Fn::GetAtt: - LambdaRemediateRole - Arn CFNStackManageLambdaFunction: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: "Has permission, does not use Amazon Managed Policy to grant" - id: W89 reason: "Not applicable for use case" Properties: TracingConfig: Mode: Active Code: S3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" S3Key: !Ref CodeS3Key Handler: "route53/config-proactive-engagement/lambda/cfn-stack-manage/index.lambda_handler" Runtime: python3.9 Timeout: 14 ReservedConcurrentExecutions: 1 Environment: Variables: AccountId: !Ref "AWS::AccountId" SQS_QUEUE_URL: !GetAtt "RemediateSQSQueue.QueueUrl" MSGS_TO_BE_PROCESSED: !Ref "MessagesToBeProcessed" CodeS3Bucket: !Sub "${CodeS3BucketPrefix}-${AWS::Region}" Role: !GetAtt "LambdaCFNStackManageRole.Arn" CFNStackManageLambdaEventSourceMapping: Type: AWS::Lambda::EventSourceMapping Properties: EventSourceArn: !GetAtt "RemediateSQSQueue.Arn" FunctionName: !GetAtt "CFNStackManageLambdaFunction.Arn" CFNStackManageLambdaInvokePermissions: Type: AWS::Lambda::Permission Metadata: cfn_nag: rules_to_suppress: - id: W89 reason: "Not appropiate for use case" Properties: FunctionName: !GetAtt "CFNStackManageLambdaFunction.Arn" Action: lambda:InvokeFunction Principal: sqs.amazonaws.com SourceArn: !GetAtt "RemediateSQSQueue.Arn" KMSKey: Type: 'AWS::KMS::Key' Properties: Description: SQS Message Encryption Key EnableKeyRotation: true PendingWindowInDays: 20 KeyPolicy: Version: 2012-10-17 Id: key-default-1 Statement: - Sid: Enable IAM User Permissions Effect: Allow Principal: AWS: !Sub 'arn:aws:iam::${AWS::AccountId}:root' Action: 'kms:*' Resource: '*' #- Sid: ProducerAccessToSQSKMS #Effect: Allow #Principal: #AWS: #- !GetAtt "ConfigRuleEvaluateLambdaFunction.Arn" #- !GetAtt "RemediateLambdaFunction.Arn" #- !GetAtt "CFNStackManageLambdaFunction.Arn" #Action: #- "kms:GenerateDataKey" #- "kms:Decrypt" #Resource: "*" #- Sid: ConsumerAccessToSQSKMS #Effect: Allow #Principal: #AWS: !GetAtt "CFNStackManageLambdaFunction.Arn" #Action: #- "kms:Decrypt" #Resource: '*' RemediateSQSQueue: Type: AWS::SQS::Queue Properties: DelaySeconds: 0 MaximumMessageSize: 262144 MessageRetentionPeriod: 1209600 ReceiveMessageWaitTimeSeconds: 0 KmsMasterKeyId: !Ref "KMSKey" RedrivePolicy: deadLetterTargetArn: !GetAtt RemediateDLQ.Arn maxReceiveCount: 960 VisibilityTimeout: 15 RemediateDLQ: Type: AWS::SQS::Queue Properties: ReceiveMessageWaitTimeSeconds: 20 VisibilityTimeout: 60 KmsMasterKeyId: !Ref "KMSKey" SSMAutomationPermissionToCallLambda: Type: AWS::Lambda::Permission Properties: FunctionName: Fn::GetAtt: - RemediateLambdaFunction - Arn Action: "lambda:InvokeFunction" Principal: "ssm.amazonaws.com" ConfigRule: Type: AWS::Config::ConfigRule Properties: Scope: ComplianceResourceTypes: - "AWS::Shield::Protection" - "AWS::ShieldRegional::Protection" MaximumExecutionFrequency: One_Hour Source: Owner: "CUSTOM_LAMBDA" SourceIdentifier: !GetAtt ConfigRuleEvaluateLambdaFunction.Arn SourceDetails: - EventSource: aws.config MessageType: ScheduledNotification MaximumExecutionFrequency: One_Hour - EventSource: "aws.config" MessageType: "ConfigurationItemChangeNotification" - EventSource: aws.config MessageType: OversizedConfigurationItemChangeNotification DependsOn: ConfigPermissionToCallLambda SSMRole: Type: AWS::IAM::Role Properties: AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com - config.amazonaws.com Action: - 'sts:AssumeRole' ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole Path: / SSMRolePolicy: Type: 'AWS::IAM::Policy' Properties: PolicyName: Policy PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - "logs:CreateLogGroup" - "logs:CreateLogStream" - "logs:PutLogEvents" Resource: "arn:aws:logs:*:*:*" - Effect: Allow Action: - "lambda:InvokeFunction" Resource: - !GetAtt "RemediateLambdaFunction.Arn" Roles: - !Ref SSMRole SSMDocument: Type: AWS::SSM::Document Properties: DocumentType: Automation DocumentFormat: YAML Content: description: description schemaVersion: '0.3' assumeRole: !GetAtt SSMRole.Arn parameters: ResourceArn: type: String allowedPattern: '[a-zA-Z0-9\\-]*' minChars: 36 maxChars: 36 AutomationAssumeRole: type: String default: '' mainSteps: - name: proactive_engagement_health_check_cloudfront action: 'aws:invokeLambdaFunction' inputs: InvocationType: Event FunctionName: !Ref RemediateLambdaFunction Payload: '"{{ ResourceArn }}"' ConfigRuleRemediationConfiguration: Type: "AWS::Config::RemediationConfiguration" Properties: Automatic: !Ref Remediation ConfigRuleName: !Ref ConfigRule MaximumAutomaticAttempts: 5 RetryAttemptSeconds: 15 ExecutionControls: SsmControls: ConcurrentExecutionRatePercentage: 2 ErrorPercentage: 100 Parameters: ResourceArn: ResourceValue: Value: RESOURCE_ID AutomationAssumeRole: StaticValue: Values: - !GetAtt SSMRole.Arn TargetId: !Ref SSMDocument TargetType: "SSM_DOCUMENT" TargetVersion: "1" AutomationServiceRole: Condition: PrimaryRegionOnly Type: AWS::IAM::Role Metadata: cfn_nag: rules_to_suppress: - id: W28 reason: "Resource Name is not configurable for this service and if it ever is, is not relevant for this use case" Properties: AssumeRolePolicyDocument: Version: '2012-10-17' Statement: - Effect: Allow Principal: Service: - ssm.amazonaws.com - config.amazonaws.com Action: sts:AssumeRole ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AmazonSSMAutomationRole Path: "/" RoleName: ConfigRemediationSSMServiceRole Policies: - PolicyName: ConfigRemediationSSMServicePolicy PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: 'lambda:InvokeFunction' Resource: !Sub "arn:aws:lambda:*:${AWS::AccountId}:function:config-proactive-engagement-*"