G-gen の武井です。当記事では IAM Deny policies(拒否ポリシー)を使った予防的統制について解説します。
はじめに
当記事について
当記事では、IAM Deny policies(以下、拒否ポリシー)で特定の操作を制限し、Google Cloud 環境に予防的統制を効かせる方法を解説します。
予防的統制
予防的統制とは、リスク(意図しない操作、不正な操作)を未然に防ぐための統制を意味します。
以下は Google Cloud における予防的統制の一例です。
使用するプロダクト | 効果 |
---|---|
拒否ポリシー (Cloud IAM) |
リソースに対する特定の操作を IAM パーミッション (権限) に基づき制限する |
組織のポリシー (Resource Manager) |
リソースに対する特定の操作を制約 (定義済みのアクション) に基づき制限する |
VPC Service Controls | API へのアクセスをコンテキストベースのルールに基づき制限する |
拒否ポリシー
拒否ポリシーは、通常の IAM Policy よりも強い強制力で Google Cloud リソースへの操作を制限します。
IAM ポリシーの評価フローでは、拒否ポリシー(明示的な Deny)が通常の IAM Policy(明示的な Allow)より先に評価され、優先的に適用されます。
そのため、拒否ポリシーが設定されている場合、IAM Policy を上回る強制力で当該操作を拒否します。
拒否ポリシーの詳細は以下の記事で解説しています。
拒否ポリシーの使い所
ポリシーの評価順は前述の通り、拒否ポリシー(明示的な Deny)が最も強い強制力を持ちます。
そのため、IAM による権限設計では、まずは拒否ポリシーを使わずに IAM Policy(明示的な Allow)で管理することを原則とし、 どうしても強い権限で拒否したい(権限にフタをしたい)場合に拒否ポリシーを使う
という方針が望ましいと言えます。
拒否ポリシーは統制の度合いとしては強力なため、安易に使ってしまうと後から修正が難しくなる場合があるのでご注意ください。
拒否ポリシーと組織のポリシーの違い
Google Cloud の予防的統制には、拒否ポリシーに似た仕組みとして組織のポリシー(Resource Manager の1機能)があります。
前者は IAM パーミッション(権限)
、後者は 制約
と呼ばれる定義済みのアクションにもとづいて操作を制限するという点に違いがあります。
- 参考 : ロールのコンポーネント (権限)
- 参考 : 組織のポリシーの制約
検証の概要
目的
以下の要件にもとづき、組織リソースに対して拒否ポリシーを適用し、実際の動作を確認します。
組織のポリシー(制約)の作成・削除・更新
についてはすべてのプリンシパルで禁止にしつつ、Terraform が使用するサービスアカウント、ならびに管理者グループだけは例外(操作可能)としています。
# | 拒否したい操作 | 拒否対象のプリンシパル | 例外のプリンシパル |
---|---|---|---|
1 | 組織のポリシーの作成 | すべて | ・Terraform 用 サービスアカウント ・管理者グループ |
2 | 組織のポリシーの削除 | すべて | ・Terraform 用 サービスアカウント ・管理者グループ |
3 | 組織のポリシーの更新 | すべて | ・Terraform 用 サービスアカウント ・管理者グループ |
前提
デモを実施するにあたり、以下の IAM Policy を設定しています。
# | プリンシパル | 付与した IAM ロール | 付与したリソース (場所) |
---|---|---|---|
1 | Terraform 用 サービスアカウント | ・オーナー ・組織管理者 ・組織ポリシー管理者 ・拒否管理者 |
組織リソース |
2 | 管理者グループ | ・オーナー ・組織管理者 ・組織ポリシー管理者 ・拒否管理者 |
組織リソース |
3 | 非管理者グループ | ・組織ポリシー管理者 | 組織リソース |
環境
拒否ポリシーの設定は Terraform で行います。
また、拒否ポリシー設定後は以下の条件で動作確認を行います。
# | プリンシパル | 操作 | 期待する動作 |
---|---|---|---|
1 | 管理者グループ | 組織のポリシーを作成 | 成功 |
2 | 非管理者グループ | 組織のポリシーを削除 | 失敗 |
必要な IAM ロール
拒否ポリシーを管理する場合、組織レベルで 拒否管理者ロール(roles/iam.denyAdmin)
が必要です。
今回のデモでは Terraform が使用するサービスアカウントに対し、組織レベルで上記ロールを付与しています。
- 参考 : 必要なロール
拒否ポリシーでサポートされる権限
拒否ポリシーでは一部の権限を指定することはできません。
拒否ポリシーにてサポートされる権限については以下をご確認ください。
環境構築
ソースコード
今回の検証では、Terraform で環境構築を実施します。使用した Terraform のソースコードは以下のとおりです。
$ tree . ├── env │ └── organization │ ├── backend.tf │ ├── locals.tf │ ├── main.tf │ └── versions.tf └── modules └── preventive_controls └── organization_deny_policies ├── main.tf ├── outputs.tf └── variables.tf
# main.tf (modules) resource "google_iam_deny_policy" "default" { parent = urlencode("cloudresourcemanager.googleapis.com/organizations/${var.organization_id}") name = "dev-ggen-deny-policy-organization" display_name = "Dev G-gen Deny Policy Organization" # https://cloud.google.com/iam/docs/deny-permissions-support # 組織のポリシーの編集禁止 rules { description = "First rule" deny_rule { denied_principals = ["principalSet://goog/public:all"] denied_permissions = [ "orgpolicy.googleapis.com/policies.create", "orgpolicy.googleapis.com/policies.delete", "orgpolicy.googleapis.com/policies.update", ] exception_principals = var.permitted_principals } } }
# variables.tf variable "permitted_principals" { description = "List of principals that are exempt from the deny policy" type = list(string) } variable "organization_id" { description = "The ID of the organization to create resources in" type = string }
# main.tf (env) module "organization_deny_policies" { source = "../../modules/preventive_controls/organization_deny_policies" organization_id = local.organization_id permitted_principals = local.permitted_principals }
# locals.tf locals { organization_id = "1234567890" # https://cloud.google.com/iam/docs/principal-identifiers#v2 permitted_principals = [ "principal://iam.googleapis.com/projects/-/serviceAccounts/terraform-gha-sa@iam-demo-prj.iam.gserviceaccount.com", "principalSet://goog/group/ggen-administrator-test@dev.g-gen.co.jp", ] }
- 参考 : google_iam_deny_policy
- 参考 : プリンシパルID (IAM v2 API)
実行結果
terraform apply
の実行結果は以下のとおりです。
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols: + create Terraform will perform the following actions: # module.organization_deny_policies.google_iam_deny_policy.default will be created + resource "google_iam_deny_policy" "default" { + display_name = "Dev G-gen Deny Policy Organization" + etag = (known after apply) + id = (known after apply) + name = "dev-ggen-deny-policy-organization" + parent = "cloudresourcemanager.googleapis.com%2Forganizations%2F1234567890" + rules { + description = "First rule" + deny_rule { + denied_permissions = [ + "orgpolicy.googleapis.com/policies.create", + "orgpolicy.googleapis.com/policies.delete", + "orgpolicy.googleapis.com/policies.update", ] + denied_principals = [ + "principalSet://goog/public:all", ] + exception_principals = [ + "principal://iam.googleapis.com/projects/-/serviceAccounts/terraform-gha-sa@iam-demo-prj.iam.gserviceaccount.com", + "principalSet://goog/group/ggen-administrator-test@dev.g-gen.co.jp", ] } } } Plan: 1 to add, 0 to change, 0 to destroy. module.organization_deny_policies.google_iam_deny_policy.default: Creating... module.organization_deny_policies.google_iam_deny_policy.default: Still creating... [10s elapsed] module.organization_deny_policies.google_iam_deny_policy.default: Creation complete after 11s [id=cloudresourcemanager.googleapis.com%2Forganizations%2F1234567890/dev-ggen-deny-policy-organization] Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
動作確認
拒否ポリシー設定前
両グループとも IAM Policy によって組織のポリシーの編集が許可されているため、当該操作が実行できました。
拒否ポリシー設定後
非管理者グループにおいては、拒否ポリシー設定前には実行できた操作が、設定後には制限されました。
# | プリンシパル | 操作 | 期待する動作 | 実際の結果 |
---|---|---|---|---|
1 | 管理者グループ | 組織のポリシーを作成 | 成功 | 成功 |
2 | 非管理者グループ | 組織のポリシーを削除 | 失敗 | 失敗 |
関連記事
今回ご紹介した他にも、G-gen Tech Blog では予防的統制に関する記事を多数公開しています。これらもあわせてご確認ください。
武井 祐介 (記事一覧)
クラウドソリューション部所属。G-gen唯一の山梨県在住エンジニア
Google Cloud Partner Top Engineer 2025 選出。IaC や CI/CD 周りのサービスやプロダクトが興味分野です。
趣味はロードバイク、ロードレースやサッカー観戦です。
Follow @ggenyutakei