AWS Security Hub CSPM コントロール 「EC2.182」 を AWS Organizations の宣言型ポリシーで対応してみた

AWS Security Hub CSPM コントロール 「EC2.182」 を AWS Organizations の宣言型ポリシーで対応してみた

2026.01.31

こんにちは!クラウド事業本部のおつまみです。

今回は、AWS Organizations 宣言型ポリシーを活用して、AWS Security Hub CSPM コントロール 「EC2.182」 の是正対応を行ったのでご紹介します。

EC2.182コントロールについては、こちらのブログが分かりやすいのでご参照ください。

https://dev.classmethod.jp/articles/securityhub-fsbp-remediation-ec2-182/

対応手順

ステップ1: 既存EBSスナップショットのパブリック共有状況を確認

まず現状を把握するため、Organizations配下の全アカウントでパブリック共有スナップショットの有無を確認します。

事前準備

こちらのブログを参考に、管理アカウントから全メンバーアカウントを一括操作するためのIAMロール(CrossAccountAdminRole)を作成します。

https://dev.classmethod.jp/articles/aws-cloudformation-stacksets-iam-role-deployment/

スクリプト実行

管理アカウントから以下のスクリプトをCloudShellなどで実行します。

#!/bin/bash
# 全アカウントのパブリック共有EBSスナップショットを確認

# 環境変数から設定を取得(デフォルト値あり)
ROLE_NAME="${ROLE_NAME:-CrossAccountAdminRole}"

# 対象リージョン(必要に応じて変更)
TARGET_REGIONS=(
  "ap-northeast-1"
  "us-east-1"
  "us-east-2"
  "us-west-2"
)

# Organizations配下の全アカウントIDを取得
ACCOUNTS=$(aws organizations list-accounts --query 'Accounts[?Status==`ACTIVE`].Id' --output text)

echo "=== パブリック共有EBSスナップショット確認 ==="
echo "対象ロール: ${ROLE_NAME}"
echo "対象リージョン: ${TARGET_REGIONS[*]}"
echo ""

PUBLIC_SNAPSHOTS_FOUND=0
TOTAL_ACCOUNTS=0
FAILED_ACCOUNTS=0

for ACCOUNT_ID in $ACCOUNTS; do
  echo "アカウント: $ACCOUNT_ID"
  TOTAL_ACCOUNTS=$((TOTAL_ACCOUNTS + 1))

  # AssumeRoleでアカウントにアクセス
  CREDS=$(aws sts assume-role \
    --role-arn "arn:aws:iam::${ACCOUNT_ID}:role/${ROLE_NAME}" \
    --role-session-name "ebs-snapshot-check" \
    --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken]' \
    --output text 2>/dev/null)

  if [ $? -eq 0 ]; then
    export AWS_ACCESS_KEY_ID=$(echo $CREDS | awk '{print $1}')
    export AWS_SECRET_ACCESS_KEY=$(echo $CREDS | awk '{print $2}')
    export AWS_SESSION_TOKEN=$(echo $CREDS | awk '{print $3}')

    ACCOUNT_HAS_PUBLIC=0

    # 対象リージョンで確認
    for REGION in "${TARGET_REGIONS[@]}"; do
      PUBLIC_SNAPSHOTS=$(aws ec2 describe-snapshots \
        --owner-ids self \
        --region $REGION \
        --query 'Snapshots[?CreateVolumePermissions[?Group==`all`]].{SnapshotId:SnapshotId,Description:Description,VolumeId:VolumeId,Encrypted:Encrypted,StartTime:StartTime}' \
        --output json 2>/dev/null)

      if [ $? -eq 0 ] && [ "$PUBLIC_SNAPSHOTS" != "[]" ]; then
        if [ $ACCOUNT_HAS_PUBLIC -eq 0 ]; then
          echo "  [警告] パブリック共有スナップショット検出"
          ACCOUNT_HAS_PUBLIC=1
          PUBLIC_SNAPSHOTS_FOUND=$((PUBLIC_SNAPSHOTS_FOUND + 1))
        fi
        echo "  リージョン: $REGION"
        echo "$PUBLIC_SNAPSHOTS" | jq -r '.[] | "    - スナップショットID: \(.SnapshotId), 暗号化: \(.Encrypted), 作成日時: \(.StartTime)"'
      fi
    done

    if [ $ACCOUNT_HAS_PUBLIC -eq 0 ]; then
      echo "  [OK] パブリック共有スナップショットなし"
    fi

    unset AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN
  else
    echo "  [エラー] アカウント $ACCOUNT_ID へのAssumeRole失敗"
    FAILED_ACCOUNTS=$((FAILED_ACCOUNTS + 1))
  fi

  echo ""
done

echo "=== 確認結果サマリー ==="
echo "確認アカウント数: $TOTAL_ACCOUNTS"
echo "パブリック共有スナップショットあり: $PUBLIC_SNAPSHOTS_FOUND"
echo "AssumeRole失敗: $FAILED_ACCOUNTS"

