G-gen の佐々木です。当記事では、IAM 拒否ポリシーを使用して Google Cloud プロジェクトの削除を防止する方法を解説します。

プロジェクト削除の防止方法
IAM 拒否ポリシー(Deny Policy)
当記事で使用する IAM 拒否ポリシー(Deny Policy、以下「拒否ポリシー」と表記)は、プリンシパル(ユーザーやグループなど)に対して、特定の操作を明示的に禁止するためのポリシーです。
拒否ポリシーは IAM による許可よりも優先度が高いため、たとえ IAM ロールによって権限が付与されていても、拒否ポリシーで制限された操作は実行できません。
機能の詳細については以下の記事も参照してください。
リーエン(Lien)
プロジェクト削除を防ぐ方法としては、拒否ポリシーのほかにリーエン(Lien)を使用する方法もあります。
リーエンは、Google Cloud プロジェクトに対してロックをかける仕組みです。リーエンが設定されている間は、たとえプロジェクトの削除権限を持つユーザーであっても、先にリーエンを削除(解除)しない限りプロジェクトを削除することができません。
リーエンを使用してプロジェクト削除を防止する方法については、以下の記事をご一読ください。
拒否ポリシーとリーエンの比較
拒否ポリシーとリーエンはどちらもプロジェクトの削除を防止することができる機能ですが、以下のような違いがあります。
| 比較項目 | 拒否ポリシー | リーエン |
|---|---|---|
| アプローチ | プリンシパルの操作に対する明示的な拒否(禁止) | リソース(プロジェクト)に対する物理的なロック |
| 適用スコープ | 組織、フォルダ、プロジェクト(下位リソースに波及する) | プロジェクト単体 |
| 例外の許可 | 可能(特定のプリンシパルをポリシーの適用対象外にできる) | 不可(誰であっても、プロジェクトの削除前にリーエンの解除が必要) |
| 最適なユースケース | 組織全体や特定の範囲(本番環境など)が誤操作や悪意を持った操作により削除されることを防ぐ | 特定のプロジェクトが誤操作により削除されることを防ぐ |
組織や特定のフォルダ(本番環境フォルダなど)にある複数のプロジェクトに対して、プロジェクト削除防止のガードレールを敷きたい場合は拒否ポリシーが適しています。一方で、特定のプロジェクトの削除を防ぎたい場合はリーエンが適しています。
また、拒否ポリシー方式は IAM の仕組みによる厳格な禁止であり、クラウドの管理者のみが拒否ポリシーを編集する権限を持つことで、悪意を持った操作を防止することができます。一方のリーエン方式では、例としてプロジェクトのオーナー権限等が奪取されてしまった場合にはリーエン自体が編集されてしまうため、セキュリティ面の強固さは相対的に劣ります。
これらは併用することができるため、まずは拒否ポリシーで全体のガードレールを敷き、管理者等のユーザーだけが例外的にプロジェクトの削除を行えるようにします。その上で、特に重要なプロジェクトに対してリーエンを設定するとよいでしょう。
拒否ポリシーの設定手順
コンソールの場合
Google Cloud コンソールから拒否ポリシーを設定する場合、IAM コンソールの [許可しない] タブから [拒否ポリシーを作成] を選択します。

拒否されたプリンシパル項目に public:all を入力することで、すべてのプリンシパルを拒否ポリシーの対象とします。また、例外のプリンシパル項目には、例外的にプロジェクトの削除を行うことができるプリンシパルを入力します。
そして、プロジェクトの削除を拒否するため、拒否される権限項目に cloudresourcemanager.googleapis.com/projects.delete を入力します。

ポリシーを作成すると、例外として指定したプリンシパル以外は、プロジェクトを削除する権限を付与されていても削除操作を行うことができなくなります。

