コンテンツにスキップ

IAM ロール

検証日: 2026-04-03 / リージョン: ap-northeast-1

概要

IAM Access Analyzer が IAM ロールの外部アクセスをどのように検出するかを検証する。

IAM ロールはグローバルリソースであり、信頼ポリシーにより外部プリンシパルからの AssumeRole を許可できる。Block Public Access のようなデフォルト保護は存在しない。信頼ポリシーに Principal: {"AWS": "*"} を設定するとパブリックアクセスとして検出され、特定の外部アカウントを設定するとクロスアカウントアクセスとして検出される。

IAM ロールの外部アクセス制御レイヤー

レイヤーIAM ロールの状況
デフォルト保護なし
予防(RCP)CT.STS.PV.1(組織外プリンシパルによる AssumeRole を拒否)
Security Hub CSPM外部アクセスの直接チェックなし
IAM Access Analyzerパブリック + クロスアカウントの到達可能性を分析

結果

  • パブリックアクセスの検出: 信頼ポリシーに Principal: {"AWS": "*"} を設定すると、isPublic: true の finding が生成された。IAM ロールでもパブリックアクセスは検出される
  • クロスアカウントアクセスの検出: 組織外アカウントを信頼ポリシーに設定すると、isPublic: false の finding が生成された。principal に組織外アカウント ID が特定された
  • グローバルリソースの重複検出: IAM ロールはグローバルリソースのため全リージョンで finding が生成されるが、東京以外ではアーカイブルール(ArchiveRule-Iam-Role-Global-Suppress)により自動アーカイブされた
  • 予防コントロール(CT.STS.PV.1)との連動: RCP 有効時は組織外からの AssumeRole がパブリック・クロスアカウントの両方でブロックされた。再スキャン後、resourceControlPolicyRestrictionAPPLICABLE に変わった
  • Principal の制約: create-role および update-assume-role-policy では "Principal": "*" の形式はエラーになり、"Principal": {"AWS": "*"} の形式で設定する必要がある

検証環境

検証環境の構成図

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

検証の流れ

    flowchart LR
    A[1. 既存 finding の<br>確認] --> B[2. テスト用ロール<br>作成]
    B --> C[3. パブリックアクセス<br>検出の確認]
    C --> D[4. クロスアカウント<br>アクセス検出]
    D --> E[5. 予防コントロール<br>との連動]
    E --> F[6. クリーンアップ]
  

1. 既存 finding の確認

テスト用ロールを作成する前に、既存の IAM ロール finding を確認する。GitHub Actions OIDC 用ロールが検出されていることを確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"status": {"eq": ["ACTIVE"]}, "resourceType": {"eq": ["AWS::IAM::Role"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-1 \
  --profile Audit
[
    {
        "id": "<GitHub Actions ロール finding ID>",
        "resource": "arn:aws:iam::<Workload アカウント ID>:role/<GitHub Actions OIDC 用ロール名>",
        "status": "ACTIVE"
    }
]

既存 finding の詳細を確認する。

aws accessanalyzer get-finding-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --id <GitHub Actions ロール finding ID> \
  --region ap-northeast-1 \
  --profile Audit
{
    "findingDetails": [
        {
            "externalAccessDetails": {
                "action": ["sts:AssumeRoleWithWebIdentity"],
                "condition": {},
                "isPublic": false,
                "principal": {"Federated": "arn:aws:iam::<Workload アカウント ID>:oidc-provider/token.actions.githubusercontent.com"},
                "resourceControlPolicyRestriction": "NOT_APPLICABLE"
            }
        }
    ],
    "resource": "arn:aws:iam::<Workload アカウント ID>:role/<GitHub Actions OIDC 用ロール名>",
    "status": "ACTIVE",
    "resourceType": "AWS::IAM::Role",
    "findingType": "ExternalAccess",
    "resourceOwnerAccount": "<Workload アカウント ID>",
    "id": "<GitHub Actions ロール finding ID>"
}

以下を確認する。

  • isPublicfalse(特定のプリンシパルへの信頼のため)
  • principal に OIDC プロバイダーの ARN が特定されている
  • actionsts:AssumeRoleWithWebIdentity

2. テスト用ロールの作成

組織外アカウントへの AssumeRole を許可するロールを作成する。検証目的のみで行い、ステップ 6 で削除する。

2 つのテスト用ロールを作成する。テスト用ロールにはアクセス許可ポリシーをアタッチしない。信頼ポリシーのみで IAM Access Analyzer の検出対象となる。AssumeRole しても何も操作できない状態であり、検証として安全である。

パブリックアクセス検証用ロール

信頼ポリシーに Principal: {"AWS": "*"} を設定する。まず自アカウントを信頼する形で作成し、その後 update-assume-role-policy で変更する。

create-role および update-assume-role-policy では "Principal": "*" の形式はエラーになる。"Principal": {"AWS": "*"} の形式であれば設定できる。公式ドキュメントでは両者は同等(equivalent)と記載されているが、IAM ロールの信頼ポリシーでは前者が受け付けられない。
aws iam create-role \
  --role-name iaa-iam-role-public-test \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<Workload アカウント ID>:root"},
        "Action": "sts:AssumeRole"
      }
    ]
  }'
{
    "Role": {
        "RoleName": "iaa-iam-role-public-test",
        "Arn": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test"
    }
}
aws iam update-assume-role-policy \
  --role-name iaa-iam-role-public-test \
  --policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {"AWS": "*"},
        "Action": "sts:AssumeRole"
      }
    ]
  }'
