組織下のAWSアカウントの名前や所属OUを一覧にしてCSV出力したい【Python, Boto3】

2024.03.26

AWSアカウントの情報一覧をCSVとして保存したいです。 ここでいう情報はAWSアカウントの名前やID、所属する組織単位(OU)などです。

AWSアカウントの名前、IDだけであれば organizations list-accounts のみで済みますが、 私としては所属するOUの情報もほしいです。 その場合は少しスクリプトを作り込まないと いけません。

今回は Python(Boto3)スクリプトを書いて、 これを実現してみます。

出したいCSV

organizations list-accounts で取得できるAWSアカウント情報に加えて、 所属するOUも付与したいです。 イメージとしては以下のような表になります。

Name Id OU Path OU ID Email Status JoinedMethod JoinedTimestamp
Payer-XXX 111111111111 /root r-xxxx payer@example.com ACTIVE INVITED 2023/04/13 18:53:07
Infra 222222222222 /root/Infra ou-xxxx-aaaaa infra@example.com ACTIVE CREATED 2023/12/15 10:30:14
Workload 333333333333 /root/Workloads ou-xxxx-bbbbb workload@example.com ACTIVE CREATED 2023/11/20 09:44:05
Audit 444444444444 /root/Security ou-xxxx-ccccc audit@example.com ACTIVE CREATED 2023/10/13 17:40:18
LogArchive 555555555555 /root/Security ou-xxxx-ccccc logarchive@example.com ACTIVE CREATED 2023/10/13 17:40:25

書いたスクリプト

以下に作成した Pythonスクリプトを記載します。 追加で pip install が必要なパッケージは boto3 のみです。

org-inventory-accounts.py

import boto3
import logging
from datetime import datetime
from operator import itemgetter
import csv

logging.basicConfig(level=logging.INFO)
org_client = boto3.client('organizations')

OU_DICT = {}

def create_ou_dict (parent_id, parent_name, prefix):
    ou_path = f'{prefix}/{parent_name}'
    OU_DICT[parent_id] = ou_path
    response = org_client.list_organizational_units_for_parent(
        ParentId=parent_id
    )
    for ou in response.get('OrganizationalUnits'):
        create_ou_dict(ou.get('Id'), ou.get('Name'), ou_path)

def org_root():
    response = org_client.list_roots()
    return response.get('Roots')[0].get('Id')

def accounts_for_parent(parent_id):
    response = org_client.list_accounts_for_parent(
        ParentId=parent_id
    )
    return response.get('Accounts')

def main():
    # 実行開始時刻取得と出力ファイル名の確定
    datetime_now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    file_path = f'accounts_{datetime_now}.csv'
    logging.info(f'[start] timestamp: {datetime_now}')

    # OUパスの辞書作成
    logging.info('# getting OU dictionary...')
    create_ou_dict(org_root(), 'root', '')
    logging.info(f'-> number of OUs: {len(OU_DICT)}')

    # AWSアカウント情報のリスト作成
    logging.info('# creating AWS accounts list...')
    accounts = []
    for ou_id, ou_path in OU_DICT.items():
        logging.info(f'## searching accounts in {ou_path}...')
        for account in accounts_for_parent(ou_id):
            accounts.append([
                account.get('Name'), account.get('Id'),
                ou_path, ou_id,
                account.get('Email'), account.get('Status'),
                account.get('JoinedMethod'),
                account.get('JoinedTimestamp').strftime('%Y/%m/%d %H:%M:%S')
            ])
    logging.info(f'-> number of accounts: {len(accounts)}')

    # CSV出力
    logging.info(f'# generating csv ({file_path})')
    header = [
        'Name', 'Id',
        'OU Path', 'OU ID',
        'Email', 'Status',
        'JoinedMethod', 'JoinedTimestamp'
    ]
    rows = [header] + sorted(accounts, key=itemgetter(0,2))
    with open(file_path, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
        writer.writerows(rows)
    logging.info('[end]')

main()

実行例

実行するにあたって、以下AWSアクションの権限が必要です。

  • Organizations:ListRoots
  • Organizations:ListOrganizationsUnitsForParent
  • Organizations:ListAccountsForParent

上記権限を持った認証情報を事前にセットして、 スクリプトを実行します。 以下実行サンプルです。

$ python3 ./org-inventory-accounts.py
# INFO:botocore.credentials:Found credentials in environment variables.
# INFO:root:[start] timestamp: 2024-03-26_08-44-15
# INFO:root:# getting OU dictionary...
# INFO:root:-> number of OUs: 4
# INFO:root:# creating AWS accounts list...
# INFO:root:## searching accounts in /root...
# INFO:root:## searching accounts in /root/Security...
# INFO:root:## searching accounts in /root/Workloads...
# INFO:root:## searching accounts in /root/Infrastructure...
# INFO:root:-> number of accounts: 5
# INFO:root:# generating csv (accounts_2024-03-26_08-44-15.csv)
# INFO:root:[end]

出力されたCSVは以下のとおり。 「出したい出力」章にて記載した表と同じ構成です。

"Name","Id","OUPath","OUID","Email","Status","JoinedMethod","JoinedTimestamp"
"Payer-XXX","111111111111","/root","r-xxxx","payer@example.com","ACTIVE","INVITED","2023/04/1318:53:07"
"Infra","222222222222","/root/Infra","ou-xxxx-aaaaa","infra@example.com","ACTIVE","CREATED","2023/12/1510:30:14"
"Workload","333333333333","/root/Workloads","ou-xxxx-bbbbb","workload@example.com","ACTIVE","CREATED","2023/11/2009:44:05"
"Audit","444444444444","/root/Security","ou-xxxx-ccccc","audit@example.com","ACTIVE","CREATED","2023/10/1317:40:18"
"LogArchive","555555555555","/root/Security","ou-xxxx-ccccc","logarchive@example.com","ACTIVE","CREATED","2023/10/1317:40:25"

おわりに

AWSアカウントの棚卸しスクリプトを書いてみました。 このCSVを使って QuickSight で可視化したり、 アカウント名の lookup で活用したりできそうです。

以上、参考になれば幸いです。

参考

補足

実行環境

  • OS: macOS Sonoma 14.3.1
  • Python: 3.11.7
  • boto3: 1.34.54