コンテンツにスキップ

S3 バケット

本記事は構成中です。検証手順は確定していますが、出力例は検証完了後に追記予定です。
検証日: 未実施 / リージョン: ap-northeast-1

概要

IAM Access Analyzer が S3 バケットの外部アクセスをどのように検出するかを検証する。

S3 バケットは IAM Access Analyzer の対応リソースの中で最も馴染みがあり、デフォルト保護(Block Public Access)、予防コントロール(RCP)、検出(IAM Access Analyzer)の 3 レイヤーすべてが揃っているリソースである。本記事では、各レイヤーの関係を検証を通じて明らかにする。

S3 バケットの外部アクセス制御レイヤー

レイヤーS3 バケットの状況
デフォルト保護Block Public Access(2023 年 4 月以降、新規バケットでデフォルト有効)
予防(RCP)CT.S3.PV.4(組織外プリンシパルによるアクセスを拒否)✅
予防(SCP)カスタム SCP 不要(RCP でカバー)
検出IAM Access Analyzer(パブリック + クロスアカウント)✅

検証環境

検証環境の構成図

本記事のコマンドは、--profile 指定がない場合は Workload アカウントで実行する。IAM Access Analyzer の finding 確認は Audit アカウントで実行する。

検証の流れ

    flowchart LR
    A[1. 事前準備] --> B[2. パブリックアクセス<br>検出]
    B --> C[3. クロスアカウント<br>アクセス検出]
    C --> D[4. Security Hub<br>連携確認]
    D --> E[5. アーカイブと<br>Security Hub]
    E --> F[6. BPA 有効時の<br>finding 変化]
    F --> G[7. 予防コントロール<br>との連動]
    G --> H[8. S3 ディレクトリ<br>バケット]
    H --> I[9. クリーンアップ]
  

結果

(検証完了後に記載予定)

1. 事前準備

テスト用の S3 バケットを作成する。

aws s3api create-bucket \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --create-bucket-configuration LocationConstraint=ap-northeast-1

パブリックアクセスの検出を検証するため、Block Public Access を無効化する。

Block Public Access の無効化は検証目的のみで行う。検証完了後にステップ 6 で再有効化し、ステップ 9 でバケットを削除する。
aws s3api put-public-access-block \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --public-access-block-configuration \
    "BlockPublicAcls=false,IgnorePublicAcls=false,BlockPublicPolicy=false,RestrictPublicBuckets=false"
(出力なし)

Block Public Access が無効化されたことを確認する。

aws s3api get-public-access-block \
  --bucket aa-s3-test-<Workload アカウント ID>

2. パブリックアクセスの検出

バケットポリシーに Principal: "*" を設定し、パブリックアクセスを許可する。

aws s3api put-bucket-policy \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowPublicRead",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>/*"
      }
    ]
  }'
(出力なし)
IAM Access Analyzer はポリシー変更後、最大 30 分で finding を生成する。

finding が生成されたことを確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,resourceType:resourceType,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

finding の詳細を確認する。パブリックアクセスの場合、isPublictrue であることを確認する。

aws accessanalyzer get-finding-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --id <パブリックアクセス finding ID> \
  --region ap-northeast-1 \
  --profile Audit

3. クロスアカウントアクセスの検出

バケットポリシーに組織外アカウントへの許可を追加する。

aws s3api put-bucket-policy \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowPublicRead",
        "Effect": "Allow",
        "Principal": "*",
        "Action": "s3:GetObject",
        "Resource": "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>/*"
      },
      {
        "Sid": "AllowCrossAccountAccess",
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:root"},
        "Action": ["s3:GetObject", "s3:PutObject"],
        "Resource": "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>/*"
      }
    ]
  }'
(出力なし)

finding を確認する。パブリックアクセスとクロスアカウントアクセスで 2 件の finding が別々に生成される ことを確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,resourceType:resourceType,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

クロスアカウントアクセスの finding 詳細を確認する。isPublicfalse であること、principal に組織外アカウント ID が特定されていることを確認する。

