なんとなくわかった気になっていた GCP IAM を学びなおす
はじめに
「このサービスアカウントに roles/storage.admin を付与しておいて」
GCPを使っていると、こんなやりとりは日常茶飯事です。言われたとおりにコンソールをポチポチして、なんとなく動くようになった。でも、ふと立ち止まって考えてみると…
- Principal と Member って何が違うの?
- Policy と Binding の関係がよくわからない
- Impersonation って結局何をしているの?
- Workload Identity Federation が便利らしいけど仕組みがわからない
この記事では、GCP IAMの仕組みを基礎から体系的に整理し、「なんとなく」を「しっかり」に変えていきます。
目次
- IAMの全体像
- Principal(プリンシパル)を理解する
- Service Account の二面性
- Role と Permission の関係
- Policy の種類と評価順序
- Binding とは何か
- Resource Hierarchy と継承
- Impersonation を正しく理解する
- Workload Identity Federation の仕組み
- 実践:よくあるユースケースと設定例
- ベストプラクティス
- まとめ
1. IAMの全体像
GCP IAMは、一言でいうと 「誰が、何を、どのリソースに対してできるか」 を制御するシステムです。
┌─────────────────────────────────────────────────────────┐
│ GCP IAM の基本構造 │
├─────────────────────────────────────────────────────────┤
│ │
│ WHO WHAT WHERE │
│ 誰が × 何を × どこに │
│ │
│ Principal Role Resource │
│ (主体) (権限の集合) (対象) │
│ │
│ ・User ・Basic ・Organization │
│ ・Service ・Predefined ・Folder │
│ Account ・Custom ・Project │
│ ・Group ・個別リソース │
│ │
└─────────────────────────────────────────────────────────┘
この3つの要素を Binding(バインディング) で結びつけ、それを Policy(ポリシー) として管理します。
アクセス判定のフロー
Principal がリソースにアクセスしようとすると、IAMは以下の順序で評価を行います。
リクエスト発生
│
▼
┌────────────────────────────────────┐
│ 1. Principal Access Boundary (PAB) │ ← そもそもアクセス資格があるか?
│ アクセス可能なリソース範囲の制限 │
└────────────────────────────────────┘
│ 資格あり
▼
┌────────────────────────────────────┐
│ 2. Deny Policy │ ← 明示的に拒否されていないか?
│ Allow より優先される拒否ルール │
└────────────────────────────────────┘
│ 拒否なし
▼
┌────────────────────────────────────┐
│ 3. Allow Policy │ ← 必要な権限が付与されているか?
│ Role Binding による権限付与 │
└────────────────────────────────────┘
│ 権限あり
▼
✓ アクセス許可
ポイントは Deny が Allow より優先される ということ。どんなに強力な Role を持っていても、Deny Policy で拒否されていればアクセスできません。
2. Principal(プリンシパル)を理解する
Principal は「アクションを実行する主体」です。以前は Member と呼ばれていましたが、現在は Principal という用語が標準になっています(ドキュメントによっては Member も併用)。
Principal の種類
| 種類 | 識別子の形式 | 用途 |
|---|---|---|
| Google Account | user:alice@example.com |
個人ユーザー |
| Service Account | serviceAccount:my-sa@project.iam.gserviceaccount.com |
アプリケーション用ID |
| Google Group | group:developers@example.com |
ユーザーのグループ |
| Google Workspace Domain | domain:example.com |
ドメイン内の全ユーザー |
| allUsers | allUsers |
インターネット上の誰でも(認証不要) |
| allAuthenticatedUsers | allAuthenticatedUsers |
Googleアカウント保持者全員 |
v2 形式の Principal 識別子
Deny Policy や Principal Access Boundary Policy では、より詳細な v2形式 の識別子を使用します。
# ユーザー
principal://goog/subject/alice@example.com
# サービスアカウント
principal://iam.googleapis.com/projects/-/serviceAccounts/my-sa@project.iam.gserviceaccount.com
# グループ
principalSet://goog/group/developers@example.com
# Workload Identity Pool のサブジェクト
principal://iam.googleapis.com/projects/PROJECT_NUMBER/locations/global/workloadIdentityPools/POOL_ID/subject/SUBJECT
principal:// は単一のID、principalSet:// は複数のIDの集合を表します。
3. Service Account の二面性
Service Account(SA)は GCP IAM で最も重要かつ混乱しやすい概念の一つです。なぜなら、SA は 「IDとして」 と 「リソースとして」 の二つの顔を持つからです。
┌─────────────────────────────────────────────────────────────┐
│ Service Account の二面性 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【IDとして使う場合】 【リソースとして使う場合】 │
│ │
│ SA が他のリソースにアクセス 誰が SA を使えるか管理 │
│ │
│ 「SA に Storage Admin を付与」 「User に SA の使用権を付与」│
│ │
│ SA ──────→ Cloud Storage User ──────→ SA │
│ アクセス 利用 │
│ │
└─────────────────────────────────────────────────────────────┘
Service Account の種類
| 種類 | 説明 | 管理責任 |
|---|---|---|
| User-managed SA | ユーザーが明示的に作成 | ユーザー |
| Default SA | 特定サービス有効化時に自動作成 | ユーザー(⚠️過剰権限に注意) |
| Service Agent | Googleが内部用に作成 |
Default SA は便利ですが、過剰な権限(多くの場合 Editor 相当)を持っていることが多いため、本番環境では専用の SA を作成することを強く推奨します。
4. Role と Permission の関係
Permission は「何ができるか」を表す最小単位で、以下の形式で定義されています。
<service>.<resource>.<verb>
例:
compute.instances.create # VMインスタンスを作成
storage.objects.get # オブジェクトを読み取り
iam.roles.create # カスタムロールを作成
Permission を直接 Principal に付与することはできません。代わりに、Permission をまとめた Role を付与します。
Role の種類
┌─────────────────────────────────────────────────────────────┐
│ Role の種類 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. Basic Roles(基本ロール) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ roles/owner → 全権限 + IAM管理 + 課金管理 │ │
│ │ roles/editor → 読み書き(IAM変更不可) │ │
│ │ roles/viewer → 読み取りのみ │ │
│ └─────────────────────────────────────────────────┘ │
│ ⚠️ 非常に広範な権限。本番環境では使用を避ける │
│ │
│ 2. Predefined Roles(事前定義ロール) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ Google が作成・維持 │ │
│ │ サービスごとに細分化された権限 │ │
│ │ 例: roles/storage.objectViewer │ │
│ │ roles/compute.networkAdmin │ │
│ └─────────────────────────────────────────────────┘ │
│ ✓ 最小権限の原則に沿った運用が可能 │
│ │
│ 3. Custom Roles(カスタムロール) │
│ ┌─────────────────────────────────────────────────┐ │
│ │ ユーザーが Permission を選んで独自に定義 │ │
│ │ 組織またはプロジェクトレベルで作成 │ │
│ └─────────────────────────────────────────────────┘ │
│ ✓ 最も細かい制御が可能 │
│ │
└─────────────────────────────────────────────────────────────┘
よく使う Predefined Roles
| Role | 説明 |
|---|---|
roles/iam.serviceAccountUser |
SA をリソースにアタッチできる |
roles/iam.serviceAccountTokenCreator |
SA の短期認証情報を生成(Impersonation に必要) |
roles/iam.workloadIdentityUser |
GKE Workload から SA を使用 |
roles/iam.securityAdmin |
IAM ポリシー全般の管理 |
5. Policy の種類と評価順序
GCP IAM には3種類の Policy があります。
5.1 Allow Policy(許可ポリシー)
最も基本的なポリシー。Principal に Role を付与します。
# Allow Policy の構造
bindings:
- members:
- user:alice@example.com
- serviceAccount:deploy@project.iam.gserviceaccount.com
role: roles/storage.objectViewer
- members:
- group:admins@example.com
role: roles/storage.admin
etag: BwWWja0YfJA=
version: 3
5.2 Deny Policy(拒否ポリシー)
Allow Policy より優先され、特定の Permission を明示的に拒否します。
# Deny Policy の例:本番環境でのロール削除を禁止
displayName: "Prevent role deletion in prod"
rules:
- denyRule:
deniedPrincipals:
- principalSet://goog/public:all
exceptionPrincipals:
- principal://goog/subject/security-admin@example.com
deniedPermissions:
- iam.googleapis.com/roles.delete
condition:
expression: "resource.matchTag('env', 'production')"
ユースケース:
- 重要リソースの誤削除防止
- 特定操作の組織全体での禁止
- 緊急時のアクセス遮断
5.3 Principal Access Boundary (PAB) Policy
Principal がアクセス可能なリソースの範囲を制限します。
┌─────────────────────────────────────────────────────────────┐
│ PAB のユースケース:データ流出防止 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Organization A Organization B │
│ (自社) (攻撃者) │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ Project 1 │ │ Project X │ │
│ │ Project 2 │ ───✗───→ │ │ │
│ └──────────────┘ └──────────────┘ │
│ │
│ PAB: 「この Principal は Organization A のみアクセス可能」 │
│ │
│ → フィッシングで Organization B の Role を付与されても、 │
│ PAB がブロックするためデータは流出しない │
│ │
└─────────────────────────────────────────────────────────────┘
評価順序のまとめ
1. PAB → アクセス資格がなければ即座に DENY
2. Deny → 明示的拒否があれば DENY(Allow より優先)
3. Allow → 権限があれば ALLOW、なければ DENY
6. Binding とは何か
Binding は Principal と Role を結びつける構造です。
┌─────────────────────────────────────────────────────────────┐
│ Binding の構造 │
├─────────────────────────────────────────────────────────────┤
│ │
│ Binding │
│ │ │
│ ┌───────────────┼───────────────┐ │
│ │ │ │ │
│ ▼ ▼ ▼ │
│ ┌─────────┐ ┌─────────┐ ┌─────────────┐ │
│ │ Members │ │ Role │ │ Condition │ │
│ │ │ │ │ │ (optional) │ │
│ └─────────┘ └─────────┘ └─────────────┘ │
│ │
│ user:a@... roles/ request.time < │
│ group:dev@.. storage. timestamp("...") │
│ admin │
│ │
└─────────────────────────────────────────────────────────────┘
Conditional Role Binding
Condition を追加することで、より細かい制御が可能です。
bindings:
- members:
- user:contractor@example.com
role: roles/storage.objectViewer
condition:
title: "Temporary access until March 2026"
expression: |
request.time < timestamp("2026-03-01T00:00:00Z")
使用可能な条件属性:
| 属性 | 説明 | 例 |
|---|---|---|
request.time |
リクエスト時刻 | 期限付きアクセス |
resource.name |
リソース名 | 特定リソースのみ許可 |
resource.type |
リソースタイプ | VM のみ許可 |
resource.service |
サービス名 | Storage のみ許可 |
resource.matchTag() |
リソースタグ | 本番環境のみ許可 |
7. Resource Hierarchy と継承
GCP のリソースは階層構造を持ち、Allow Policy は親から子へ継承されます。
┌──────────────┐
│ Organization │ ← 組織レベルの Policy
└──────┬───────┘ (全体に継承)
│
┌────────────┼────────────┐
│ │ │
┌─────▼─────┐ ┌────▼────┐ ┌────▼────┐
│ Folder │ │ Folder │ │ Folder │ ← フォルダレベル
│ (Dev) │ │(Staging)│ │ (Prod) │
└─────┬─────┘ └────┬────┘ └────┬────┘
│ │ │
┌─────▼─────┐ ┌────▼────┐ ┌────▼────┐
│ Project │ │ Project │ │ Project │ ← プロジェクトレベル
└─────┬─────┘ └────┬────┘ └────┬────┘
│ │ │
┌─────▼─────┐ ┌────▼────┐ ┌────▼────┐
│ Resources │ │Resources│ │Resources│ ← リソースレベル
└───────────┘ └─────────┘ └─────────┘
継承のルール
Organization で roles/viewer を User A に付与
│
▼ 継承
Folder でも User A は Viewer 権限を持つ
│
▼ 継承
Project でも User A は Viewer 権限を持つ
│
+ Project で roles/editor を追加付与
│
▼ 累積(Union)
User A は Project で Viewer + Editor の権限を持つ
重要: Allow Policy は累積(Union)されますが、Deny Policy は Allow より優先されます。
8. Impersonation を正しく理解する
Impersonation(なりすまし) は、認証済みの Principal が別の Service Account として振る舞い、その SA の権限でリソースにアクセスする仕組みです。
なぜ Impersonation が必要なのか?
┌─────────────────────────────────────────────────────────────┐
│ Impersonation のユースケース │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1. 一時的な権限昇格 │
│ ・普段は Viewer だが、デプロイ時だけ Admin 権限が必要 │
│ ・deploy-sa を Impersonate して作業 │
│ │
│ 2. ローカル開発 │
│ ・本番 SA の権限で動作確認したい │
│ ・SA Key を発行せずに Impersonate │
│ │
│ 3. 権限テスト │
│ ・「この SA でこの操作ができるか?」を確認 │
│ │
└─────────────────────────────────────────────────────────────┘
Impersonation のフロー
┌─────────────────────────────────────────────────────────────┐
│ Impersonation Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ User A (自分のアカウント) │
│ │ │
│ │ 1. Impersonation リクエスト │
│ │ 「deploy-sa になりたい」 │
│ ▼ │
│ IAM Credentials API │
│ │ │
│ │ 2. 権限チェック │
│ │ User A が deploy-sa に対して │
│ │ roles/iam.serviceAccountTokenCreator を持つか? │
│ │ │
│ │ 3. 短期 Access Token 発行(有効期限: 1時間) │
│ ▼ │
│ User A (deploy-sa として) │
│ │ │
│ │ 4. deploy-sa の権限でリソースにアクセス │
│ ▼ │
│ Cloud Storage (deploy-sa に Storage Admin が付与済み) │
│ │
└─────────────────────────────────────────────────────────────┘
必要な Role
| Role | 用途 |
|---|---|
roles/iam.serviceAccountTokenCreator |
Access Token 生成、--impersonate-service-account フラグ |
roles/iam.serviceAccountUser |
SA をリソースにアタッチ(Impersonation ではない) |
gcloud での Impersonation
# 単発コマンドで Impersonate
gcloud storage buckets list \
--impersonate-service-account=deploy-sa@project.iam.gserviceaccount.com
# デフォルト設定として Impersonate
gcloud config set auth/impersonate_service_account \
deploy-sa@project.iam.gserviceaccount.com
# ADC (Application Default Credentials) で Impersonate
gcloud auth application-default login \
--impersonate-service-account=deploy-sa@project.iam.gserviceaccount.com
Impersonation vs SA Key
| 項目 | Impersonation | SA Key |
|---|---|---|
| 認証情報の寿命 | 短期(1時間) | 長期(最大10年) |
| 漏洩リスク | 低い | 高い |
| 事前認証 | 必要 | 不要 |
| 監査ログ | 元のID + SA 両方記録 | SA のみ |
| 推奨度 | ✓ 推奨 | ✗ 非推奨 |
9. Workload Identity Federation の仕組み
Workload Identity Federation は、外部 IdP(AWS、Azure、GitHub Actions など)の認証情報を使って GCP リソースにアクセスする仕組みです。SA Key を使わずに、外部ワークロードから GCP を操作できます。
全体フロー
┌─────────────────────────────────────────────────────────────┐
│ Workload Identity Federation Flow │
├─────────────────────────────────────────────────────────────┤
│ │
│ ┌───────────────┐ │
│ │ 外部ワークロード │ (AWS EC2, Azure VM, GitHub Actions) │
│ └───────┬───────┘ │
│ │ │
│ │ 1. 外部 IdP から認証情報を取得 │
│ │ (AWS: Instance Profile, Azure: Managed ID) │
│ ▼ │
│ ┌───────────────┐ │
│ │ External Token │ │
│ └───────┬───────┘ │
│ │ │
│ │ 2. GCP Security Token Service に送信 │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Workload Identity Pool │ │
│ │ ┌─────────────────────────────────┐ │ │
│ │ │ Provider │ │ │
│ │ │ - issuer URL │ │ │
│ │ │ - attribute mapping │ │ │
│ │ │ - attribute conditions │ │ │
│ │ └─────────────────────────────────┘ │ │
│ └──────────────────┬──────────────────────┘ │
│ │ │
│ │ 3. Federated Token 発行 │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Option A: Direct Resource Access │ │
│ │ (一部 API のみ対応) │ │
│ └─────────────────────────────────────────┘ │
│ │ │
│ │ または │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Option B: SA Impersonation │ │
│ │ (roles/iam.workloadIdentityUser 必要) │ │
│ └──────────────────┬──────────────────────┘ │
│ │ │
│ │ 4. SA の Access Token 取得 │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ GCP Resources にアクセス │ │
│ └─────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘
設定例:GitHub Actions → GCP
# .github/workflows/deploy.yml
jobs:
deploy:
permissions:
contents: read
id-token: write # OIDC トークン取得に必要
steps:
- uses: google-github-actions/auth@v2
with:
workload_identity_provider: 'projects/123456789/locations/global/workloadIdentityPools/github-pool/providers/github-provider'
service_account: 'deploy-sa@my-project.iam.gserviceaccount.com'
- name: Deploy to Cloud Run
run: gcloud run deploy my-service --image gcr.io/my-project/app
GKE Workload Identity
GKE では、Kubernetes Service Account (KSA) と Google Service Account (GSA) を紐付けます。
# 1. GSA に KSA からの Impersonation を許可
gcloud iam service-accounts add-iam-policy-binding \
my-gsa@project.iam.gserviceaccount.com \
--role="roles/iam.workloadIdentityUser" \
--member="serviceAccount:project.svc.id.goog[namespace/my-ksa]"
# 2. KSA に annotation を追加
kubectl annotate serviceaccount my-ksa \
--namespace namespace \
iam.gke.io/gcp-service-account=my-gsa@project.iam.gserviceaccount.com
これで Pod から SA Key なしで GCP リソースにアクセスできます。
10. 実践:よくあるユースケースと設定例
ユースケース1: 開発者に特定プロジェクトの Storage 読み取り権限を付与
gcloud projects add-iam-policy-binding my-project \
--member="group:developers@example.com" \
--role="roles/storage.objectViewer"
ユースケース2: 期限付きの一時アクセス権を付与
gcloud projects add-iam-policy-binding my-project \
--member="user:contractor@example.com" \
--role="roles/compute.viewer" \
--condition='expression=request.time < timestamp("2026-03-01T00:00:00Z"),title=temp-access,description=Temporary access until March 2026'
ユースケース3: ユーザーに SA の Impersonation 権限を付与
# deploy-sa を User が Impersonate できるようにする
gcloud iam service-accounts add-iam-policy-binding \
deploy-sa@my-project.iam.gserviceaccount.com \
--member="user:alice@example.com" \
--role="roles/iam.serviceAccountTokenCreator"
ユースケース4: 本番環境でのリソース削除を禁止(Deny Policy)
# deny-policy.json
cat << 'EOF' > deny-policy.json
{
"displayName": "Prevent deletion in production",
"rules": [
{
"denyRule": {
"deniedPrincipals": ["principalSet://goog/public:all"],
"exceptionPrincipals": ["principal://goog/subject/admin@example.com"],
"deniedPermissions": [
"compute.googleapis.com/instances.delete",
"storage.googleapis.com/buckets.delete"
],
"denialCondition": {
"expression": "resource.matchTag('env', 'production')"
}
}
}
]
}
EOF
gcloud iam policies create deny-prod-deletion \
--attachment-point="cloudresourcemanager.googleapis.com/projects/my-project" \
--kind=denypolicies \
--policy-file=deny-policy.json
ユースケース5: 権限のトラブルシューティング
# なぜアクセスできない/できるかを調査
gcloud policy-troubleshoot iam \
//storage.googleapis.com/projects/_/buckets/my-bucket \
--permission=storage.objects.get \
--principal-email=alice@example.com
11. ベストプラクティス
1. 最小権限の原則を徹底する
✗ 避ける: roles/owner, roles/editor などの Basic Roles
✓ 推奨: サービス固有の Predefined Roles(roles/storage.objectViewer など)
✓ 最適: 必要最小限の Permission だけを含む Custom Roles
2. 個人ではなくグループに権限を付与
# ✗ 避ける
gcloud projects add-iam-policy-binding ... --member="user:alice@..."
gcloud projects add-iam-policy-binding ... --member="user:bob@..."
# ✓ 推奨
gcloud projects add-iam-policy-binding ... --member="group:developers@..."
3. SA Key を使わない
✗ 避ける: SA Key をダウンロードして環境変数に設定
✓ 推奨: Workload Identity Federation
✓ 推奨: Impersonation
✓ 推奨: Attached Service Account(GCE, Cloud Run など)
4. 階層を適切に活用
Organization レベル: 組織全体のセキュリティポリシー、監査ログ設定
Folder レベル: 環境(Dev/Staging/Prod)ごとの共通設定
Project レベル: サービス固有の権限
Resource レベル: 特定リソースへの限定的なアクセス
5. Deny Policy でガードレールを設置
- 本番環境での誤削除防止
- 特定の危険な操作の組織全体での禁止
- 外部データ流出の防止(PAB と組み合わせ)
6. 定期的な監査
# IAM Recommender で過剰権限を検出
gcloud recommender recommendations list \
--project=my-project \
--location=global \
--recommender=google.iam.policy.Recommender
12. まとめ
GCP IAM の全体像を整理すると、以下のようになります。
┌─────────────────────────────────────────────────────────────┐
│ GCP IAM まとめ │
├─────────────────────────────────────────────────────────────┤
│ │
│ 【登場人物】 │
│ ・Principal: 誰が(User, SA, Group など) │
│ ・Role: 何を(Permission の集合) │
│ ・Resource: どこに(Organization → Project → リソース) │
│ │
│ 【結びつける仕組み】 │
│ ・Binding: Principal + Role (+ Condition) │
│ ・Policy: Binding の集合 │
│ │
│ 【Policy の種類と優先度】 │
│ 1. PAB Policy → アクセス資格の制限 │
│ 2. Deny Policy → 明示的な拒否(Allow より優先) │
│ 3. Allow Policy → 権限の付与 │
│ │
│ 【認証・認可の仕組み】 │
│ ・Impersonation: 別の SA として振る舞う │
│ ・Workload Identity Federation: 外部 IdP との連携 │
│ │
│ 【継承】 │
│ ・Allow Policy は親から子へ継承(累積) │
│ ・Deny Policy も継承(Allow より優先) │
│ │
└─────────────────────────────────────────────────────────────┘
「なんとなく」から「しっかり」に変わったでしょうか?
IAM は GCP を安全に使うための基盤です。最小権限の原則を守り、Deny Policy でガードレールを設置し、Workload Identity Federation で SA Key を排除する。これらを意識することで、より安全で管理しやすい環境を構築できます。
Discussion