🕌

なんとなくわかった気になっていた GCP IAM を学びなおす

に公開

はじめに

「このサービスアカウントに roles/storage.admin を付与しておいて」

GCPを使っていると、こんなやりとりは日常茶飯事です。言われたとおりにコンソールをポチポチして、なんとなく動くようになった。でも、ふと立ち止まって考えてみると…

  • PrincipalMember って何が違うの?
  • PolicyBinding の関係がよくわからない
  • Impersonation って結局何をしているの?
  • Workload Identity Federation が便利らしいけど仕組みがわからない

この記事では、GCP IAMの仕組みを基礎から体系的に整理し、「なんとなく」を「しっかり」に変えていきます。


目次

  1. IAMの全体像
  2. Principal(プリンシパル)を理解する
  3. Service Account の二面性
  4. Role と Permission の関係
  5. Policy の種類と評価順序
  6. Binding とは何か
  7. Resource Hierarchy と継承
  8. Impersonation を正しく理解する
  9. Workload Identity Federation の仕組み
  10. 実践:よくあるユースケースと設定例
  11. ベストプラクティス
  12. まとめ

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が内部用に作成 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