######################################################################## # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT-0 ######################################################################## AWSTemplateFormatVersion: 2010-09-09 Description: This template adds alternate contacts for Billing, Operations, and Security communications to the accounts. - 'account_alternate_contacts' solution in the repo, https://github.com/aws-samples/aws-security-reference-architecture-examples (sra-1ssgnse6j) Metadata: SRA: Version: 1.0 Order: 2 AWS::CloudFormation::Interface: ParameterGroups: - Label: default: General Properties Parameters: - pSRASolutionName - pSRAStagingS3BucketName - pSRAAlarmEmail - Label: default: Lambda Function Properties Parameters: - pAccountAlternateContactsLambdaRoleName - pAccountAlternateContactsLambdaFunctionName - pManagementAccountId - pOrganizationId - Label: default: Custom Resource Properties Parameters: - pAccountAlternateContactsConfigurationRoleName - pBillingContactAction - pOperationsContactAction - pSecurityContactAction - pExcludeAlternateContactAccountTags - pBillingEmail - pBillingName - pBillingPhone - pBillingTitle - pOperationsEmail - pOperationsName - pOperationsPhone - pOperationsTitle - pSecurityEmail - pSecurityName - pSecurityPhone - pSecurityTitle - Label: default: General Lambda Function Properties Parameters: - pCreateLambdaLogGroup - pLambdaLogGroupRetention - pLambdaLogGroupKmsKey - pLambdaLogLevel - Label: default: EventBridge Rule Properties Parameters: - pComplianceFrequency - pControlTowerLifeCycleRuleName - pEventRuleRoleName ParameterLabels: pAccountAlternateContactsLambdaFunctionName: default: Lambda Function Name pAccountAlternateContactsLambdaRoleName: default: Lambda Role Name pAccountAlternateContactsConfigurationRoleName: default: Account Alternate Contacts Configuration Role Name pBillingContactAction: default: Billing Alternate Contact Action pBillingEmail: default: (Optional) Billing Email Address pBillingName: default: (Optional) Billing Full Name pBillingPhone: default: (Optional) Billing Phone Number pBillingTitle: default: (Optional) Billing Title pComplianceFrequency: default: Frequency to Check for Organizational Compliance pControlTowerLifeCycleRuleName: default: Control Tower Lifecycle Rule Name pCreateLambdaLogGroup: default: Create Lambda Log Group pEventRuleRoleName: default: Event Rule Role Name pExcludeAlternateContactAccountTags: default: (Optional) Exclude Alternate Account Tags pLambdaLogGroupKmsKey: default: (Optional) Lambda Logs KMS Key pLambdaLogGroupRetention: default: Lambda Log Group Retention pLambdaLogLevel: default: Lambda Log Level pManagementAccountId: default: Management Account ID pOperationsContactAction: default: Operations Alternate Contact Action pOperationsEmail: default: (Optional) Operations Email Address pOperationsName: default: (Optional) Operations Full Name pOperationsPhone: default: (Optional) Operations Phone Number pOperationsTitle: default: (Optional) Operations Title pOrganizationId: default: Organization ID pSecurityContactAction: default: Security Alternate Contact Action pSecurityEmail: default: (Optional) Security Email Address pSecurityName: default: (Optional) Security Full Name pSecurityPhone: default: (Optional) Security Phone Number pSecurityTitle: default: (Optional) Security Title pSRAAlarmEmail: default: (Optional) SRA Alarm Email pSRASolutionName: default: SRA Solution Name pSRAStagingS3BucketName: default: SRA Staging S3 Bucket Name Parameters: pAccountAlternateContactsLambdaFunctionName: AllowedPattern: '^[\w-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [_, -] Default: sra-account-alternate-contacts Description: Lambda function name for updating the account alternate contacts. Type: String pAccountAlternateContactsLambdaRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. Default: sra-account-alternate-contacts-lambda Description: Lambda execution role for updating the account alternate contacts. Type: String pAccountAlternateContactsConfigurationRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -] Default: sra-account-alternate-contacts-configuration Description: Account Alternate Contacts Configuration role to assume in the accounts. Type: String pBillingContactAction: AllowedValues: ['add', 'delete', 'ignore'] Default: 'add' Description: Indicates whether to add, delete, or ignore the Billing alternate contact. Type: String pBillingEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Email Validation as per RFC2822 standards. Default: '' Description: (Optional) Email Address for Billing alternate contact. If 'Billing Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pBillingName: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Full Name for Billing alternate contact. If 'Billing Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pBillingPhone: AllowedPattern: '^$|^[\s0-9()+-]+$' ConstraintDescription: Must be numbers, special characters [()+-], and/or whitespace Default: '' Description: (Optional) Phone Number for Billing alternate contact. If 'Billing Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pBillingTitle: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Title for Billing alternate contact. If 'Billing Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pComplianceFrequency: ConstraintDescription: Compliance Frequency must be a number between 1 and 30, inclusive. Default: 7 Description: Frequency (in days between 1 and 30, default is 7) to check organizational compliance MinValue: 1 MaxValue: 30 Type: Number pControlTowerLifeCycleRuleName: AllowedPattern: '^[\w.-]{1,64}$' ConstraintDescription: Max 64 alphanumeric and underscore characters. Also special characters supported [., -] Default: sra-account-alternate-contacts-trigger Description: The name of the AWS Control Tower Life Cycle Rule. Type: String pCreateLambdaLogGroup: AllowedValues: ['true', 'false'] Default: 'false' Description: Indicates whether a CloudWatch Log Group should be explicitly created for the Lambda function, to allow for setting a Log Retention and/or KMS Key for encryption. Type: String pEventRuleRoleName: AllowedPattern: '^[\w+=,.@-]{1,64}$' ConstraintDescription: Max 64 alphanumeric characters. Also special characters supported [+, =, ., @, -]. Default: sra-account-alternate-contacts-global-events Description: Event rule role name for putting events on the home region event bus Type: String pExcludeAlternateContactAccountTags: AllowedPattern: '^$|.*' Description: '(Optional) Resource Tags that denote an Account should be excluded from this solution in JSON format: [{"Key": "string", "Value": "string"}, ... ]. For example, [{"Key": "exclude-alternate-contacts", "Value": "true"}].' Type: String pLambdaLogGroupKmsKey: AllowedPattern: '^$|^arn:(aws[a-zA-Z-]*){1}:kms:[a-z0-9-]+:\d{12}:key\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$' ConstraintDescription: 'Key ARN example: arn:aws:kms:us-east-2:111122223333:key/1234abcd-12ab-34cd-56ef-1234567890ab' Default: '' Description: (Optional) KMS Key ARN to use for encrypting the Lambda logs data. If empty, encryption is enabled with CloudWatch Logs managing the server-side encryption keys. Type: String pLambdaLogGroupRetention: AllowedValues: [1, 3, 5, 7, 14, 30, 60, 90, 120, 150, 180, 365, 400, 545, 731, 1827, 3653] Default: 14 Description: Specifies the number of days you want to retain log events. Type: String pLambdaLogLevel: AllowedValues: [INFO, ERROR, DEBUG] Default: INFO Description: Lambda Function Logging Level. Type: String pManagementAccountId: AllowedPattern: '^\d{12}$' ConstraintDescription: Must be alphanumeric or special characters [., _, -]. In addition, the slash character ( / ) used to delineate hierarchies in parameter names. Description: AWS Account ID of the Control Tower Management account. Type: String pOperationsContactAction: AllowedValues: ['add', 'delete', 'ignore'] Default: 'add' Description: Indicates whether to add, delete, or ignore the Operations alternate contact. Type: String pOperationsEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Email Validation as per RFC2822 standards. Default: '' Description: (Optional) Email Address for Operations alternate contact. If 'Operations Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pOperationsName: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Full Name for Operations alternate contact. If 'Operations Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pOperationsPhone: AllowedPattern: '^$|^[\s0-9()+-]+$' ConstraintDescription: Must be numbers, special characters [()+-], and/or whitespace Default: '' Description: (Optional) Phone Number for Operations alternate contact. If 'Operations Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pOperationsTitle: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Title for Operations alternate contact. If 'Operations Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pOrganizationId: AllowedPattern: '^o-[a-z0-9]{10,32}$' ConstraintDescription: The Organization ID must be a 12 character string starting with o- and followed by 10 lower case alphanumeric characters Description: AWS Organizations ID Type: String pSecurityContactAction: AllowedValues: ['add', 'delete', 'ignore'] Default: 'add' Description: Indicates whether to add, delete, or ignore the Security alternate contact. Type: String pSecurityEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Email Validation as per RFC2822 standards. Default: '' Description: (Optional) Email Address for Security alternate contact. If 'Security Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pSecurityName: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Full Name for Security alternate contact. If 'Security Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pSecurityPhone: AllowedPattern: '^$|^[\s0-9()+-]+$' ConstraintDescription: Must be numbers, special characters [()+-], and/or whitespace Default: '' Description: (Optional) Phone Number for Security alternate contact. If 'Security Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pSecurityTitle: AllowedPattern: '^(?![&<>\\%|]).*$' ConstraintDescription: All characters allowed except '&<>\%|' Default: '' Description: (Optional) Title for Security alternate contact. If 'Security Alternate Contact Action' parameter is set to 'add', then this parameter becomes required. Type: String pSRAAlarmEmail: AllowedPattern: '^$|^([a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+)$' ConstraintDescription: Email Validation as per RFC2822 standards. Default: '' Description: (Optional) Email address for receiving DLQ alarms. If empty, CloudWatch Alarm will not be created to notify when the DLQ has a queue depth of 1. Type: String pSRASolutionName: AllowedValues: [sra-account-alternate-contacts] Default: sra-account-alternate-contacts Description: The SRA solution name. The default value is the folder name of the solution. Type: String pSRAStagingS3BucketName: AllowedPattern: '^(?=^.{3,63}$)(?!.*[.-]{2})(?!.*[--]{2})(?!^(?:(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(?!$)|$)){4}$)(^(([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])\.)*([a-z0-9]|[a-z0-9][a-z0-9\-]*[a-z0-9])$)' ConstraintDescription: SRA Staging S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Description: SRA Staging S3 bucket name for the artifacts relevant to solution. (e.g., lambda zips, CloudFormation templates) S3 bucket name can include numbers, lowercase letters, uppercase letters, and hyphens (-). It cannot start or end with a hyphen (-). Type: String Rules: BillingContactValidation: RuleCondition: !Equals [!Ref pBillingContactAction, 'add'] Assertions: - Assert: !And - !Not [!Equals [!Ref pBillingName, '']] - !Not [!Equals [!Ref pBillingTitle, '']] - !Not [!Equals [!Ref pBillingEmail, '']] - !Not [!Equals [!Ref pBillingPhone, '']] AssertDescription: "'Billing Full Name', 'Billing Title', 'Billing Email' and 'Billing Phone' parameters are required if the 'Billing Alternate Contact Action' parameter is set to 'add'." OperationsContactValidation: RuleCondition: !Equals [!Ref pOperationsContactAction, 'add'] Assertions: - Assert: !And - !Not [!Equals [!Ref pOperationsName, '']] - !Not [!Equals [!Ref pOperationsTitle, '']] - !Not [!Equals [!Ref pOperationsEmail, '']] - !Not [!Equals [!Ref pOperationsPhone, '']] AssertDescription: "'Operations Full Name', 'Operations Title', 'Operations Email' and 'Operations Phone' parameters are required if the 'Operations Alternate Contact Action' parameter is set to 'add'." SecurityContactValidation: RuleCondition: !Equals [!Ref pSecurityContactAction, 'add'] Assertions: - Assert: !And - !Not [!Equals [!Ref pSecurityName, '']] - !Not [!Equals [!Ref pSecurityTitle, '']] - !Not [!Equals [!Ref pSecurityEmail, '']] - !Not [!Equals [!Ref pSecurityPhone, '']] AssertDescription: "'Security Full Name', 'Security Title', 'Security Email' and 'Security Phone' parameters are required if the 'Security Alternate Contact Action' parameter is set to 'add'." Conditions: cComplianceFrequencySingleDay: !Equals [!Ref pComplianceFrequency, 1] cCreateDLQAlarm: !Not [!Equals [!Ref pSRAAlarmEmail, '']] cCreateLambdaLogGroup: !Equals [!Ref pCreateLambdaLogGroup, 'true'] cUseGraviton: !Or - !Equals [!Ref 'AWS::Region', ap-northeast-1] - !Equals [!Ref 'AWS::Region', ap-south-1] - !Equals [!Ref 'AWS::Region', ap-southeast-1] - !Equals [!Ref 'AWS::Region', ap-southeast-2] - !Equals [!Ref 'AWS::Region', eu-central-1] - !Equals [!Ref 'AWS::Region', eu-west-1] - !Equals [!Ref 'AWS::Region', eu-west-2] - !Equals [!Ref 'AWS::Region', us-east-1] - !Equals [!Ref 'AWS::Region', us-east-2] - !Equals [!Ref 'AWS::Region', us-west-2] cUseKmsKey: !Not [!Equals [!Ref pLambdaLogGroupKmsKey, '']] cNotGlobalRegionUsEast1: !Not [!Equals [!Ref 'AWS::Region', us-east-1]] Resources: rAccountAlternateContactsDLQ: Type: AWS::SQS::Queue Properties: KmsMasterKeyId: alias/aws/sqs QueueName: !Sub ${pSRASolutionName}-dlq Tags: - Key: sra-solution Value: !Ref pSRASolutionName rAccountAlternateContactsDLQAlarm: Type: AWS::CloudWatch::Alarm Condition: cCreateDLQAlarm Properties: AlarmDescription: SRA DLQ alarm if the queue depth is 1 Namespace: AWS/SQS MetricName: ApproximateNumberOfMessagesVisible Dimensions: - Name: QueueName Value: !GetAtt rAccountAlternateContactsDLQ.QueueName Statistic: Sum Period: 300 EvaluationPeriods: 1 Threshold: 1 ComparisonOperator: GreaterThanThreshold AlarmActions: - !Ref rAccountAlternateContactsDLQAlarmTopic InsufficientDataActions: - !Ref rAccountAlternateContactsDLQAlarmTopic rAccountAlternateContactsDLQAlarmTopic: Type: AWS::SNS::Topic Condition: cCreateDLQAlarm Properties: DisplayName: !Sub ${pSRASolutionName}-dlq-alarm KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns TopicName: !Sub ${pSRASolutionName}-dlq-alarm Subscription: - Endpoint: !Ref pSRAAlarmEmail Protocol: email Tags: - Key: sra-solution Value: !Ref pSRASolutionName rAccountAlternateContactsDLQPolicy: Type: AWS::SQS::QueuePolicy Properties: Queues: - !Ref rAccountAlternateContactsDLQ PolicyDocument: Statement: - Effect: Allow Action: SQS:SendMessage Condition: ArnEquals: aws:SourceArn: - !GetAtt rAccountAlternateContactsLambdaFunction.Arn Resource: - !GetAtt rAccountAlternateContactsDLQ.Arn Principal: Service: events.amazonaws.com rAccountAlternateContactsLambdaCustomResource: Type: Custom::LambdaCustomResource Version: '1.0' Properties: ServiceToken: !GetAtt rAccountAlternateContactsLambdaFunction.Arn BILLING_CONTACT_ACTION: !Ref pBillingContactAction BILLING_EMAIL: !Ref pBillingEmail BILLING_NAME: !Ref pBillingName BILLING_PHONE: !Ref pBillingPhone BILLING_TITLE: !Ref pBillingTitle CONFIGURATION_ROLE_NAME: !Ref pAccountAlternateContactsConfigurationRoleName EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeAlternateContactAccountTags OPERATIONS_CONTACT_ACTION: !Ref pOperationsContactAction OPERATIONS_EMAIL: !Ref pOperationsEmail OPERATIONS_NAME: !Ref pOperationsName OPERATIONS_PHONE: !Ref pOperationsPhone OPERATIONS_TITLE: !Ref pOperationsTitle ROLE_SESSION_NAME: 'AccountAlternateContacts' SECURITY_CONTACT_ACTION: !Ref pSecurityContactAction SECURITY_EMAIL: !Ref pSecurityEmail SECURITY_NAME: !Ref pSecurityName SECURITY_PHONE: !Ref pSecurityPhone SECURITY_TITLE: !Ref pSecurityTitle SNS_TOPIC_ARN: !Ref rAccountAlternateContactsTopic rAccountAlternateContactsLambdaFunction: Type: AWS::Lambda::Function Metadata: cfn_nag: rules_to_suppress: - id: W58 reason: CloudWatch access provided by the attached IAM role - id: W89 reason: Lambda is not deployed within a VPC - id: W92 reason: Lambda does not need reserved concurrent executions. checkov: skip: - id: CKV_AWS_115 comment: Lambda does not need reserved concurrent executions. - id: CKV_AWS_117 comment: Lambda does not need to communicate with VPC resources. - id: CKV_AWS_173 comment: Environment variables are not sensitive Properties: FunctionName: !Ref pAccountAlternateContactsLambdaFunctionName Description: Configure Account Alternate Contacts Architectures: !If - cUseGraviton - [arm64] - !Ref AWS::NoValue Handler: app.lambda_handler Role: !GetAtt rAccountAlternateContactsLambdaRole.Arn Runtime: python3.9 Timeout: 900 Code: S3Bucket: !Ref pSRAStagingS3BucketName S3Key: !Sub ${pSRASolutionName}/lambda_code/${pSRASolutionName}.zip DeadLetterConfig: TargetArn: !GetAtt rAccountAlternateContactsDLQ.Arn Environment: Variables: LOG_LEVEL: !Ref pLambdaLogLevel CONFIGURATION_ROLE_NAME: !Ref pAccountAlternateContactsConfigurationRoleName BILLING_CONTACT_ACTION: !Ref pBillingContactAction BILLING_EMAIL: !Ref pBillingEmail BILLING_NAME: !Ref pBillingName BILLING_PHONE: !Ref pBillingPhone BILLING_TITLE: !Ref pBillingTitle EXCLUDE_ACCOUNT_TAGS: !Ref pExcludeAlternateContactAccountTags OPERATIONS_CONTACT_ACTION: !Ref pOperationsContactAction OPERATIONS_EMAIL: !Ref pOperationsEmail OPERATIONS_NAME: !Ref pOperationsName OPERATIONS_PHONE: !Ref pOperationsPhone OPERATIONS_TITLE: !Ref pOperationsTitle ROLE_SESSION_NAME: 'AccountAlternateContacts' SECURITY_CONTACT_ACTION: !Ref pSecurityContactAction SECURITY_EMAIL: !Ref pSecurityEmail SECURITY_NAME: !Ref pSecurityName SECURITY_PHONE: !Ref pSecurityPhone SECURITY_TITLE: !Ref pSecurityTitle SNS_TOPIC_ARN: !Ref rAccountAlternateContactsTopic Tags: - Key: sra-solution Value: !Ref pSRASolutionName rAccountAlternateContactsLambdaLogGroup: Type: AWS::Logs::LogGroup Condition: cCreateLambdaLogGroup DeletionPolicy: Retain UpdateReplacePolicy: Retain Properties: LogGroupName: !Sub /aws/lambda/${pAccountAlternateContactsLambdaFunctionName} KmsKeyId: !If - cUseKmsKey - !Ref pLambdaLogGroupKmsKey - !Ref AWS::NoValue RetentionInDays: !Ref pLambdaLogGroupRetention rAccountAlternateContactsLambdaRole: Type: AWS::IAM::Role Metadata: cfn_nag: rules_to_suppress: - id: W11 reason: Actions require wildcard in resource - id: W28 reason: The role name is defined checkov: skip: - id: CKV_AWS_111 comment: IAM write actions require wildcard in resource Properties: RoleName: !Ref pAccountAlternateContactsLambdaRoleName Description: !Sub Role for '${pAccountAlternateContactsLambdaRoleName}' Lambda function AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - lambda.amazonaws.com Tags: - Key: sra-solution Value: !Ref pSRASolutionName Policies: - PolicyName: sra-account-alternate-contacts-policy-iam PolicyDocument: Version: 2012-10-17 Statement: - Sid: AssumeRole Effect: Allow Action: sts:AssumeRole Resource: !Sub arn:${AWS::Partition}:iam::*:role/${pAccountAlternateContactsConfigurationRoleName} Condition: StringEquals: aws:PrincipalOrgId: !Ref pOrganizationId - PolicyName: sra-account-alternate-contacts-policy-logs PolicyDocument: Version: 2012-10-17 Statement: - Sid: CreateLogGroupAndEvents Effect: Allow Action: - logs:CreateLogGroup - logs:CreateLogStream - logs:PutLogEvents Resource: !Sub arn:${AWS::Partition}:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/lambda/${pAccountAlternateContactsLambdaFunctionName}:log-stream:* - PolicyName: sra-account-alternate-contacts-policy-organizations PolicyDocument: Version: 2012-10-17 Statement: - Sid: OrganizationsReadAccess Effect: Allow Action: - organizations:DescribeAccount - organizations:ListAccounts Resource: '*' - Sid: ListTagsForAccounts Effect: Allow Action: organizations:ListTagsForResource Resource: !Sub arn:${AWS::Partition}:organizations::${pManagementAccountId}:account/${pOrganizationId}/* - PolicyName: sra-account-alternate-contacts-policy-sns PolicyDocument: Version: 2012-10-17 Statement: - Sid: SNSPublish Effect: Allow Action: - sns:Publish - sns:PublishBatch Resource: !Ref rAccountAlternateContactsTopic - PolicyName: sra-account-alternate-contacts-policy-sqs PolicyDocument: Version: 2012-10-17 Statement: - Sid: SQSSendMessage Effect: Allow Action: sqs:SendMessage Resource: !GetAtt rAccountAlternateContactsDLQ.Arn rAccountAlternateContactsTopic: Type: AWS::SNS::Topic Properties: DisplayName: !Sub ${pSRASolutionName}-configuration KmsMasterKeyId: !Sub arn:${AWS::Partition}:kms:${AWS::Region}:${AWS::AccountId}:alias/aws/sns Tags: - Key: sra-solution Value: !Ref pSRASolutionName rAccountAlternateContactsTopicLambdaPermission: Type: AWS::Lambda::Permission Properties: Action: lambda:InvokeFunction FunctionName: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Principal: sns.amazonaws.com SourceArn: !Ref rAccountAlternateContactsTopic rAccountAlternateContactsTopicSubscription: Type: AWS::SNS::Subscription Properties: Endpoint: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Protocol: lambda TopicArn: !Ref rAccountAlternateContactsTopic rOrganizationsRule: Type: AWS::Events::Rule Properties: Name: !Sub ${pControlTowerLifeCycleRuleName}-org-update Description: SRA Account Alternate Contacts Trigger on Organizations update EventPattern: source: - aws.organizations detail-type: - AWS API Call via CloudTrail detail: eventSource: - organizations.amazonaws.com eventName: - AcceptHandshake - CreateAccountResult - TagResource State: ENABLED Targets: - Arn: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Id: !Ref pAccountAlternateContactsLambdaFunctionName rControlTowerLifeCycleRule: Type: AWS::Events::Rule Properties: Name: !Ref pControlTowerLifeCycleRuleName Description: SRA Account Alternate Contacts Control Tower Life Cycle Trigger (triggers on new Control Tower vended accounts) EventPattern: source: - aws.controltower detail-type: - AWS Service Event via CloudTrail detail: eventName: - CreateManagedAccount - UpdateManagedAccount State: ENABLED Targets: - Arn: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Id: !Ref pAccountAlternateContactsLambdaFunctionName rPermissionForControlTowerRuleToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt rControlTowerLifeCycleRule.Arn PermissionForOrganizationsRuleToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt rOrganizationsRule.Arn PermissionForScheduledComplianceRuleToInvokeLambda: Type: AWS::Lambda::Permission Properties: FunctionName: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Action: lambda:InvokeFunction Principal: events.amazonaws.com SourceArn: !GetAtt rScheduledComplianceRule.Arn rScheduledComplianceRule: Type: AWS::Events::Rule Properties: Name: !Sub ${pControlTowerLifeCycleRuleName}-organization-compliance Description: SRA Account Alternate Contacts Trigger for scheduled organization compliance ScheduleExpression: !If - cComplianceFrequencySingleDay - !Sub rate(${pComplianceFrequency} day) - !Sub rate(${pComplianceFrequency} days) State: ENABLED Targets: - Arn: !GetAtt rAccountAlternateContactsLambdaFunction.Arn Id: !Ref pAccountAlternateContactsLambdaFunctionName rCrossRegionEventRuleRole: Type: AWS::IAM::Role Condition: cNotGlobalRegionUsEast1 Metadata: cfn_nag: rules_to_suppress: - id: W28 reason: Specific role name provided Properties: RoleName: !Ref pEventRuleRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: sts:AssumeRole Principal: Service: - events.amazonaws.com Policies: - PolicyName: sra-account-alternate-contacts-policy-events PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: events:PutEvents Resource: !Sub arn:${AWS::Partition}:events:${AWS::Region}:${AWS::AccountId}:event-bus/default Outputs: oAccountAlternateContactsLambdaFunctionArn: Description: Account Alternate Contacts Lambda Function ARN Value: !GetAtt rAccountAlternateContactsLambdaFunction.Arn oAccountAlternateContactsLambdaLogGroupArn: Condition: cCreateLambdaLogGroup Description: Account Alternate Contacts Lambda Log Group ARN Value: !GetAtt rAccountAlternateContactsLambdaLogGroup.Arn oAccountAlternateContactsLambdaRoleArn: Description: Account Alternate Contacts Lambda Role ARN Value: !GetAtt rAccountAlternateContactsLambdaRole.Arn oCrossRegionEventRuleRoleArn: Condition: cNotGlobalRegionUsEast1 Description: Cross Region Event Rule Role ARN Value: !GetAtt rCrossRegionEventRuleRole.Arn