if [ $PUBLIC_SNAPSHOTS_FOUND -eq 0 ] && [ $FAILED_ACCOUNTS -eq 0 ]; then
  echo ""
  echo "[結論] 全アカウントでパブリック共有スナップショットは検出されませんでした。"
  echo "Block Public Access設定の有効化を進めることができます。"
fi

スクリプト実行方法

# 管理アカウントで実行
bash check-public-ebs-snapshots.sh

実行結果サンプル

パターン1: パブリック共有スナップショットが検出されなかった場合
=== パブリック共有EBSスナップショット確認 ===
対象ロール: CrossAccountAdminRole
対象リージョン: ap-northeast-1 us-east-1 us-east-2 us-west-2

アカウント: 123456789012
  [OK] パブリック共有スナップショットなし

アカウント: 234567890123
  [OK] パブリック共有スナップショットなし

アカウント: 345678901234
  [OK] パブリック共有スナップショットなし

アカウント: 456789012345
  [OK] パブリック共有スナップショットなし

=== 確認結果サマリー ===
確認アカウント数: 4
パブリック共有スナップショットあり: 0
AssumeRole失敗: 0

[結論] 全アカウントでパブリック共有スナップショットは検出されませんでした。
Block Public Access設定の有効化を進めることができます。
パターン2: パブリック共有スナップショットが検出された場合
=== パブリック共有EBSスナップショット確認 ===
対象ロール: CrossAccountAdminRole
対象リージョン: ap-northeast-1 us-east-1 us-east-2 us-west-2

アカウント: 123456789012
  [OK] パブリック共有スナップショットなし

アカウント: 234567890123
  [警告] パブリック共有スナップショット検出
  リージョン: ap-northeast-1
    - スナップショットID: snap-0a1b2c3d4e5f6g7h8, 暗号化: false, 作成日時: 2025-11-15T10:30:45.000Z
    - スナップショットID: snap-1b2c3d4e5f6g7h8i9, 暗号化: true, 作成日時: 2025-12-01T14:22:10.000Z

アカウント: 345678901234
  [OK] パブリック共有スナップショットなし

=== 確認結果サマリー ===
確認アカウント数: 3
パブリック共有スナップショットあり: 1
AssumeRole失敗: 0

注意: パブリック共有スナップショットが検出された場合は、まず該当スナップショットのパブリック共有を解除してから、次のステップに進んでください。

パブリック共有スナップショットが0件であることを確認できたら、次のステップへ進みます。

ステップ2: Organizations EC2宣言型ポリシーで一括ブロック

推奨実装方法: Organizations EC2宣言型ポリシー

Organizations環境で複数のアカウント・複数のリージョンを一括管理する場合、EC2の宣言型ポリシー(Declarative Policies)による設定が推奨されます。
これにより、新規作成されたアカウントにも自動的に設定が適用されます。

設定手順:

  1. AWS Organizations コンソールを開く
  2. 「ポリシー」→「宣言型ポリシー」を選択
  3. 「ポリシーの作成」をクリック
  4. 以下の設定を行います:
    • サービス: EC2
    • ポリシータイプ: EBS Snapshot Block Public Access
    • 設定値: すべてのパブリック共有をブロック

CleanShot 2026-01-31 at 18.22.40@2x

CleanShot 2026-01-31 at 18.14.25@2x

  1. 作成したポリシーを組織のルートまたは対象OUにアタッチします

これで設定完了です。

おまけ:Control Towerコントロールとの併用について

Control Towerをご利用の場合、以下のコントロールを併用することで、ガバナンス統制をさらに強化できます。

コントロール名: Disallow all public sharing of Amazon EBS snapshots

CleanShot 2026-01-31 at 18.17.51@2x

こちらも宣言型ポリシーを使っており機能としては、同じものです。ただし、Control Tower経由で設定することで以下のメリットがあります。

  • 監査ログとコンプライアンスステータスがControl Towerダッシュボードで可視化される
  • ドリフト検出機能により設定変更を継続的に監視できる

検証結果

以下の流れで是正されたことを確認できました。

  1. 全アカウントでパブリック共有スナップショットが0件であることを確認
  2. Organizations EC2宣言型ポリシーを組織ルートに適用
  3. 本番環境に反映
  4. Security Hub EC2.182のステータスがPASSEDに変更されたことを確認

CleanShot 2026-01-31 at 18.28.44@2x

まとめ

今回はSecurity Hub EC2.182への対応を通じて、Organizations EC2宣言型ポリシーの活用方法を解説しました。

この機能により、全アカウント・全リージョンに一括でセキュリティポリシーを適用できるようになります。
AWS Organizationsをお使いの方は今回の方法をぜひ試してみてください。

最後までお読みいただきありがとうございました!
どなたかのお役に立てれば幸いです。

以上、おつまみ(@AWS11077)でした!

参考

この記事をシェアする

FacebookHatena blogX

関連記事