(出力なし)

クロスアカウントアクセス検証用ロール

信頼ポリシーに組織外アカウントを設定する。

aws iam create-role \
  --role-name iaa-iam-role-crossaccount-test \
  --assume-role-policy-document '{
    "Version": "2012-10-17",
    "Statement": [
      {
        "Effect": "Allow",
        "Principal": {"AWS": "arn:aws:iam::<組織外アカウント ID>:root"},
        "Action": "sts:AssumeRole"
      }
    ]
  }'
{
    "Role": {
        "RoleName": "iaa-iam-role-crossaccount-test",
        "Arn": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test"
    }
}

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

ポリシー変更後、IAM Access Analyzer が finding を生成・更新するまで最大 30 分かかる場合がある。

パブリックアクセス検証用ロール(Principal: {"AWS": "*"})の finding を確認する。Principal: {"AWS": "*"} は全 AWS プリンシパルに AssumeRole を許可する設定であり、IAM Access Analyzer がパブリックアクセス(isPublic: true)として検出するかを確認する。

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": ["iaa-iam-role-public-test"]}}' \
  --query 'findings[].{id:id,resource:resource,resourceType:resourceType,status:status}' \
  --region ap-northeast-1 \
  --profile Audit
[
    {
        "id": "<パブリックロール finding ID>",
        "resource": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test",
        "resourceType": "AWS::IAM::Role",
        "status": "ACTIVE"
    }
]

finding の詳細を確認する。

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
{
    "findingDetails": [
        {
            "externalAccessDetails": {
                "action": ["sts:AssumeRole"],
                "condition": {},
                "isPublic": true,
                "principal": {"AWS": "*"},
                "resourceControlPolicyRestriction": "NOT_APPLICABLE"
            }
        }
    ],
    "resource": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test",
    "status": "ACTIVE",
    "resourceType": "AWS::IAM::Role",
    "findingType": "ExternalAccess",
    "resourceOwnerAccount": "<Workload アカウント ID>",
    "id": "<パブリックロール finding ID>"
}

以下を確認する。

  • isPublictruePrincipal: {"AWS": "*"} はパブリックアクセスとして検出される)
  • principal{"AWS": "*"}
  • actionsts:AssumeRole

組織外アカウントからの実際のアクセス確認

組織外アカウントからパブリックロールへの AssumeRole が成功することを確認する。

aws sts assume-role \
  --role-arn arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test \
  --role-session-name test-session \
  --profile <組織外プロファイル> \
  --region ap-northeast-1
{
    "Credentials": { "...": "..." },
    "AssumedRoleUser": {
        "Arn": "arn:aws:sts::<Workload アカウント ID>:assumed-role/iaa-iam-role-public-test/test-session"
    }
}

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

クロスアカウントアクセス検証用ロールの 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": ["iaa-iam-role-crossaccount-test"]}}' \
  --query 'findings[].{id:id,resource:resource,resourceType:resourceType,status:status}' \
  --region ap-northeast-1 \
  --profile Audit
[
    {
        "id": "<クロスアカウントロール finding ID>",
        "resource": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test",
        "resourceType": "AWS::IAM::Role",
        "status": "ACTIVE"
    }
]

finding の詳細を確認する。

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
{
    "findingDetails": [
        {
            "externalAccessDetails": {
                "action": ["sts:AssumeRole"],
                "condition": {},
                "isPublic": false,
                "principal": {"AWS": "<組織外アカウント ID>"},
                "resourceControlPolicyRestriction": "NOT_APPLICABLE"
            }
        }
    ],
    "resource": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test",
    "status": "ACTIVE",
    "resourceType": "AWS::IAM::Role",
    "findingType": "ExternalAccess",
    "resourceOwnerAccount": "<Workload アカウント ID>",
    "id": "<クロスアカウントロール finding ID>"
}

以下を確認する。

  • isPublicfalse
  • principal に組織外アカウント ID が特定されている
  • actionsts:AssumeRole
  • resourceControlPolicyRestrictionNOT_APPLICABLE(CT.STS.PV.1 無効時)

東京以外のリージョンでの確認

IAM ロールはグローバルリソースのため、東京以外のリージョンでも finding が生成される。ただし、アーカイブルール(ArchiveRule-Iam-Role-Global-Suppress)により自動アーカイブされていることを確認する。

