06. IAM
GCP IAM は「member(誰が) に role(何ができる) を resource スコープで付与」というシンプルなモデル。ただし Terraform の 3 種類のリソース(policy / binding / member)の使い分けを誤ると大事故になります。
3 種類のリソース
GCP IAM の Terraform リソースは 同じ目的に 3 種類 あります。違いを理解せず使うと 全 IAM 削除事故 が起きる。
| リソース | 動作 | 安全度 |
|---|---|---|
google_*_iam_member | 1 ロール × 1 member を 追加。他に影響なし | ★★★ 推奨 |
google_*_iam_binding | 1 ロール の member 一覧を完全に置き換え。他で同じロールに追加した member は消える | ★★ 注意 |
google_*_iam_policy | そのリソースの 全 IAM ポリシーを置き換え。Terraform 外で付けたロールも全消滅 | ★ 原則使わない |
policy は事故の元
google_project_iam_policy を 1 行書いただけで、コンソール/組織で付けてあった全 IAM が消滅します。本番では絶対に使わないこと。
member の書式
user:alice@example.com # 人間
serviceAccount:my-sa@myapp-prd.iam.gserviceaccount.com # SA
group:dev-team@example.com # Workspace グループ
domain:example.com # ドメイン全員
allUsers # 全インターネット(公開)
allAuthenticatedUsers # Google アカウントログイン済み全員
principal://iam.googleapis.com/projects/.../locations/.../subject/ # Workload Identity
スコープ
権限を付ける場所は階層に応じて選びます:
| スコープ | Terraform リソース |
|---|---|
| Organization | google_organization_iam_member |
| Folder | google_folder_iam_member |
| Project | google_project_iam_member |
| Bucket | google_storage_bucket_iam_member |
| SA 自身 | google_service_account_iam_member |
| Secret Manager Secret | google_secret_manager_secret_iam_member |
主要なロール
# プロジェクト全体に Editor(広い権限。本番ではなるべく避ける)
resource "google_project_iam_member" "alice_editor" {
project = "myapp-prd"
role = "roles/editor"
member = "user:alice@example.com"
}
# Cloud Storage Object 読み取りだけ
resource "google_storage_bucket_iam_member" "vm_read" {
bucket = google_storage_bucket.data.name
role = "roles/storage.objectViewer"
member = "serviceAccount:${google_service_account.vm.email}"
}
# Cloud Run の Invoker(呼び出しのみ)
resource "google_cloud_run_v2_service_iam_member" "public" {
location = google_cloud_run_v2_service.api.location
name = google_cloud_run_v2_service.api.name
role = "roles/run.invoker"
member = "allUsers" # 全公開(注意)
}
よく使う基本ロール(広い、本番非推奨)
| ロール | 権限 |
|---|---|
roles/owner | すべて + IAM 付与 |
roles/editor | リソース変更全般 |
roles/viewer | 閲覧のみ |
本番では サービス固有ロール(roles/storage.objectViewer 等)を組み合わせて使うのが鉄則。
Service Account
resource "google_service_account" "app" {
account_id = "myapp-api"
display_name = "myapp API runtime SA"
description = "Used by Cloud Run service myapp-api"
}
# プロジェクトレベルで権限付与
resource "google_project_iam_member" "app_storage" {
project = "myapp-prd"
role = "roles/storage.objectAdmin"
member = "serviceAccount:${google_service_account.app.email}"
}
resource "google_project_iam_member" "app_secret" {
project = "myapp-prd"
role = "roles/secretmanager.secretAccessor"
member = "serviceAccount:${google_service_account.app.email}"
}
# SA を「なりすませる」権限を CI に付与(Impersonation)
resource "google_service_account_iam_member" "ci_impersonate_app" {
service_account_id = google_service_account.app.name
role = "roles/iam.serviceAccountTokenCreator"
member = "user:ci@example.com"
}
カスタムロール
resource "google_project_iam_custom_role" "myapp_deployer" {
role_id = "myappDeployer"
title = "myapp Deployer"
description = "Deploy myapp resources only"
project = "myapp-prd"
permissions = [
"run.services.create",
"run.services.update",
"run.services.get",
"artifactregistry.repositories.uploadArtifacts",
"storage.objects.create",
"storage.objects.get",
]
}
resource "google_project_iam_member" "ci_deployer" {
project = "myapp-prd"
role = google_project_iam_custom_role.myapp_deployer.id
member = "serviceAccount:ci-terraform@myapp-prd.iam.gserviceaccount.com"
}
条件付き IAM
「特定の時間帯のみ」「特定のリソースのみ」のように条件を CEL(Common Expression Language)で記述できる。
resource "google_storage_bucket_iam_member" "limited" {
bucket = google_storage_bucket.data.name
role = "roles/storage.objectViewer"
member = "user:alice@example.com"
condition {
title = "expires_end_of_2026"
description = "2026 年末まで有効"
expression = "request.time < timestamp('2027-01-01T00:00:00Z')"
}
}