CLI の場合
使用する設定ファイル
gcloud CLI で拒否ポリシーを設定する場合、ポリシーの内容を記述した JSON ファイルを用意します。
以下はプロジェクトの削除を拒否するポリシーの例です。当記事ではファイル名を deny-project-delete.json とします。
{ "displayName": "Prevent Project Deletion", "rules": [ { "denyRule": { "deniedPrincipals": [ "principalSet://goog/public:all" ], "exceptionPrincipals": [ "principalSet://goog/group/<グループのメールアドレス>", "principal://goog/subject/<ユーザーのメールアドレス>", "principal://iam.googleapis.com/projects/-/serviceAccounts/<サービスアカウントのメールアドレス>" ], "deniedPermissions": [ "cloudresourcemanager.googleapis.com/projects.delete" ] } } ] }
deniedPrincipals には、ポリシーによる拒否の対象となるプリンシパルを指定します。principalSet://goog/public:all はすべてのプリンシパルを意味します。
exceptionPrincipals には、ポリシーで拒否している操作を例外的に許可するプリンシパルを指定します。
対象とするプリンシパルの記法(指定方法)については以下のドキュメントを参照してください。
deniedPermissions はポリシーによって拒否する権限を指定します。ここではプロジェクトの削除操作を拒否するため、cloudresourcemanager.googleapis.com/projects.delete を指定します。
拒否ポリシーで使用できる権限(拒否の対象に設定できる操作)については、以下のドキュメントを参照してください。
組織レベルの拒否ポリシー
組織レベルで拒否ポリシーを設定すると、組織内のすべてのプロジェクトに対してポリシーが適用されます。
ポリシーの作成時に対象組織の ID を指定する必要があります。
# 組織IDを検索してシェル変数に設定する $ ORG_ID=$(gcloud organizations list --format="value(ID)" --filter="displayName=<組織の名前>") # 組織レベルで拒否ポリシーを適用する $ gcloud iam policies create <任意のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/organizations/${ORG_ID} \ --kind=denypolicies \ --policy-file=deny-project-delete.json
フォルダレベルの拒否ポリシー
フォルダレベルで拒否ポリシーを設定すると、そのフォルダ内のすべてのプロジェクトに対してポリシーが適用されます。
ポリシーの作成時に対象フォルダの ID を指定する必要がありますが、組織内でフォルダがネストされている場合、ID の取得には少々手間がかかります。
# 組織IDを取得してシェル変数に設定する $ ORG_ID=$(gcloud organizations list --format="value(ID)" --filter="displayName=<組織の名前>") # 対象のフォルダIDを取得してシェル変数に設定する(組織直下のフォルダの場合) $ FOLDER_ID=$(gcloud resource-manager folders list \ --organization=${ORG_ID} \ --filter="displayName=<フォルダの名前>" \ --format="value(ID)") # 親フォルダの中を検索して対象フォルダのIDを取得する(フォルダがネストされている場合) $ FOLDER_ID=$(gcloud resource-manager folders list \ --folder=<親フォルダのID> \ --filter="displayName=<親フォルダの名前>" \ --format="value(ID)") # 取得したフォルダIDを使って拒否ポリシーを作成する $ gcloud iam policies create <任意のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/folders/${FOLDER_ID} \ --kind=denypolicies \ --policy-file=deny-project-delete.json
プロジェクトレベルの拒否ポリシー
プロジェクトレベルで拒否ポリシーを設定すると、そのプロジェクトに対してのみポリシーが適用されます。
# プロジェクトレベルで拒否ポリシーを適用する $ gcloud iam policies create <任意のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/projects/<プロジェクトID> \ --kind=denypolicies \ --policy-file=deny-project-delete.json
Terraform の場合
Terraform を使用して拒否ポリシーを設定することもできます。
以下の例では、フォルダに対してプロジェクト削除を拒否するポリシーを設定します。
# フォルダに対して拒否ポリシーを設定する locals { folder_id = "<フォルダID>" permitted_principals = [ "principalSet://goog/group/<グループのメールアドレス>", "principal://goog/subject/<ユーザーのメールアドレス>", "principal://iam.googleapis.com/projects/-/serviceAccounts/<サービスアカウントのメールアドレス>" ] } resource "google_iam_deny_policy" "this" { parent = urlencode("cloudresourcemanager.googleapis.com/folders/${local.folder_id}") name = "prevent-project-deletion" display_name = "Prevent Project Deletion" rules { description = "First rule" deny_rule { denied_principals = ["principalSet://goog/public:all"] denied_permissions = [ "cloudresourcemanager.googleapis.com/projects.delete", ] exception_principals = local.permitted_principals } } }
拒否ポリシーの削除
拒否ポリシーは、コンソールや gcloud CLI で削除することができます。
CLI で拒否ポリシーを削除するには、以下のコマンドを実行します。
# 組織レベルの拒否ポリシーを削除する $ gcloud iam policies delete <対象のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/organizations/<組織ID> \ --kind=denypolicies # フォルダレベルの拒否ポリシーを削除する $ gcloud iam policies delete <対象のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/folders/<フォルダID> \ --kind=denypolicies # プロジェクトレベルの拒否ポリシーを削除する $ gcloud iam policies delete <対象のポリシー名> \ --attachment-point=cloudresourcemanager.googleapis.com/projects/<プロジェクトID> \ --kind=denypolicies
佐々木 駿太 (記事一覧)
G-gen 最北端、北海道在住のクラウドソリューション部エンジニア
2022年6月に G-gen にジョイン。Google Cloud Partner Top Engineer に選出(2024 / 2025 Fellow / 2026)。好きな Google Cloud プロダクトは Cloud Run。
趣味はコーヒー、小説(SF、ミステリ)、カラオケなど。
Follow @sasashun0805