# * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # * SPDX-License-Identifier: MIT-0 # * # * Permission is hereby granted, free of charge, to any person obtaining a copy of this # * software and associated documentation files (the "Software"), to deal in the Software # * without restriction, including without limitation the rights to use, copy, modify, # * merge, publish, distribute, sublicense, and/or sell copies of the Software, and to # * permit persons to whom the Software is furnished to do so. # * # * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, # * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A # * PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT # * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION # * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. AWSTemplateFormatVersion: 2010-09-09 Description: AWS Control Tower Account Factory Solution Deployment Template Parameters: CreateConfigurationBucket: Description: Do you want to create configuration Amazon S3 bucket true|false Type: String Default: true AllowedValues: - true - false ConfigurationBucketName: Description: Name of Amazon S3 Configuration Bucket Type: String ConfigurationFileName: Description: Name and prefix of the configuration file Type: String Default: config.yml UpdateFileName: Description: Name and prefix of the update file Type: String Default: update.yml SourceCodeBucketName: Description: Name of Amazon S3 Bucket with lambda zipped source code Type: String SourceCodePackageName: Description: Name of code package including prefix Type: String Default: control-tower-account-factory-solution.zip FunctionName: Description: Account Factory AWS Lambda Function Name Type: String Default: control-tower-account-factory-lambda FunctionRoleName: Description: Account Factory AWS Lambda Function Role Name Type: String Default: control-tower-account-factory-lambda-role StateMachineName: Description: Name of AWS Step Function State Machine Type: String Default: control-tower-account-factory-state-machine StateMachineRoleName: Description: Name of AWS Step Function State Machine IAM Role Type: String Default: control-tower-account-factory-state-machine-role MaxIterations: Description: Maximum number of iteration for step funtion before report error Type: Number Default: 30 TrackingTableName: Description: Name of the Amazon DynamoDB table to track product deployments and updates Type: String Default: control-tower-account-factory-tracking-table TopicName: Description: Name of SNS Topic to send notification Type: String Default: control-tower-account-factory-notification NotificationEmail: Description: Email address where to send notification Type: String Default: '' Conditions: CreateConfigurationBucket: !Equals [!Ref CreateConfigurationBucket, 'true'] CreateNotification: !Not [!Equals [!Ref NotificationEmail, '']] Resources: AccountFactoryLambdaRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Ref FunctionRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - lambda.amazonaws.com Action: - 'sts:AssumeRole' Path: / ManagedPolicyArns: - arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole Policies: - PolicyName: "Lambda" PolicyDocument: Version: "2012-10-17" Statement: - Effect: "Allow" Action: - servicecatalog:List* - servicecatalog:Search* - servicecatalog:Describe* - servicecatalog:UpdateConstraint - servicecatalog:CreateConstraint - servicecatalog:ProvisionProduct - servicecatalog:AssociatePrincipalWithPortfolio - servicecatalog:DeleteConstraint - servicecatalog:UpdateProvisionedProduct - organizations:ListRoots - organizations:DescribeAccount - organizations:ListChildren - organizations:DescribeOrganization - organizations:DescribeOrganizationalUnit - organizations:ListAccountsForParent - organizations:ListOrganizationalUnitsForParent - organizations:ListParents - states:SendTaskSuccess - states:StartExecution - states:SendTaskFailure - cloudformation:CreateStackSet - cloudformation:CreateStackInstances - cloudformation:Describe* - cloudformation:List* - cloudformation:UpdateStackSet - kms:Decrypt - iam:GetRole - s3:GetObject Resource: "*" - Effect: Allow Action: - sns:Publish Resource: !Sub 'arn:aws:sns:${AWS::Region}:${AWS::AccountId}:${TopicName}' - Effect: Allow Action: - iam:PassRole Resource: !Sub 'arn:aws:iam::${AWS::AccountId}:role/service-role/AWSControlTowerStackSetRole' - Effect: Allow Action: - dynamodb:PutItem - dynamodb:UpdateItem - dynamodb:Scan Resource: !Sub 'arn:aws:dynamodb:${AWS::Region}:${AWS::AccountId}:table/${TrackingTableName}' AccountFactoryStateMachineRole: Type: 'AWS::IAM::Role' Properties: RoleName: !Ref StateMachineRoleName AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: Service: - states.amazonaws.com Action: - 'sts:AssumeRole' Path: / Policies: - PolicyName: "StateMachine" PolicyDocument: Version: "2012-10-17" Statement: - Effect: Allow Action: - xray:PutTraceSegments - xray:PutTelemetryRecords - xray:GetSamplingRules - xray:GetSamplingTargets Resource: "*" - Effect: Allow Action: - logs:CreateLogDelivery - logs:GetLogDelivery - logs:UpdateLogDelivery - logs:DeleteLogDelivery - logs:ListLogDeliveries - logs:PutResourcePolicy - logs:DescribeResourcePolicies - logs:DescribeLogGroups Resource: "*" - Effect: Allow Action: - lambda:InvokeFunction Resource: !Sub 'arn:aws:lambda:${AWS::Region}:${AWS::AccountId}:function:${FunctionName}' S3Bucket: Type: AWS::S3::Bucket Condition: CreateConfigurationBucket Properties: BucketName: !Ref ConfigurationBucketName AccessControl: BucketOwnerFullControl NotificationConfiguration: LambdaConfigurations: - Event: s3:ObjectCreated:* Filter: S3Key: Rules: - Name: suffix Value: !Ref UpdateFileName Function: !GetAtt AccountFactoryFunction.Arn TrackingTable: Type: AWS::DynamoDB::Table Properties: AttributeDefinitions: - AttributeName: "ProvisionName" AttributeType: "S" - AttributeName: "Date" AttributeType: "S" KeySchema: - AttributeName: "ProvisionName" KeyType: "HASH" - AttributeName: "Date" KeyType: "RANGE" ProvisionedThroughput: ReadCapacityUnits: 5 WriteCapacityUnits: 5 TableName: !Ref TrackingTableName AccountFactoryFunction: Type: AWS::Lambda::Function Properties: FunctionName: !Ref FunctionName Description: "AWS Custom Control Tower Lifecycle event Lambda function to customize new accounts" Handler: handler.lambda_handler Role: !GetAtt AccountFactoryLambdaRole.Arn Environment: Variables: configuration_bucket_name: !Ref ConfigurationBucketName configuration_file: !Ref ConfigurationFileName update_file: !Ref UpdateFileName lambda_role: !GetAtt AccountFactoryLambdaRole.Arn max_iterations: !Ref MaxIterations state_machine_name: !Ref StateMachineName notification_topic: !If [CreateNotification , !Ref TopicName, "none"] track_table: !Ref TrackingTableName Code: S3Bucket: !Ref SourceCodeBucketName S3Key: !Ref SourceCodePackageName Runtime: python3.8 Timeout: 900 ReservedConcurrentExecutions: 10 AccountFactoryStateMachine: Type: 'AWS::StepFunctions::StateMachine' Properties: StateMachineName: !Ref StateMachineName RoleArn: !GetAtt AccountFactoryStateMachineRole.Arn DefinitionString: Fn::Sub: |- { "Comment": "A state machine that deployes products to new AWS Control Tower account", "StartAt": "Init-Baseline-Products", "States": { "Init-Baseline-Products": { "Type": "Task", "Resource": "${AccountFactoryFunction.Arn}", "TimeoutSeconds": 300, "HeartbeatSeconds": 60, "ResultPath": "$", "Next": "Wait-On-Init-Products" }, "Wait-On-Init-Products": { "Type": "Wait", "Seconds": 60, "Next": "Baseline-Products" }, "Baseline-Products": { "Type": "Task", "Resource": "${AccountFactoryFunction.Arn}", "TimeoutSeconds": 300, "HeartbeatSeconds": 60, "ResultPath": "$", "Next": "Deployment-Status" }, "Wait-For-Products": { "Type": "Wait", "Seconds": 60, "Next": "Baseline-Products" }, "Deployment-Status": { "Type": "Choice", "Choices": [ { "Variable": "$.status", "StringEquals": "progress", "Next": "Wait-For-Products" }, { "Variable": "$.status", "StringEquals": "done", "Next": "Success" } ] }, "Success": { "Type": "Succeed" } } } ControlTowerEvent: Type: AWS::Events::Rule Properties: Description: Fire lambda on AWS ontrol Tower new account creation EventPattern: source: - aws.controltower detail-type: - AWS Service Event via CloudTrail detail: serviceEventDetails: createManagedAccountStatus: state: - SUCCEEDED eventName: - CreateManagedAccount Name: 'AWS-Controle-Tower-Baseline-New-Account' Targets: - Id: 'AWS-Controle-Tower-Baseline-Lambda' Arn: !GetAtt AccountFactoryFunction.Arn ControlTowerEventPermission: Type: AWS::Lambda::Permission Properties: FunctionName: !Ref FunctionName Action: "lambda:InvokeFunction" Principal: "events.amazonaws.com" SourceArn: !GetAtt ControlTowerEvent.Arn SourceAccount: !Ref "AWS::AccountId" SNSTopic: Type: AWS::SNS::Topic Condition: CreateNotification Properties: Subscription: - Endpoint: !Ref NotificationEmail Protocol: "email" TopicName: !Ref TopicName