aws accessanalyzer list-findings-v2 \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-2:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --filter '{"resource": {"contains": ["iaa-iam-role-crossaccount-test"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-2 \
  --profile Audit
[
    {
        "id": "<ソウルリージョン finding ID>",
        "resource": "arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test",
        "status": "ARCHIVED"
    }
]

5. 予防コントロール(CT.STS.PV.1)との連動

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

CT.STS.PV.1 の有効化確認

CT.STS.PV.1 が有効であることを確認する。

aws controltower list-enabled-controls \
  --target-identifier <対象 OU ARN> \
  --query "enabledControls[?controlIdentifier=='arn:aws:controlcatalog:::control/aqnqv7jjgi2dtl6r1v12xglio'].{controlIdentifier:controlIdentifier,statusSummary:statusSummary}" \
  --profile Master
[]

無効の場合は有効化する。

aws controltower enable-control \
  --control-identifier arn:aws:controlcatalog:::control/aqnqv7jjgi2dtl6r1v12xglio \
  --target-identifier <対象 OU ARN> \
  --profile Master
{
    "arn": "<有効化コントロール ARN>",
    "operationIdentifier": "<オペレーション ID>"
}

組織外アカウントからの AssumeRole 確認

CT.STS.PV.1 が有効な状態で、組織外アカウントからクロスアカウントテスト用ロールへの AssumeRole を試み、RCP によりブロックされることを確認する。

aws sts assume-role \
  --role-arn arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test \
  --role-session-name test-session \
  --profile <組織外プロファイル> \
  --region ap-northeast-1
An error occurred (AccessDenied) when calling the AssumeRole operation: ...

パブリックロールへの AssumeRole も同様にブロックされることを確認する。

aws sts assume-role \
  --role-arn arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test \
  --role-session-name test-session \
  --profile <組織外プロファイル> \
  --region ap-northeast-1
An error occurred (AccessDenied) when calling the AssumeRole operation: ...

resourceControlPolicyRestriction の確認

リソースの再スキャンを実行して、RCP の反映を確認する。再スキャンにより旧 finding は RESOLVED になり、新しい finding ID で再生成される。

aws accessanalyzer start-resource-scan \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --resource-arn arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-crossaccount-test \
  --resource-owner-account <Workload アカウント ID> \
  --region ap-northeast-1 \
  --profile Audit
(出力なし)

パブリックロールも再スキャンする。

aws accessanalyzer start-resource-scan \
  --analyzer-arn arn:aws:access-analyzer:ap-northeast-1:<Audit アカウント ID>:analyzer/org-access-analyzer \
  --resource-arn arn:aws:iam::<Workload アカウント ID>:role/iaa-iam-role-public-test \
  --resource-owner-account <Workload アカウント ID> \
  --region ap-northeast-1 \
  --profile Audit
(出力なし)

再スキャン後の 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": ["iaa-iam-role-crossaccount-test"]}}' \
  --query 'findings[].{id:id,status:status}' \
  --region ap-northeast-1 \
  --profile Audit
[
    {
        "id": "<新クロスアカウントロール finding ID>",
        "status": "ACTIVE"
    }
]

finding 詳細を確認し、resourceControlPolicyRestrictionAPPLICABLE に変わっていることを確認する。

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
{
    "findingDetails": [
        {
            "externalAccessDetails": {
                "action": ["sts:AssumeRole"],
                "isPublic": false,
                "principal": {"AWS": "<組織外アカウント ID>"},
                "resourceControlPolicyRestriction": "APPLICABLE"
            }
        }
    ],
    "status": "ACTIVE",
    "id": "<新クロスアカウントロール finding 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
{
    "findingDetails": [
        {
            "externalAccessDetails": {
                "action": ["sts:AssumeRole"],
                "isPublic": true,
                "principal": {"AWS": "*"},
                "resourceControlPolicyRestriction": "APPLICABLE"
            }
        }
    ],
    "status": "ACTIVE",
    "id": "<新パブリックロール finding ID>"
}

6. クリーンアップ

CT.STS.PV.1 の無効化

ステップ 5 で CT.STS.PV.1 を有効化した場合のみ無効化する。元々有効な環境ではそのまま有効にしておくこと。
aws controltower disable-control \
  --control-identifier arn:aws:controlcatalog:::control/aqnqv7jjgi2dtl6r1v12xglio \
  --target-identifier <対象 OU ARN> \
  --profile Master
{
    "operationIdentifier": "<オペレーション ID>"
}

テスト用ロールの削除

aws iam delete-role \
  --role-name iaa-iam-role-public-test
(出力なし)
aws iam delete-role \
  --role-name iaa-iam-role-crossaccount-test
(出力なし)

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": ["iaa-iam-role"]}}' \
  --query 'findings[].{id:id,resource:resource,status:status}' \
  --region ap-northeast-1 \
  --profile Audit
[]

Amazonアソシエイトリンク