Customers use the cloud to move faster and build differentiated products and services. AWS lets you experiment, innovate, and scale more quickly, all while providing a flexible and secure cloud environment. Furthermore, a multi-account AWS environment lets you build and deploy workloads quickly, while providing mechanisms to do so in a secure, scalable, and resilient manner. As well, in a multi-account AWS environment, it is important that the alternate AWS Account contacts for Billing, Operations, and Security teams receive important notifications about the AWS accounts in addition to the primary Account owner. For customers using AWS Organizations, organization administrators can now centrally manage alternate contacts for member accounts using the management account or a delegated administrator account without requiring credentials for each AWS account. For example, you can set the same security alternate contact on all of your accounts, so that your Cloud Center of Excellence (CCoE) team can receive important security notifications about your AWS accounts. Managing alternate contacts becomes even more important as your organization scales to hundreds or thousands of accounts. This saves you time and reduces the operational burden.

In this post, we will demonstrate a solution to update the alternate contact details automatically for any newly created AWS accounts as part of the account creation process. This will make sure that the right group of individuals receive important AWS notifications and can respond to it. Moreover, this solution will work for accounts created either through the AWS Organizations or AWS Control Tower Account Factory.

Solution Overview

In this solution, we will use a combination of Amazon EventBridge, AWS Lambda, and AWS Account Management API to listen to AWS Account creation events and update the alternate contact details in the newly created AWS account. The solution architecture is shown in the following figure.

Architecture flow diagram for programmatically adding alternate contacts to a new AWS account

Figure 1: Solution Architecture

The solution workflow includes the following steps:

  1. Administrator creates a new AWS Account through AWS Organizations (1a) or AWS Control Tower Account Factory (1b).
  2. After the successful creation of the AWS account, an EventBridge event is created with detail type as a CreateAccountResult for AWS Organizations (2a) and CreateManagedAccount for the AWS Control Tower Account Factory Lifecycle event (2b).
  3. An EventBridge rule will trigger a Lambda function that is configured as a target every time an EventBridge event is generated for the account creation. The EventBridge rule configuration for the AWS Organizations events and AWS Control Tower Lifecycle event is shown in the following section.

AWS Organizations Account Creation Rule:

{ "detail-type": ["AWS Service Event via CloudTrail"], "source": ["aws.organizations"], "detail": { "serviceEventDetails": { "createAccountStatus": { "state": ["SUCCEEDED"] } }, "eventName": ["CreateAccountResult"] }
}

AWS Control Tower Lifecycle Event Rule:

{ "detail-type": ["AWS Service Event via CloudTrail"], "source": ["aws.controltower"], "detail": { "serviceEventDetails": { "createManagedAccountStatus": { "state": ["SUCCEEDED"] } }, "eventName": ["CreateManagedAccount"] }
}
  1. The Lambda function uses the account ID from the event payload, and it uses the alternate contact details available as environment variables to update them within the newly created AWS Account using the Account Management API. The following python code within the Lambda handler uses the environment variables to update alternate contacts for the Billing, Operations, and Security contact types. The AccountHelper uses the Account Management API PutAlternateContact action:
def lambda_handler(event, context): billing_email = os.environ["BILLING_EMAIL"] security_email = os.environ["SECURITY_EMAIL"] operations_email = os.environ["OPERATIONS_EMAIL"] billing_contact = os.environ["BILLING_CONTACT_NAME"] security_contact = os.environ["SECURITY_CONTACT_NAME"] operations_contact = os.environ["OPERATIONS_CONTACT_NAME"] billing_contact_title = os.environ["BILLING_CONTACT_TITLE"] security_contact_title = os.environ["SECURITY_CONTACT_TITLE"] operations_contact_title = os.environ["OPERATIONS_CONTACT_TITLE"] billing_contact_phone = os.environ["BILLING_CONTACT_PHONE"] security_contact_phone = os.environ["SECURITY_CONTACT_PHONE"] operations_contact_phone = os.environ["OPERATIONS_CONTACT_PHONE"] status='' new_account_id='' if event["source"] == "aws.organizations": aws_event:AWSEvent = Marshaller.unmarshall(event, AWSEvent) status = aws_event.detail.serviceEventDetails.createAccountStatus.state new_account_id = aws_event.detail.serviceEventDetails.createAccountStatus.accountId else: aws_event:ctAWSEvent = ctMarshaller.unmarshall(event, ctAWSEvent) status = aws_event.detail.serviceEventDetails.createManagedAccountStatus.state response = AccountHelper.update_account_contact(new_account_id,billing_email,"BILLING",billing_contact,billing_contact_title,billing_contact_phone) logger.info("Updated Billing alternate Contact") response = AccountHelper.update_account_contact(new_account_id,security_email,"SECURITY",security_contact,security_contact_title,security_contact_phone) logger.info("Updated Security alternate Contact") response = AccountHelper.update_account_contact(new_account_id,operations_email,"OPERATIONS",operations_contact,operations_contact_title,operations_contact_phone) logger.info("Updated Operations alternate Contact") return { 'statusCode': 200, 'body': json.dumps('Processed the EventBridge event') }

