AWS アカウントの代替の連絡先 (alternate contacts) を AWS CLI から登録する

はじめに

aws.amazon.com

2021/9/30 の当該アップデートで下記 3つの API が追加されました。

  • DeleteAlternateContact
  • GetAlternateContact
  • PutAlternateContact

その名の通り AWS アカウントの「代替の連絡先」を削除・取得・登録する API です。
勤務先で Organizations を導入したばかりのところにこのアップデートがやってきたので、全アカウントにセキュリティコンタクトを登録してみました。

事前準備

AWS CLI のアップデート(2021/10/03時点)

私の CloudShell の環境では AWS CLI のバージョンが旧く、登録のための aws account コマンドが使用できませんでした。
同様の状況だった場合は下記のコマンドで AWS CLI をアップデートしてください。

$ curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
$ unzip awscliv2.zip
$ sudo ./aws/install --update
$ aws --version
aws-cli/2.2.43 Python/3.8.8 Linux/4.14.243-185.433.amzn2.x86_64 exec-env/CloudShell exe/x86_64.amzn.2 prompt/off

「信頼されたアクセス」の有効化

Organizations 経由で代替の連絡先を登録するためには「信頼されたアクセス」を有効化してあげる必要があります。
管理アカウントで下記コマンドを実行して有効化します。

$ aws organizations enable-aws-service-access --service-principal account.amazonaws.com

登録手順(メンバーアカウント)

aws.amazon.com

基本的にこのブログにそって登録していきます。 以下の手順は管理アカウントの CloudShell から実施しています。

シェルスクリプトの準備

ブログ内の手順では2つのシェルスクリプトを使用してセキュリティコンタクトの登録を行っています。

loop-through-accounts.sh の準備

下記のコマンドを CloudShell で実行してシェルスクリプトの作成・パーミッションの変更を実施します。

cat << EOF > loop-through-accounts.sh
#! /bin/bash
    managementaccount=\`aws organizations describe-organization --query Organization.MasterAccountId --output text\`

    for account in \$(aws organizations list-accounts --query 'Accounts[].Id' --output text); do

            if [ "\$managementaccount" -eq "\$account" ]
                     then
                         echo 'Skipping management account.'
                         continue
            fi
            ./put-security-contact.sh -a \$account
            sleep 0.2
    done
EOF
chmod 755 loop-through-accounts.sh

このシェルスクリプトでは Organizations の組織配下に存在するメンバーアカウントのアカウント ID をリストし put-security-contact.sh (後述) に渡しています。
if ブロックで管理アカウントのアカウント ID が除外されている理由については後述します。
また、組織配下の AWS アカウント数が 1000 を超える場合は pagination で処理する必要があるのでご注意ください。

Using AWS CLI pagination options - AWS Command Line Interface

put-security-contact.sh の準備

下記のコマンドを CloudShell で実行してシェルスクリプトの作成・パーミッションの変更を実施します。
aws account put-alternate-contact のオプションの Email アドレス・電話番号・役職・氏名は適切なものに変更してください。

cat << EOF > put-security-contact.sh
#! /bin/bash
while getopts a: flag
do
    case "\${flag}" in
        a) account_id=\${OPTARG};;
    esac
done

echo 'Put security contact for account '\$account_id'...'
aws account put-alternate-contact \
  --account-id \$account_id \
  --alternate-contact-type=SECURITY \
  --email-address=security-contact@example.com \
  --phone-number="+1(555)555-5555" \
  --title="Security Contact" \
  --name="Mary Major"
echo 'Done putting security contact for account '\$account_id'.'

EOF
chmod 755 put-security-contact.sh

前述の loop-through-accounts.sh から受け取った AWS アカウント ID を元に代替の連絡先を登録するシェルスクリプトです。

登録の実行

上記2ファイルの準備が終わったら、loop-through-accounts.sh を実行して登録します。

./loop-through-accounts.sh

登録手順(管理アカウント)

管理アカウントに代替の連絡先を登録するためには下記のコマンドを実行します。
メンバーアカウントと同様に、Email アドレス・電話番号・役職・氏名を適切なものに変更したあと実行してください。

aws account put-alternate-contact \
  --alternate-contact-type=SECURITY \
  --email-address=security-contact@example.com \
  --phone-number="+1(555)555-5555" \
  --title="Security Contact" \
  --name="Mary Major"

メンバーアカウント用のコマンドとの差異は --account-id オプションの有無にあります。
代替の連絡先を登録するオペレーションには Standalone contextOrganizations contextの2種類があり、--account-id オプションでアカウント ID を指定しない場合 Standalone context として実行されます。
管理アカウントの代替の連絡先はこの Standalone context でのみ登録可能であるため、loop-through-accounts.sh では明示的に管理アカウントの ID を除外していました。
両 context の詳細については下記ドキュメントを参照してください。

Adding or updating the primary and alternate contact information - AWS Account Management

登録の確認

せっかくなので GetAlternateContact API を利用して各アカウントにセキュリティコンタクトが正しく登録されているか確認してみましょう。
下記のコマンドを CloudShell で実行してシェルスクリプトの作成・パーミッションの変更を実施します。

cat << EOF > check-security-contact.sh
#! /bin/bash
    managementaccount=\`aws organizations describe-organization --query Organization.MasterAccountId --output text\`
    for account in \$(aws organizations list-accounts --query 'Accounts[].Id' --output text); do
            echo AWS Account ID: \$account

            if [ "\$managementaccount" -eq "\$account" ]
                     then
                         aws account get-alternate-contact --alternate-contact-type=SECURITY
                         continue
            fi
            aws account get-alternate-contact --account-id \$account --alternate-contact-type=SECURITY
            sleep 0.2
    done
EOF
chmod 755 check-security-contact.sh

作成したシェルスクリプトを実行します。

$ ./check-security-contact.sh 
AWS Account ID: 111111111111
{
    "AlternateContact": {
        "AlternateContactType": "SECURITY",
        "EmailAddress": "security-contact@example.com",
        "Name": "xiyegen",
        "PhoneNumber": "+81(0X0)XXXX-XXXX",
        "Title": "Security Contact"
    }
}
AWS Account ID: 222222222222
{
    "AlternateContact": {
        "AlternateContactType": "SECURITY",
        "EmailAddress": "security-contact@example.com",
        "Name": "xiyegen",
        "PhoneNumber": "+81(0X0)XXXX-XXXX",
        "Title": "Security Contact"
    }
}
AWS Account ID: 333333333333
{
    "AlternateContact": {
        "AlternateContactType": "SECURITY",
        "EmailAddress": "security-contact@example.com",
        "Name": "xiyegen",
        "PhoneNumber": "+81(0X0)XXXX-XXXX",
        "Title": "Security Contact"
    }
}
(省略)

同一の代替の連絡先がすべてのアカウントに登録できていることを確認できました。

参考

2021/09/30 - AWS Account - 3 new api methods
Programmatically managing alternate contacts on member accounts with AWS Organizations