aws accessanalyzer get-finding-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --id <クロスアカウントアクセス finding ID> \
  --region ap-northeast-1 \
  --profile Audit

4. Security Hub 連携確認

Security Hub に IAM Access Analyzer の finding が連携されていることを確認する。

aws securityhub get-findings \
  --filters '{
    "ProductName": [{"Value": "IAM Access Analyzer", "Comparison": "EQUALS"}],
    "ResourceId": [{"Value": "aa-s3-test", "Comparison": "CONTAINS"}]
  }' \
  --query 'Findings[].{Title:Title,Severity:Severity.Label,ResourceId:Resources[0].Id,WorkflowStatus:Workflow.Status}' \
  --profile Audit

以下を確認する。

  • パブリックアクセスの finding: Severity が MEDIUM
  • クロスアカウントアクセスの finding: Severity が LOW
  • ProductName が IAM Access Analyzer

5. アーカイブと Security Hub の連動

アーカイブ後の Security Hub

パブリックアクセスの finding をアーカイブする。

aws accessanalyzer update-findings \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --ids '["<パブリックアクセス finding ID>"]' \
  --status ARCHIVED \
  --region ap-northeast-1 \
  --profile Audit
(出力なし)

Security Hub から finding が消えることを確認する。

aws securityhub get-findings \
  --filters '{
    "ProductName": [{"Value": "IAM Access Analyzer", "Comparison": "EQUALS"}],
    "ResourceId": [{"Value": "aa-s3-test", "Comparison": "CONTAINS"}]
  }' \
  --query 'Findings[].{Title:Title,Severity:Severity.Label,WorkflowStatus:Workflow.Status}' \
  --profile Audit

アーカイブした finding が Security Hub から消え、クロスアカウントアクセスの finding のみが残ることを確認する。

ポリシー変更後の再アクティブ化

バケットポリシーを変更(アクションを追加)して、アーカイブした finding が再アクティブ化されるか確認する。

aws s3api put-bucket-policy \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowPublicReadExpanded",
        "Effect": "Allow",
        "Principal": "*",
        "Action": ["s3:GetObject", "s3:ListBucket"],
        "Resource": [
          "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>",
          "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>/*"
        ]
      },
      {
        "Sid": "AllowCrossAccountAccess",
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:root"},
        "Action": ["s3:GetObject", "s3:PutObject"],
        "Resource": "arn:aws:s3:::aa-s3-test-<Workload アカウント ID>/*"
      }
    ]
  }'
(出力なし)

ポリシー変更後、アーカイブされていたパブリックアクセスの finding が再び ACTIVE になるか確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

6. Block Public Access 有効時の finding 変化

Block Public Access を再有効化する。

aws s3api put-public-access-block \
  --bucket aa-s3-test-<Workload アカウント ID> \
  --public-access-block-configuration \
    "BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true"
(出力なし)

以下の 2 点を確認する。

パブリックアクセスの finding

Block Public Access が有効な状態で、パブリックアクセスの finding がどうなるか確認する。Zelkova の到達可能性分析が BPA を考慮して「実際にはアクセスできない」と判定し、finding が RESOLVED になるか、それとも ACTIVE のまま残るか。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status,resourceType:resourceType}' \
  --region ap-northeast-1 \
  --profile Audit

クロスアカウントアクセスの finding

Block Public Access はパブリックアクセスのみをブロックし、クロスアカウントアクセスには影響しない。クロスアカウントアクセスの finding が引き続き ACTIVE であることを確認する。

これは「BPA を有効にしているから安心」という誤解を解く重要な検証である。BPA ではクロスアカウント共有は防げず、IAM Access Analyzer による検出が必要であることを実証する。

7. 予防コントロール(CT.S3.PV.4)との連動

本ステップは CT.S3.PV.4(RCP: 組織外プリンシパルによる S3 アクセスを拒否)が有効な環境で実施する。CT.S3.PV.4 の詳細は CT.S3.PV.4 の検証記事 を参照。

