Standardizing contact information across a growing AWS footprint is a critical, yet often overlooked, part of cloud governance. Whether it’s ensuring the billing department receives invoices or making sure security notifications reach your SOC, manual updates are not scalable.
Today, we’re sharing a unified automation approach to manage both Primary and Alternate contacts across an entire AWS Organization using Python and Boto3.
The Challenge
As organizations scale, member accounts often end up with stale or inconsistent contact metadata. This can lead to missed security alerts or operational bottlenecks. AWS now provides APIs through the account and organizations services to handle these updates programmatically from the Management account.
The Solution: Automated Contact Management
We have published a comprehensive script on our Cacher Snippets library that handles two core workflows:
- Alternate Contact Automation: Targets specialized roles (Security, Operations, and Billing).
- Primary Contact Standardization: Mass-updates corporate address and identity details.
Access the full code here: https://snippets.cacher.io/snippet/78a7e179bfb70e1be449
Step-by-Step Implementation Guide
Follow these steps to deploy the scripts safely within your environment:
1. Configure IAM Permissions
The execution environment (Local machine, Lambda, or CloudShell) must be authenticated to the Management Account (or a delegated administrator account) with the following permissions:
organizations:ListAccountsaccount:PutContactInformationaccount:PutAlternateContact
2. Set Up Your Exclusion List
To prevent overwriting the Management account or specific "Break Glass" accounts, update the exclusion logic in the script:
Python
# Skip/Exclude sensitive accounts
if account_id != '111111111111' and account_id != '222222222222':
put_contact_information(account_id)
3. Define Your Standard Metadata
Populate the ContactInformation and AlternateContact dictionaries in the script with your organization’s standard data (e.g., your centralized SOC email for Security contacts and corporate headquarters for the address).
4. Execution
Run the script using Python 3. The process will:
- Paginate through your entire AWS Organization.
- Identify member accounts while respecting your exclusion list.
- Update the Primary and Alternate contacts, providing a console log for success or failure for each account.
Why This Matters
Automating these details ensures that AWS can always reach the right people during a security event or billing inquiry. By utilizing the organizations paginator, you ensure no new accounts are missed, keeping your governance posture consistent as you grow.
*For more AWS automation tips and cloud security insights, stay tuned to the Sentri Cloud Blog.
import boto3
# Assuming org_client is already initialized
org_client = boto3.client('organizations')
# Collect all accounts using paginator
accounts = []
paginator = org_client.get_paginator('list_accounts')
for page in paginator.paginate():
accounts.extend(page['Accounts'])
# Update the alternate contact details for each account in the organization
for account in accounts:
account_id = account['Id']
# Initialize a session using the AWS account
account_session = boto3.Session()
account_client = account_session.client('account')
# Now you can use account_client to update alternate contact details or perform other actions
try:
# Update alternate contact details for the account
account_client.put_alternate_contact(
AccountId=account_id,
AlternateContactType='SECURITY',
Title='',
EmailAddress='',
Name='',
PhoneNumber=''
)
account_client.put_alternate_contact(
AccountId=account_id,
AlternateContactType='OPERATIONS',
Title='',
EmailAddress='',
Name='',
PhoneNumber=''
)
account_client.put_alternate_contact(
AccountId=account_id,
AlternateContactType='',
Title='',
EmailAddress='',
Name='',
PhoneNumber=''
)
print(f"Updated alternate contact details for account: {account_id}")
except Exception as e:
print(f"Failed to update alternate contact details for account: {account_id}. Error: {e}")
import boto3
def put_contact_information(account_id):
account_client = boto3.client('account')
response = account_client.put_contact_information(
AccountId=account_id,
ContactInformation={
'FullName': '',
'AddressLine1': '',
'City': '',
'CountryCode': '',
'CompanyName': '',
'FullName': '',
'PhoneNumber': '',
'PostalCode': '',
'StateOrRegion': '',
'WebsiteUrl': '',
}
)
if response['ResponseMetadata']['HTTPStatusCode'] == 200:
print('Successfully updated contact information for account ID: {}'.format(account_id))
else:
print('Failed to update contact information for account ID: {}'.format(account_id))
def get_account_name(account_id):
"""
Retrieve the name of the AWS account.
:param account_id: ID of the AWS account
:return: Name of the AWS account
"""
client = boto3.client('organizations')
response = client.describe_account(AccountId=account_id)
return response['Account']['Name']
def main():
"""Loops through all accounts in an AWS organization and updates primary account information."""
organizations_client = boto3.client('organizations')
response = organizations_client.list_accounts()
for account in response['Accounts']:
account_id = account['Id']
# Skip/Exclude the master account(s)
if account_id != '222222222222' and account_id != '111111111111':
put_contact_information(account_id)
if __name__ == '__main__':
main()

Top comments (0)