GCP IAM権限の監査
使用すべき状況
- GCP組織またはプロジェクトのIAM設定のセキュリティ評価を実施する場合
- 過剰な権限や未使用のアクセス権を持つサービスアカウントを特定する場合
- コンプライアンス要件によりアクセス制御とロール割り当てのレビューが必須となっている場合
- IAM設定ミスによる横断的な権限昇格の可能性を調査する場合
- 侵害された認証情報の影響範囲を権限のスコープダウンによって低減する場合
使用すべきでない状況: VPCファイアウォールルールの監査(ネットワークセキュリティツールを使用)、GKE RBACの監査(Kubernetes固有のRBACツールを使用)、IAMアクションに対するリアルタイムの脅威検出(SCC Event Threat Detectionを使用)。
前提条件
- GCP組織またはプロジェクトに対して
roles/iam.securityReviewerとroles/cloudAsset.viewerのロールが必要 - 適切な権限で認証されたgcloud CLI
- Cloud Asset APIの有効化 (
gcloud services enable cloudasset.googleapis.com) - IAM Recommender APIの有効化 (
gcloud services enable recommender.googleapis.com) - Policy Analyzer APIの有効化 (
gcloud services enable policyanalyzer.googleapis.com)
ワークフロー
ステップ1: 組織全体のIAMバインディングを列挙する
組織、フォルダ、プロジェクトレベルのすべてのIAMバインディングをリストアップし、アクセス全体像を把握します。
# 組織レベルのIAMバインディング
gcloud organizations get-iam-policy ORG_ID \
--format=json > org-iam-policy.json
# 組織全体のIAMポリシーを検索
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--format="table(resource, policy.bindings.role, policy.bindings.members)" \
--limit=500
# Ownerロールを持つユーザーとサービスアカウントを検索
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:roles/owner" \
--format="table(resource, policy.bindings.members)"
# プリミティブロール(Owner、Editor、Viewer)を使用しているバインディングを検索
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:roles/owner OR policy:roles/editor" \
--format=json | python3 -c "
import json, sys
data = json.load(sys.stdin)
for result in data:
resource = result.get('resource', '')
for binding in result.get('policy', {}).get('bindings', []):
role = binding.get('role', '')
if role in ['roles/owner', 'roles/editor']:
for member in binding.get('members', []):
print(f'{resource} | {role} | {member}')
"
ステップ2: サービスアカウントとそのキーを監査する
過剰な権限、ユーザー管理キー、未使用のアカウントを持つサービスアカウントを特定します。
# プロジェクト内のすべてのサービスアカウントをリスト表示
gcloud iam service-accounts list \
--project=PROJECT_ID \
--format="table(email, displayName, disabled)"
# ユーザー管理キー(最小限にすべき)を確認
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
keys=$(gcloud iam service-accounts keys list \
--iam-account="$sa" \
--managed-by=user \
--format="table(name.basename(),validAfterTime,validBeforeTime)")
if [ -n "$keys" ]; then
echo "=== $sa ==="
echo "$keys"
fi
done
# すべてのプロジェクトで管理ロールを持つサービスアカウントを検索
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy.bindings.members:serviceAccount AND (policy:roles/owner OR policy:roles/editor OR policy:admin)" \
--format="table(resource, policy.bindings.role, policy.bindings.members)"
# サービスアカウントのIAMポリシー(誰が権限借用できるか)を確認
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
echo "=== $sa ==="
gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null
done
ステップ3: IAM Recommenderを使用して過剰な権限を特定する
GCPのIAM Recommenderを活用し、実際の使用よりも多くのアクセス許可を与えているロールを見つけます。
# プロジェクトのIAMロール推奨事項をリスト表示
gcloud recommender recommendations list \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--format="table(name, description, priority, stateInfo.state)"
# 詳細な推奨事項を取得
gcloud recommender recommendations describe RECOMMENDATION_ID \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--format=json
# IAM使用状況に関するインサイトをリスト表示
gcloud recommender insights list \
--project=PROJECT_ID \
--insight-type=google.iam.policy.Insight \
--location=global \
--format="table(name, description, severity, category)"
# 推奨事項を適用(確認後)
gcloud recommender recommendations mark-claimed RECOMMENDATION_ID \
--project=PROJECT_ID \
--recommender=google.iam.policy.Recommender \
--location=global \
--etag=ETAG
ステップ4: Policy Analyzerで効果的な権限を分析する
Policy Analyzerを使用して、特定のプリンシパルやリソースに対する効果的なアクセス権を判断します。
# 特定リソースへのアクセス権を持つユーザーを確認
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--full-resource-name="//storage.googleapis.com/projects/_/buckets/sensitive-data-bucket" \
--format="table(identityList.identities, accessControlLists.accesses.role)"
# 特定ユーザーがアクセスできるリソースを確認
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--identity="user:[email protected]" \
--format="table(accessControlLists.resources.fullResourceName, accessControlLists.accesses.role)"
# 特定アクションを実行できるユーザーを確認
gcloud asset analyze-iam-policy \
--organization=ORG_ID \
--full-resource-name="//cloudresourcemanager.googleapis.com/projects/PROJECT_ID" \
--permissions="iam.serviceAccounts.actAs,iam.serviceAccountKeys.create" \
--format="table(identityList.identities, accessControlLists.accesses.permission)"
# allUsersまたはallAuthenticatedUsersアクセスを持つプリンシパルを検索
gcloud asset search-all-iam-policies \
--scope=organizations/ORG_ID \
--query="policy:allUsers OR policy:allAuthenticatedUsers" \
--format="table(resource, policy.bindings.role, policy.bindings.members)"
ステップ5: ドメイン全体の委任と権限借用リスクを確認する
ドメイン全体の委任機能と権限借用機能を持つサービスアカウントを特定します。
# ドメイン全体の委任が有効なサービスアカウントを確認
# (委任アカウントのリスト表示にはAdmin SDKアクセスが必要)
gcloud iam service-accounts list --project=PROJECT_ID --format=json | python3 -c "
import json, sys
accounts = json.load(sys.stdin)
for sa in accounts:
email = sa.get('email', '')
# SAにドメイン全体の委任が有効かどうかを確認
# これにはAdmin SDK APIアクセスが必要
print(f'SA: {email} - admin.google.comで委任ステータスを確認してください')
"
# 他のIDが権限借用できるサービスアカウントを検索
for sa in $(gcloud iam service-accounts list --project=PROJECT_ID --format="value(email)"); do
policy=$(gcloud iam service-accounts get-iam-policy "$sa" --format=json 2>/dev/null)
if echo "$policy" | python3 -c "
import json, sys
p = json.load(sys.stdin)
for b in p.get('bindings', []):
if b['role'] in ['roles/iam.serviceAccountTokenCreator', 'roles/iam.serviceAccountUser']:
print(f' {b[\"role\"]}: {b[\"members\"]}')
" 2>/dev/null; then
echo "=== 権限借用リスク: $sa ==="
fi
done
ステップ6: 監査レポートを生成し是正措置を適用する
調査結果をまとめ、推奨される権限削減を実施します。
# プリミティブロールを削除し、定義済みロールに置き換え
gcloud projects remove-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/editor"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/compute.viewer"
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:[email protected]" \
--role="roles/storage.objectViewer"
# 未使用のサービスアカウントキーを削除
gcloud iam service-accounts keys delete KEY_ID \
--iam-account=SA_EMAIL
# 未使用のサービスアカウントを無効化
gcloud iam service-accounts disable SA_EMAIL --project=PROJECT_ID
主要な概念
| 用語 | 定義 |
|---|---|
| プリミティブロール | すべてのサービスにわたって広範な権限を付与する従来のGCPロール(Owner、Editor、Viewer)。本番環境では推奨されない |
| 定義済みロール | GCP管理の、特定のサービスとアクションにスコープされたロール。プリミティブロールよりも詳細なアクセス制御を提供 |
| IAM Recommender | 実際の権限使用状況を分析し、最小権限を実現するためのロール削減を提案するGCPのMLベースサービス |
| Policy Analyzer | 組織階層全体で効果的なIAMアクセスを分析し、「誰が何にアクセスできるか」という問いに答えるツール |
| サービスアカウントキー | サービスアカウント認証のためのユーザー管理資格情報。キーはエクスポート可能で自動期限切れにならないため、セキュリティリスクとなる |
| ドメイン全体の委任 | サービスアカウントがGoogle Workspaceドメイン内の任意のユーザーを権限借用できるようにする設定。重大な権限昇格リスクとなる |
ツールとシステム
- gcloud CLI: GCP IAMポリシー、サービスアカウント、ロールバインディングのクエリと管理を行う主要ツール
- IAM Recommender: 実際の使用状況に基づき過剰な権限を削減するためのMLベースの推奨エンジン
- Policy Analyzer: 誰が何にアクセスできるかを理解するための組織全体の効果的なアクセス分析ツール
- Cloud Asset Inventory: プロジェクト間でのIAMポリシーとリソースメタデータの検索
- ScoutSuite: ロール割り当てとサービスアカウントに関するGCP IAM固有のチェックを備えたマルチクラウド監査ツール
一般的なシナリオ
シナリオ: GCP組織全体でのプリミティブロール使用の削減
背景: 監査により、組織全体のIAMバインディングの60%がプリミティブロール(Owner/Editor)を使用していることが判明。セキュリティチームは、開発者のワークフローを妨げずに定義済みロールへの移行を進める必要がある。
アプローチ:
gcloud asset search-all-iam-policiesを実行し、すべてのプリミティブロールバインディングを棚卸し- IAM Recommenderを使用して、MLベースの置き換え候補となる定義済みロールの提案を取得
- 各バインディングについてPolicy Analyzerを使用し、プリンシパルが実際にアクセスしているものを理解
- マッピングドキュメントを作成: プリミティブロール -> 必要な特定の定義済みロール
- プリミティブロールと並行して定義済みロールをテスト期間適用
- Cloud Audit Logsを使用してアクセス拒否エラーを監視
- 2週間問題がないことを確認した後、プリミティブロールを削除
落とし穴: プリミティブロールにはすべてのGCPサービスにわたる権限が含まれているため、置き換えには複数の定義済みロールが必要。観測期間中にすべてのユースケースを捕捉できない場合、Recommenderは過度に制限的なロールを提案する可能性がある。必要な権限セットに完全に一致する定義済みロールがない場合は、カスタムロールでギャップを埋めることができる。
出力形式
GCP IAM権限監査レポート
===================================
組織: acme-org (ORG_ID: 123456789)
監査対象プロジェクト: 25
監査日: 2026-02-23
IAMバインディングサマリー:
バインディング総数: 342
プリミティブロール使用: 205 (60%)
定義済みロール使用: 112 (33%)
カスタムロール使用: 25 (7%)
重大な発見:
[IAM-001] Ownerロールのサービスアカウント
SA: [email protected]
ロール: roles/owner (プロジェクト prod-project)
ユーザー管理キー: 3 (最古: 14ヶ月前)
是正措置: 特定の定義済みロールに置き換え、古いキーを削除
[IAM-002] allAuthenticatedUsers バインディング
リソース: gs://public-data-bucket
ロール: roles/storage.objectViewer
リスク: すべてのGoogleアカウント所有者がバケットの内容を読み取れる
是正措置: 特定のユーザーグループまたはサービスアカウントに制限
サービスアカウント健全性:
サービスアカウント総数: 67
ユーザー管理キーを持つもの: 23
90日以上経過したキー: 18
未使用アカウント(90日以上): 12
ドメイン全体の委任を持つもの: 2
Recommender提案:
推奨事項総数: 45
優先度HIGH: 12
削減見込み権限数: 2,847 個別権限