
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