AWS Security Hubのスクリプトでの招待と承認について（初心者向け）

最近、Security Hubの招待と承認を行ったので、備忘録として残したいと思います。

本記事では、AWS Security Hubの概要と、複数アカウントを効率的に管理するための招待・承認プロセスについて詳しく解説します。さらに、このプロセスを自動化するためのAWS CLIコマンドとシェルスクリプトの実装方法も紹介します。

## 1. AWS Security Hubとは

AWS Security Hubは、AWSが提供するセキュリティ管理サービスです。
このサービスを使用することで、組織内の複数のAWSアカウントとワークロードのセキュリティ状態を一元的に把握し、管理が可能になります。Security Hubは、AWSのセキュリティベストプラクティスや業界標準に基づいてセキュリティチェックを実行し、潜在的な脆弱性や設定ミスを特定します。また、他のAWSセキュリティサービスやサードパーティ製品からの情報を集約し、包括的なセキュリティ概要を提供します。

## 2. Security Hubの基本概念

Security Hubを効果的に活用するには、いくつかの基本概念を理解することが重要です。特に重要な概念が「管理アカウント」と「メンバーアカウント」です。

管理アカウントは、Security Hubの中心的な役割を果たします。このアカウントは、他のAWSアカウント（メンバーアカウント）を招待し、それらのセキュリティ情報を集約する権限を持ちます。管理アカウントのユーザーは、すべてのメンバーアカウントのセキュリティ状態を一元的に監視し、必要に応じて対策を講じることができます。

一方、メンバーアカウントは、管理アカウントからの招待を受け入れることで、自身のセキュリティデータを共有します。これにより、組織全体のセキュリティ状況を包括的に把握することが可能になります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3812002/cd3528db-b8d2-b199-6f99-5569496c761e.png)


ただし、Security Hubの設定には一つ重要な注意点があります。それは、設定がリージョンごとに独立しています。つまり、AWSの各リージョンで個別に招待と承認のプロセスを実行する必要があります。この特性は、同時に、リージョンごとに異なるセキュリティ要件を設定できるという柔軟性も提供しています。

## 3. Security Hubの招待プロセス（管理アカウント側）

実際のSecurity Hub招待プロセスについて、管理アカウント側の手順。
このプロセスは主に3つのステップで構成されています：Security Hubの有効化、メンバーアカウントの追加、そして招待の送信です。

まず、Security Hubを有効化する必要があります。これは、まだSecurity Hubを使用したことがない場合に必要なステップです。AWS Management Consoleから手動で行うこともできますが、AWS CLIを使用すると、次のコマンドで簡単に有効化できます：

```bash
aws securityhub enable-security-hub --region REGION
```

次に、メンバーアカウントを追加します。これは、セキュリティデータを共有してほしいAWSアカウントを指定するステップです。

AWS CLIを使用する場合、以下のコマンドを実行

```bash
aws securityhub create-members --account-details '[{"AccountId":"ACCOUNT_ID","Email":"EMAIL@EXAMPLE.COM"}]' --region REGION
```

最後に、追加したメンバーアカウントに招待を送信します。この招待は、メンバーアカウントがSecurity Hubに参加するための正式な要請となります。招待の送信には次のコマンドを使用します：

```bash
aws securityhub invite-members --account-ids ACCOUNT_ID --region REGION
```

これらの手順を各リージョンで繰り返す必要がありますが、多数のアカウントや複数のリージョンを扱う場合、この作業は非常に時間がかかる可能性があります。そこで、このプロセスを自動化するためのシェルスクリプトを紹介します。

以下は、複数のリージョンで複数のアカウントに招待を送信するためのバッシュスクリプトです。

```bash
#!/bin/bash

# 招待したいアカウントIDとメールアドレスを設定
MEMBER_ACCOUNT_IDS=(
    "123456789012"
    "234567890123"
)

MEMBER_EMAILS=(
    "account1@example.com"
    "account2@example.com"
)

# AWSの主要リージョンを設定
REGIONS=(
    "us-east-1" "us-east-2" "us-west-1" "us-west-2"
    "eu-west-1" "eu-west-2" "eu-central-1"
    "ap-northeast-1" "ap-southeast-1" "ap-southeast-2"
    "sa-east-1"
)

# 現在の（管理）アカウントIDを取得
ADMIN_ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)

# 失敗したリージョンを記録する配列
FAILED_REGIONS=()

# 各リージョンでプロセスを実行
for region in "${REGIONS[@]}"; do
    echo "Processing region: $region"
    
    # Security Hubが有効化されているか確認し、必要に応じて有効化
    if ! aws securityhub get-enabled-standards --region "$region" >/dev/null 2>&1; then
        echo "Enabling SecurityHub in $region..."
        aws securityhub enable-security-hub --region "$region"
    fi

    # メンバーアカウントを追加
    for i in "${!MEMBER_ACCOUNT_IDS[@]}"; do
        aws securityhub create-members \
            --account-details "AccountId=${MEMBER_ACCOUNT_IDS[i]},Email=${MEMBER_EMAILS[i]}" \
            --region "$region"
    done

    # メンバーアカウントを招待
    if ! aws securityhub invite-members \
        --account-ids "${MEMBER_ACCOUNT_IDS[@]}" \
        --region "$region"; then
        FAILED_REGIONS+=("$region")
    fi
done

# 結果の出力
echo "Invitations sent from account $ADMIN_ACCOUNT_ID to ${#MEMBER_ACCOUNT_IDS[@]} accounts in ${#REGIONS[@]} regions."
echo "Success: $((${#REGIONS[@]} - ${#FAILED_REGIONS[@]})) regions. Failed: ${#FAILED_REGIONS[@]} regions."

if [ ${#FAILED_REGIONS[@]} -ne 0 ]; then
    echo "Failed regions: ${FAILED_REGIONS[*]}"
fi
```