Prerequisites

  • Your AWS organization must have all features enabled (this is the default setting for almost all organizations).
  • Enable the AWS Account Management service for your organization so that you can centrally manage alternate contacts. You can do this by using the following CLI command from the management account:
aws organizations enable-aws-service-access --service-principal account.amazonaws.com

Solution Deployment

Deploy the solution using either the AWS Management Console, or from the GitHub repository using the AWS SAM CLI.

Note: If you create a new account through AWS Organizations, you must deploy the solution in us-east-1 Region. If you create new accounts through AWS Control Tower Account Factory, then you must deploy this solution in the same region as your Control Tower activation region.

The solution creates a new IAM role with AWSLambdaBasicExecutionRole AWS-Managed policy and the following account-management API permissions:

{ "Version": "2012-10-17", "Statement": [ { "Action": [ "account:PutAlternateContact" ], "Resource": [ "arn:aws:organizations::<<Org. Management Account ID>>:account/o-*/*" ], "Effect": "Allow" } ]
}

To deploy the solution using the AWS Management Console

  1. In your AWS Organizations Management account, launch the template by choosing the Launch Stack button below, which creates the stack in the us-east-1 Region.     Launch stack button
  2. On the Quick create stack page, for Stack name, enter a unique stack name for this account; for example, aws-account-contact-bootstrap-stack, as shown in the following figure.

screenshot of quick create stack page.

Figure 2: Quick Create CloudFormation stack for the solution

  1. Fill in the values Contact Name, Email, Title, and Phone Number for the Billing, Operations, and Security functions.
  2. For TypeOfDeployment, choose ORGANIZATIONS if you will be creating the new accounts through the AWS Organizations, or CONTROL_TOWER if you have AWS Control Tower enabled and will be using Account Factory to create the new accounts.
  3. Choose Create stack.

To deploy the solution from the GitHub Repository and AWS SAM CLI

  1. Install the AWS SAM CLI
  2. Download or clone the github repository using the following commands:
$ git clone [email protected]:aws-samples/aws-account-alternate-contacts-bootstrap.git
$ cd aws-account-alternate-contacts-bootstrap

To create a new bucket for deployment artifacts, run create-bucket.sh by specifying the region as argument as follows:

$ ./create-bucket.sh us-east-1
  1. Update the content of the profile.txt file with the profile name that you want to use for the deployment.
  2. Deploy the solution to the account by running the deploy.sh script by specifying the region as argument.
$ ./deploy.sh us-east-1

Testing the Solution

To test the solution, we will create a new account through AWS Organizations with details shown in the following figure.

Figure 3: Create a new AWS Account

Figure 3: Create a new AWS Account

Verify that the Lambda created by the solution was triggered by the new AWS Account creation EventBridge notification from the Monitor tab for the Lambda function or Amazon CloudWatch Logs for the Lambda function. You can find Lambda in the resources section of the solution’s AWS CloudFormation Stack. An example execution of the Lambda function is shown in the following figure.

Figure 4: Amazon CloudWatch logs for Lambda execution

Figure 4: Amazon CloudWatch logs for Lambda execution

Navigate to the Account Setting page for the newly created AWS Account, and review the Alternate Contacts sections to validate that the details are populated and match the input provided during the solution deployment.

Figure 5: Account Alternate Contacts

Cleanup

Delete any unused resources to avoid incurring future charges. You can do this through AWS CloudFormation console if you created the stack through the Launch Stack button. On the other hand, if you deployed the solution from GitHub repository, then you can delete the solution by executing the cleanup.sh script available in the cloned repository.

$ ./cleanup.sh us-east-1

Conclusion

In this post, we demonstrated a solution for automating the updating of the alternate contacts when a new account is created. Once you deploy this solution, any newly created AWS accounts will be automatically updated with a predefined set of alternate contacts. You can also programmatically manage alternate accounts on existing accounts or manage AWS account alternate contacts with Terraform.

About the authors

Sudhanshu Malhotra

Sudhanshu Malhotra is a Boston-based Enterprise Solutions Architect for AWS. He’s a technology enthusiast who enjoys helping customers find innovative solutions to complex business challenges. His areas of focus are DevOps, machine learning, and security. When he’s not working with customers on their journey to the cloud, he enjoys reading, hiking, and exploring new cuisines.

Siva Rajamani

Siva Rajamani is a Boston-based Enterprise Solutions Architect at AWS. He enjoys working closely with customers and supporting their digital transformation and AWS adoption journey. His areas of focus are serverless, application integration, and security. Outside of work, he enjoys outdoor activities and watching documentaries.