To automatically generate a "Sign-in URL" to a newly added Control Tower account, you will need the following:
- create a Lambda function on the master account (the region must be us-east-1 – Virginia, so we will use CloudTrail as a trigger);
- create a policy that allows you to assign a role and attach it to the Lambda role;
- create a CloudWatch Event Rule and specify a lambda as a target;
- create a StackSet on the master account to create the necessary role and policy on the new account in the OU;
StackSet:
AWSTemplateFormatVersion: 2010-09-09 Description: 'Template create IAM Roles and Policies for access from Control Tower master account' Resources: ControlTowerMaster: Type: 'AWS::IAM::Role' Properties: RoleName: 'ControlTower-Master' AssumeRolePolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Principal: AWS: - "arn:aws:iam::XXXXXXXXXXXX:root" Action: - 'sts:AssumeRole' Policies: - PolicyName: 'ControlTower-Master' PolicyDocument: Version: 2012-10-17 Statement: - Effect: Allow Action: - 'iam:CreateAccountAlias' Resource: '*' MaxSessionDuration: 3600 Path: /
Where "XXXXXXXXXXXX" – master account ID
Lambda:
import boto3 import re def get_account_name(account_id): account_name = boto3.client('organizations').describe_account(AccountId = account_id).get('Account').get('Name') create_account_alias(account_id, account_name) def create_account_alias(account_id, account_name): account_name = re.sub('[^A-Za-z0-9]+', '-', account_name) sts_client = boto3.client('sts') response = sts_client.assume_role( RoleArn = "arn:aws:iam::" + str(account_id) + ":role/AIT-ControlTower-Master", RoleSessionName = 'assume_role_session' ) iam_client = boto3.client( 'iam', aws_access_key_id = response['Credentials']['AccessKeyId'], aws_secret_access_key = response['Credentials']['SecretAccessKey'], aws_session_token = response['Credentials']['SessionToken'] ) # Create an account alias iam_client.create_account_alias( AccountAlias = account_name.lower() ) def main(event, context): account_id = (event["detail"]["requestParameters"]["accountId"]) get_account_name(account_id) if __name__ == '__main__': main()
Lambda Policy:
{ "Version": "2012-10-17", "Statement": { "Effect": "Allow", "Action": "sts:AssumeRole", "Resource": "*" } }
CloudWatch Event Rule:
{ "source": [ "aws.organizations" ], "detail-type": [ "AWS API Call via CloudTrail" ], "detail": { "eventSource": [ "organizations.amazonaws.com" ], "eventName": [ "MoveAccount" ], "requestParameters": { "sourceParentId": [ "r-xxx" ], "destinationParentId": [ "ou-xxx-yyyyyyyy" ] } } }
Where "r-xxx" – your organization ID, and "ou-xxx-yyyyyyyy" – OU ID