Automating Contact Updates Across Accounts In Your Organization

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • MyrinNew
    Senior Member
    • Feb 2024
    • 5175

    #1

    Automating Contact Updates Across Accounts In Your Organization

    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:

    1. Alternate Contact Automation: Targets specialized roles (Security, Operations, and Billing).
    2. 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:ListAccounts
    • account:PutContactInformation
    • account: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.

    aram 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()










    More...
Working...