このスクリプトは、指定されたリージョンごとにSecurity Hubの有効化を確認し、必要に応じて有効化します。その後、各メンバーアカウントをSecurity Hubに追加し、招待を送信します。最後に、処理結果を出力し、失敗したリージョンがあればそれを報告します。

- スクリプトを使用する際は、MEMBER_ACCOUNT_IDSとMEMBER_EMAILSの配列を実際の値で更新
- スクリプトに実行権限を付与（chmod +x スクリプト名.sh）が必要です。
- このスクリプトを実行するIAMユーザーまたはロールが、必要なSecurity Hubの権限を持っていることを確認することも重要です。

## 4. Security Hubの承認プロセス（メンバーアカウント側）

管理アカウントからの招待が送信されたら、次はメンバーアカウント側で承認プロセスを行う必要があります。この承認プロセスも、管理アカウント側のプロセスと同様に、いくつかのステップで構成されています。

まず、メンバーアカウントでSecurity Hubを有効化する必要があります。これは管理アカウントと同じコマンドで行えます：

```bash
aws securityhub enable-security-hub --region REGION
```

次に、受け取った招待を確認します。これは以下のコマンドで行えます：

```bash
aws securityhub list-invitations --region REGION
```

最後に、確認した招待を承認します。承認には次のコマンドを使用します：

```bash
aws securityhub accept-invitation --master-id MASTER_ACCOUNT_ID --invitation-id INVITATION_ID --region REGION
```

ここでも、多数のリージョンで作業を行う必要がある場合は、自動化スクリプトが役立ちます。以下は、複数のリージョンで招待を承認するためのバッシュスクリプトです：

```bash
#!/bin/bash

# AWSの主要リージョンを設定
REGIONS=(
    "us-east-1" "us-east-2" "us-west-1" "us-west-2"
    "eu-west-1" "eu-west-2" "eu-central-1"
    "ap-northeast-1" "ap-southeast-1" "ap-southeast-2"
    "sa-east-1"
)

# 招待元の管理アカウントID（実際の値に置き換えてください）
MASTER_ACCOUNT_ID="987654321098"

# 承認に失敗したリージョンを記録する配列
FAILED_REGIONS=()

# 各リージョンで招待を承認
for region in "${REGIONS[@]}"; do
    echo "Processing region: $region"
    
    # Security Hubが有効かどうかを確認し、必要に応じて有効化
    if ! aws securityhub get-enabled-standards --region "$region" >/dev/null 2>&1; then
        echo "Enabling SecurityHub in $region..."
        aws securityhub enable-security-hub --region "$region"
    fi

    # 招待IDを取得
    INVITATION_ID=$(aws securityhub list-invitations --region "$region" --query 'Invitations[0].InvitationId' --output text)

    if [ "$INVITATION_ID" != "None" ] && [ -n "$INVITATION_ID" ]; then
        echo "Found invitation: $INVITATION_ID"
        if aws securityhub accept-invitation \
            --master-id "$MASTER_ACCOUNT_ID" \
            --invitation-id "$INVITATION_ID" \
            --region "$region"; then
            echo "Successfully accepted invitation in $region"
        else
            echo "Failed to accept invitation in $region"
            FAILED_REGIONS+=("$region")
        fi
    else
        echo "No invitation found in $region"
        FAILED_REGIONS+=("$region")
    fi
done

# 結果の出力
echo "SecurityHub invitations processed in ${#REGIONS[@]} regions."
echo "Success: $((${#REGIONS[@]} - ${#FAILED_REGIONS[@]})) regions. Failed: ${#FAILED_REGIONS[@]} regions."

if [ ${#FAILED_REGIONS[@]} -ne 0 ]; then
    echo "Failed regions: ${FAILED_REGIONS[*]}"
fi
```

このスクリプトは、指定された各リージョンでSecurity Hubの有効化を確認し、必要に応じて有効化します。その後、各リージョンで受け取った招待を確認し、存在する場合はその招待を承認します。

スクリプトを使用する際は、MASTER_ACCOUNT_IDを実際の管理アカウントのIDで更新し、スクリプトに実行権限を付与することを忘れないでください。また、このスクリプトを実行するIAMユーザーまたはロールが、必要なSecurity Hubの権限を持っていることを確認することも重要です。

## 5. 注意事項
まず、リージョンの考慮が非常に重要です。前述の通り、Security Hubの設定はリージョンごとに独立しています。そのため、組織で使用するすべてのリージョンでプロセスを実行することを強く推奨します。これにより、すべてのリージョンで一貫したセキュリティ管理が可能になります。

次に、適切なIAM権限の設定が不可欠です。管理アカウントとメンバーアカウントの両方で、Security Hub関連の操作に必要な権限が正しく設定されていることを確認してください。

エラーハンドリングも重要な考慮事項です。提供したスクリプトには基本的なエラーハンドリングが含まれていますが、実際の運用ではさらに詳細なエラー処理とログ記録を実装することをお勧めします。

## まとめ
大量のアカウントと大量のリージョンへの設定は手間と時間がかかるので、スクリプトを組んで行うと比較的楽に招待と承認ができました。