CT.S3.PV.4 が有効な状態で、バケットポリシーに組織外アカウントへの許可が残っている場合でも、IAM Access Analyzer は finding を出す。RCP はアクセスをブロックするが、バケットポリシー自体は変更しないため、IAM Access Analyzer はポリシーベースの分析で引き続き外部アクセスを検出する。

つまり、予防コントロールでブロックしていても、ポリシーの修正が必要であることを IAM Access Analyzer が示してくれる。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

finding が ACTIVE のまま残っていることを確認する。これにより、「検出→予防→検証」サイクルにおいて、IAM Access Analyzer は予防コントロールの有無に関わらずポリシーの問題を指摘し続ける役割を持つことがわかる。

8. S3 ディレクトリバケット

S3 ディレクトリバケットに対する IAM Access Analyzer の検出を確認する。

FSBP の S3 関連コントロール一覧を確認したところ、ディレクトリバケットを対象とするコントロールは S3.25(Lifecycle 設定のチェック)のみであり、外部アクセスをチェックするコントロールは存在しない(2026 年 3 月時点)。IAM Access Analyzer がディレクトリバケットの外部アクセスを検出する唯一の手段となる。

ディレクトリバケットの作成

aws s3api create-bucket \
  --bucket aa-s3-dir-test-<Workload アカウント ID>--apne1-az4--x-s3 \
  --create-bucket-configuration '{
    "Location": {
      "Type": "AvailabilityZone",
      "Name": "apne1-az4"
    },
    "Bucket": {
      "Type": "Directory",
      "DataRedundancy": "SingleAvailabilityZone"
    }
  }'

Security Hub CSPM の確認

通常バケット向けの外部アクセスコントロール(S3.2, S3.3 等)がディレクトリバケットに対して finding を出していないことを確認する。

aws securityhub get-findings \
  --filters '{
    "ResourceId": [{"Value": "aa-s3-dir-test", "Comparison": "CONTAINS"}]
  }' \
  --query 'Findings[].{Title:Title,Severity:Severity.Label,ResourceId:Resources[0].Id}' \
  --profile Audit

外部アクセスに関する finding がないことを確認する。

外部アクセスの設定と IAM Access Analyzer の検出

ディレクトリバケットにバケットポリシーで組織外アカウントへの許可を設定し、IAM Access Analyzer の finding が生成されることを確認する。

aws s3api put-bucket-policy \
  --bucket aa-s3-dir-test-<Workload アカウント ID>--apne1-az4--x-s3 \
  --policy '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Sid": "AllowCrossAccountAccess",
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:root"},
        "Action": "s3express:GetObject",
        "Resource": "arn:aws:s3express:ap-northeast-1:<Workload アカウント ID>:bucket/aa-s3-dir-test-<Workload アカウント ID>--apne1-az4--x-s3/*"
      }
    ]
  }'
(出力なし)

finding を確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resource": {"contains": ["aa-s3-dir-test"]}}' \
  --query 'findings[].{id:id,resource:resource,resourceType:resourceType,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

通常バケットとの finding の違い(リソースタイプが AWS::S3Express::DirectoryBucket であること等)を確認する。

9. クリーンアップ

テスト用リソースを削除する。

S3 ディレクトリバケットの削除

aws s3api delete-bucket \
  --bucket aa-s3-dir-test-<Workload アカウント ID>--apne1-az4--x-s3
(出力なし)

S3 バケットの削除

バケットポリシーを削除する。

aws s3api delete-bucket-policy \
  --bucket aa-s3-test-<Workload アカウント ID>
(出力なし)

バケットを削除する。

aws s3api delete-bucket \
  --bucket aa-s3-test-<Workload アカウント ID>
(出力なし)

finding の確認

リソース削除後、IAM Access Analyzer の finding が自動的に RESOLVED になることを確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"resource": {"contains": ["aa-s3-test"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-1 \
  --profile Audit

Amazonアソシエイトリンク