Google Cloud Organization 導入直後に確認すべき IAM とリソース管理設定 — プロジェクト乱立と個人依存を防ぐ初期整備の手順
Google Workspace または Cloud Identity と紐付けて Google Cloud Organization を作ったばかりのタイミングで、必ず確認しておきたい IAM の設定があります。デフォルトのままでは、ドメインに所属する全ユーザーが自由にプロジェクトや Billing Account を作れる状態になっているためです。この状態を放置したまま数か月運用すると、「My First Project」のような用途不明のプロジェクトが Organization 直下に散乱し、退職者の OAuth に依存した外部サービス連携が残り、課金の全体像が誰にも把握できなくなります。
本記事では、Organization 作成直後に確認すべき IAM、その放置がもたらすリスク、いきなり削除して自分自身が動けなくならないための安全な権限縮小手順、フォルダと命名規則、既存プロジェクトを移動するときの注意、外部サービス連携を洗い直す観点、そして最初に実施するチェックリストまでを順に整理します。ダミー値として Organization ID 123456789012、ドメイン example.com、管理者 admin@example.com を使います。
Organization 作成直後に確認する IAM
Google Cloud Organization を新規に作ると、プロビジョニング直後のロール割り当てとして、ドメイン全体(domain:example.com)に対して次の 2 つのロールが付与されている場合があります。
roles/resourcemanager.projectCreator(Project Creator)roles/billing.creator(Billing Account Creator)
Project Creator はプロジェクトを新規作成できる権限、Billing Account Creator は Billing Account を新規作成できる権限です。ドメイン全体に付いているということは、example.com に属するすべてのユーザーがコンソールから自由に Google Cloud プロジェクトと Billing Account を作れるということです。
gcloud CLI で確認するには、Organization レベルの IAM ポリシーを取り出して該当ロールを絞り込みます。
gcloud organizations get-iam-policy 123456789012 \
--flatten="bindings[].members" \
--filter="bindings.role=roles/resourcemanager.projectCreator OR bindings.role=roles/billing.creator" \
--format="table(bindings.role, bindings.members)"出力に domain:example.com が並んでいれば、初期状態のままドメイン全体へ広く付与されているということになります。Google Cloud コンソールから確認する場合は、Organization を選択したうえで「IAM と管理」→「IAM」を開き、プリンシパルの列で example.com ドメインが含まれる行を探せば同じことがわかります。
ドメイン全体への作成権限がもたらすリスク
「Organization を作ったばかりの管理者が動けなくなること」を避けるための初期状態としては合理的ですが、通常運用に適した状態かは別問題です。ドメイン全体に Project Creator と Billing Account Creator が付いた状態を放置すると、次のリスクが積み上がっていきます。
- セキュリティ観点: 全ユーザーが Organization 配下にプロジェクトを作れるため、退職や委託終了時の権限剥奪では追いつかないリソースが増える。個人がクレデンシャルを埋めた検証環境が野良で残る
- コスト観点: Billing Account を個人カードで作られると、支払いが個人請求になっていることに管理側が気付けない。逆に組織 Billing Account に紐付けられたまま用途不明のリソースが動き続け、月次で
$100単位の課金が「誰も理由を説明できない」まま計上される - 運用観点: プロジェクトの命名や配置場所が統一されず、後から棚卸ししようとしても粒度も命名もばらばらで比較できない。「My First Project」がドメイン内に何十個も並ぶ
- 退職者対応の観点: プロジェクトの Owner が個人アカウントのみで、退職と同時にアカウントが削除されると、IAM ポリシーに
deleted:user:プレフィックス が付いた孤児プリンシパルが残る。BI ツールなどが個人 OAuth でつながっていた場合、退職と同時に接続が切れて障害になる
繰り返しになりますが、初期設定として存在すること自体は管理者救済のための仕様であって、通常運用の推奨値ではありません。Organization を作ったら、初期の管理者が動ける導線を確保したうえで、ドメイン全体からこの 2 つのロールを外す作業を早めに済ませておくのが健全です。
安全な権限変更手順
いきなりドメイン全体からロールを削除すると、削除操作を実行した管理者自身も Project Creator や Billing Account Creator を失ってしまい、次の操作ができなくなることがあります。特に「Organization を作った初期に、ドメイン全体の権限にぶら下がって作業していた」場合は要注意です。次の順序で、常に少なくとも 1 つの経路が残るように付け替えます。
- 管理者または管理者グループへ
roles/resourcemanager.projectCreatorを明示的に付与 - 管理者または管理者グループへ
roles/billing.creatorを明示的に付与 testIamPermissionsなどで、想定どおりの権限が付いていることを確認- 一時テストプロジェクトを作成して、実際に作成できることを検証
- 作成されたテストプロジェクトが Organization 配下に配置されていることを確認
- テストプロジェクトを削除
- ドメイン全体から
roles/resourcemanager.projectCreatorを削除 - ドメイン全体から
roles/billing.creatorを削除 - 最終的な IAM ポリシーを再取得して、残っている付与先が意図した相手だけであることを確認
対応する gcloud CLI コマンド例を並べます。まず、変更前に現在の Organization IAM ポリシーを控えておきます。ロールバック時にそのまま set-iam-policy で戻せる形にしておくと安心です。
gcloud organizations get-iam-policy 123456789012 \
--format=json > org-iam-before.json管理者個人へ 2 つのロールを付与します。
gcloud organizations add-iam-policy-binding 123456789012 \
--member="user:admin@example.com" \
--role="roles/resourcemanager.projectCreator"
gcloud organizations add-iam-policy-binding 123456789012 \
--member="user:admin@example.com" \
--role="roles/billing.creator"testIamPermissions で、admin@example.com が実際にその権限を持てているかを確認します。組織レベルでは gcloud のサブコマンドから直接呼べないため、gcloud auth print-access-token で取得したトークンを使って REST API を叩くのが確実です。
ACCESS_TOKEN=$(gcloud auth print-access-token)
curl -s -X POST \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"permissions":["resourcemanager.projects.create","billing.accounts.create"]}' \
"https://cloudresourcemanager.googleapis.com/v3/organizations/123456789012:testIamPermissions"レスポンスの permissions に 2 つとも並んでいれば、管理者個人経由で権限が取れています。次に、一時テストプロジェクトを Organization 配下に作成します。
gcloud projects create example-org-iam-test-01 \
--name="Org IAM Test 01" \
--organization=123456789012作成できたら、親リソースが Organization になっていることを確認します。
gcloud projects describe example-org-iam-test-01 \
--format="value(parent.type, parent.id)"organization 123456789012 のように出力されれば、Organization 配下の作成として成功しています。テストが終わったらプロジェクトを削除します。削除操作は 30 日間の猶予期間つきなので、期間内であれば gcloud projects undelete で戻せます。
gcloud projects delete example-org-iam-test-01ここまで来たら、ようやくドメイン全体の付与を外します。
gcloud organizations remove-iam-policy-binding 123456789012 \
--member="domain:example.com" \
--role="roles/resourcemanager.projectCreator"
gcloud organizations remove-iam-policy-binding 123456789012 \
--member="domain:example.com" \
--role="roles/billing.creator"最後に、変更後の IAM ポリシーを取得して、意図した相手だけが 2 つのロールを持っている状態を確認します。
gcloud organizations get-iam-policy 123456789012 \
--format=json > org-iam-after.json
diff org-iam-before.json org-iam-after.jsonもし作業中に「あれ、権限が足りない」となった場合は、gcloud organizations set-iam-policy 123456789012 org-iam-before.json で控えたポリシーへ戻せます。少なくとも 1 名の Organization Administrator(roles/resourcemanager.organizationAdmin)は必ず別途保持しておきましょう。
個人への直接付与ではなくグループを使う
上の手順は緊急対応としては十分ですが、user:admin@example.com のように個人メールへロールを直接付与した状態を長く続けるのは望ましくありません。担当者が退職または異動したときに IAM を手作業で付け替える必要が出て、そのタイミングで抜けや過剰付与が発生しやすくなるためです。
長期運用では、Cloud Identity または Google Workspace のセキュリティグループ(Google Groups をベースにしたグループ)を用意して、そこにロールを付与すると、メンバー変更時にユーザーごとのロールを付け直す必要がなくなります。例えば管理者グループを次のように作成します。
google-cloud-admins@example.com
グループへの付与は個人と同じ書式で、user: を group: に置き換えるだけです。
gcloud organizations add-iam-policy-binding 123456789012 \
--member="group:google-cloud-admins@example.com" \
--role="roles/resourcemanager.projectCreator"
gcloud organizations add-iam-policy-binding 123456789012 \
--member="group:google-cloud-admins@example.com" \
--role="roles/billing.creator"グループ経由での権限が有効になったことを、実際にログインする管理者ユーザーの立場から testIamPermissions で確認します。確認が取れたら、暫定的に付けていた user:admin@example.com の直接付与を削除します。
gcloud organizations remove-iam-policy-binding 123456789012 \
--member="user:admin@example.com" \
--role="roles/resourcemanager.projectCreator"
gcloud organizations remove-iam-policy-binding 123456789012 \
--member="user:admin@example.com" \
--role="roles/billing.creator"Google Cloud IAM 単体には、人間ユーザーをまとめるネイティブなグループ機能がありません。グループの実体は Cloud Identity または Google Workspace 上で管理し、Google Cloud はそのメールアドレスを group: プリンシパルとして参照します。したがって、Google Cloud のガバナンスを整えることは、そのまま Cloud Identity または Google Workspace 側のグループ棚卸しにも直結します。
フォルダと命名規則を整備する
Project Creator を絞ったら、次に整えるのは「作られたプロジェクトをどこに置くか」という配置と、名前の付け方です。Organization 直下にプロジェクトを積み続けると、権限継承と Organization Policy 継承の粒度が Organization 単位でしか使えなくなり、後から柔軟に整理できなくなります。
Resource Manager フォルダ をサービス単位・チーム単位に切って、プロジェクトはフォルダ配下に配置するのが基本です。環境ごとの分割方針の考え方は Enterprise Foundations Blueprint が概念レベルで示しており、具体的なフォルダ名や Project ID の付け方は Terraform Example Foundation が実装レベルで参考になります。環境を最上位に置き、その下にサービスを並べる 2 段構成の例は次のようになります。
Organization (example.com)
├── folders/production
│ └── folders/example-service
│ ├── example-service-data-prod
│ └── example-service-app-prod
├── folders/nonproduction
│ └── folders/example-service
│ └── example-service-app-nonprod
└── folders/development
└── folders/example-service
└── example-service-app-dev
命名の推奨要素は次のとおりです。フォルダ名は production・nonproduction・development とフルスペルで書くのが Terraform Example Foundation の流儀です。
- サービス名(例:
example-service) - 用途(例:
data・app・log) - 環境(フォルダ名は
production・nonproduction・developmentのフルスペル) - 必要に応じてリージョン(例:
asia-northeast1を含意するan1などの短縮形)
Project ID は 6〜30 文字という上限があるため、環境名は Project ID 側で短縮するのが実務的です。Terraform Example Foundation は p・n・d の 1 文字プレフィックスを採用しています(例: prj-p-bu1-sample-floating)。読みやすさを重視するなら prod・nonprod・dev の 3 文字前後にする流派もあり、example-service-data-nonprod は 28 文字で 30 文字上限に収まります。いずれにせよ「フォルダはフルスペル、Project ID は短縮形」の組み合わせが Terraform Example Foundation の流儀です。
「My First Project」のような Google Cloud コンソールが自動で付ける表示名は、プロジェクトの表示名を変更して用途がわかる名前に直します。gcloud CLI では次のとおりです。
gcloud projects update example-service-app-prod \
--name="Example Service / App / production"ここで注意したいのは、変えられるのは表示名(name)だけで、Project ID(example-service-app-prod の部分)は作成後に一切変更できないという点です。Project ID がそのままログや監査、外部連携のキーとして各所に埋まっていくため、命名規則は Project ID の粒度で最初に決めておくのが安全です。
既存プロジェクトを移動するときの注意点
Organization 直下やほかのフォルダにあるプロジェクトを、あとから正しいフォルダへ移すには、プロジェクトの移動 を使います。移動先フォルダの IAM と Organization Policy が継承されるため、移動しただけで実効権限や制約が変わり得ます。
移動前に、次を確認します。
- 移動元と移動先で必要な
resourcemanager.projects.move権限(実行するユーザーが両方に対して持っている必要がある) - 対象プロジェクトの
resourcemanager.projects.update権限 - プロジェクトに設定された Lien(削除をブロックするため、移動前後の運用計画に影響する場合がある)
- 移動先フォルダの IAM(継承によって実効権限がどう変わるか)
- 移動先フォルダの Organization Policy(許可されるロケーションや API が変わらないか)
- 外部サービス用サービスアカウントの IAM(プロジェクト移動でサービスアカウント自体は動かないが、参照先の IAM 変更で権限が実質変わることがある)
- Billing Account との関連付け(移動によって切れることはないが、フォルダ側の課金ポリシーがある場合は再確認)
- 移動後も維持すべき直接 IAM(フォルダ継承と重複しないか、意図せず外れていないか)
移動前後で親リソース、Billing、IAM を再取得して比較する例です。移動対象を example-service-app-prod、移動先フォルダを folders/123456789012345 とします。
gcloud projects describe example-service-app-prod \
--format="value(parent.type, parent.id)" > parent-before.txt
gcloud billing projects describe example-service-app-prod \
--format="value(billingAccountName)" > billing-before.txt
gcloud projects get-iam-policy example-service-app-prod \
--format=json > iam-before.json
gcloud beta projects move example-service-app-prod \
--folder=123456789012345
gcloud projects describe example-service-app-prod \
--format="value(parent.type, parent.id)" > parent-after.txt
gcloud billing projects describe example-service-app-prod \
--format="value(billingAccountName)" > billing-after.txt
gcloud projects get-iam-policy example-service-app-prod \
--format=json > iam-after.json
diff parent-before.txt parent-after.txt
diff billing-before.txt billing-after.txt
diff iam-before.json iam-after.json継承 IAM は get-iam-policy の結果には含まれず、Policy Analyzer や Cloud Asset Inventory を通した実効権限で見る必要があります。移動対象がミッションクリティカルであれば、事前に Policy Analyzer で「移動後に想定される実効権限」をシミュレーションしておくと事故を防げます。
外部サービス連携を調査する観点
Organization を整理していると、必ず出てくるのが「この BI ツールが誰の権限で BigQuery に接続しているのかわからない」という問題です。Google Cloud コンソールから見える情報だけで判断すると、実際の接続主体を取り違えることがあります。
BI ツールや分析サービスが BigQuery へ接続している場合、画面に表示されているユーザーがプロジェクトの Owner とは限らず、OAuth で連携したユーザー本人であることがあります。調査するときは、次を分けて確認します。
- プロジェクトの所有・管理主体(
roles/owner・roles/editorを保有するプリンシパル) - BigQuery データセットのアクセス権(データセット単位の ACL)
- クエリ実行ユーザー(BigQuery INFORMATION_SCHEMA.JOBS の
user_emailフィールド) - 外部サービスの OAuth ユーザー(サービス側の管理画面から見える「接続に使ったアカウント」)
- データ転送用サービスアカウント(BigQuery Data Transfer Service や Dataflow が使うサービスアカウント)
- Billing Account との関連付け
- Cloud Audit Logs(Admin Activity ログと Data Access ログ)
- 削除済みユーザーを示す
deleted:user:プリンシパル
退職者のメールアドレスだけで IAM を完全一致検索すると、アカウント削除後の deleted:user:takashi@example.com?uid=1234567890 のような形になったプリンシパルを見落とすことがあります。IAM ポリシー全体を JSON で取り出したうえで、deleted:user: プレフィックスを含むメンバーもまとめて拾う検索を回すのが安全です。
gcloud asset search-all-iam-policies \
--scope="organizations/123456789012" \
--query="policy:deleted" \
--format="table(resource, policy.bindings.members)"このコマンドは Cloud Asset Inventory の IAM ポリシー検索 を使い、Organization 配下のリソース全体を横断で見ます。実行には roles/cloudasset.viewer などの閲覧権限が必要です。
BigQuery でクエリを実行しているアカウントを実測したい場合は、INFORMATION_SCHEMA.JOBS を集計します。
SELECT
user_email,
COUNT(*) AS job_count,
SUM(total_bytes_processed) / POW(10, 12) AS tb_processed
FROM
`region-us`.INFORMATION_SCHEMA.JOBS
WHERE
creation_time > TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 30 DAY)
GROUP BY
user_email
ORDER BY
tb_processed DESC;このクエリの user_email が個人アカウント(ex-employee@example.com のような形)で埋まっていれば、その分析基盤は個人 OAuth に依存しています。退職と同時に接続が切れる前に、サービスアカウント に付け替える計画を立てるのが望ましい状態です。
最初に実施するチェックリスト
最後に、Organization を作った直後に手を動かすためのチェックリストをまとめます。この記事で扱った作業をそのままなぞれる形にしてあります。
- Organization IAM で
domain:example.comに対するroles/resourcemanager.projectCreatorの付与を確認した - Organization IAM で
domain:example.comに対するroles/billing.creatorの付与を確認した - Project Creator の付与対象を、管理者個人または管理者グループへ限定した
- Billing Account Creator の付与対象を、管理者個人または管理者グループへ限定した
- Cloud Identity または Google Workspace で
google-cloud-admins@example.comのような管理者グループを作成し、そこにロールを付与した - プロジェクト作成の申請フロー(起票・承認・作成担当)を定義した
- サービス単位・チーム単位のフォルダ構成を定義した
- Project ID の命名規則(サービス名・用途・環境・リージョン)を定義した
- Organization 直下にある既存プロジェクトの一覧を棚卸しした
- 「My First Project」など用途不明の表示名を持つプロジェクトを洗い出した
- 各プロジェクトに紐付いた Billing Account を確認した
- IAM ポリシー内に残る
deleted:user:プリンシパルを Organization 全体で検索した - BI ツールや分析サービスの OAuth 依存を、
INFORMATION_SCHEMA.JOBSなどで実測した - Cloud Audit Logs と Cloud Asset Inventory の閲覧権限を、責任者へ整備した
- 変更前後の Organization IAM ポリシーを JSON で保存した(
org-iam-before.jsonとorg-iam-after.json) - 一時テストプロジェクトの作成・削除で、Project Creator の制御が意図どおりに効いていることを検証した
以上、Google Cloud Organization を導入した直後に必ず確認しておきたい IAM とリソース管理の初期整備を、gcloud CLI のコマンド例と作業順序、そして最初のチェックリストまで含めて整理した、現場からお送りしました。
参考情報
- Cloud Platform Resource Hierarchy(Google Cloud)
- Default access control for organizations(Google Cloud)
- Creating and managing folders(Google Cloud)
- Migrating projects between organizations(Google Cloud)
- Project liens(Google Cloud)
- Testing IAM permissions(Google Cloud)
- IAM policies(Google Cloud)
- Cloud Asset Inventory: Searching IAM policies(Google Cloud)
- Policy Analyzer overview(Google Cloud)
- Cloud Audit Logs overview(Google Cloud)
- BigQuery INFORMATION_SCHEMA.JOBS(Google Cloud)