
Security Command Center Compliance Manager のカスタムクラウドコントロールを Terraform で作って検出してみた
Compliance Manager のカスタムクラウドコントロールを試してみました。
Terraformを使ってコントロールを作成して、テスト用のリソースに対して検出までをやってみました。
カスタムクラウドコントロールとは
カスタムクラウドコントロールは、自分で検出ルールを書けるコントロールです。
ルールは CEL で書き、対象のリソースタイプと組み合わせます。
CEL には「準拠している」条件を書きます。
式が true なら準拠、false なら finding になります。
カスタムクラウドコントロールは、SCC の Premium ティアと Enterprise ティアでだけ使えます。
検出に使うには、コントロールをフレームワークに追加し、そのフレームワークを組織・フォルダ・プロジェクトにデプロイします。
デプロイすると Compliance Manager が対象のリソースを評価し、違反があれば finding が出ます。
フレームワークは、複数のコントロールをまとめたものです。
Compliance Manager には Security Essentials などの組み込みフレームワークがあります。
組み込みのフレームワークは編集できないので、カスタムクラウドコントロールは自分で作ったカスタムフレームワークに入れます。
やってみた
Terraformでリソースを作ってみます。
コントロール、フレームワーク、デプロイは、それぞれ次のリソースで作ります。
google_cloud_security_compliance_cloud_controlgoogle_cloud_security_compliance_frameworkgoogle_cloud_security_compliance_framework_deployment
検出対象は、オブジェクトのバージョニングが無効の Cloud Storage バケットにしました。
terraform {
required_version = ">= 1.9"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 8.10"
}
}
}
provider "google" {
project = var.project_id
user_project_override = true
billing_project = var.project_id
}
variable "org_id" {
type = string
}
variable "project_id" {
type = string
}
org_id = "<ORGANIZATION_ID>"
project_id = "<PROJECT_ID>"
resource "google_cloud_security_compliance_cloud_control" "bucket_versioning" {
parent = "organizations/${var.org_id}"
location = "global"
cloud_control_id = "custom-bucket-versioning"
display_name = "Bucket versioning must be enabled"
description = "Cloud Storage buckets must have versioning enabled"
categories = ["CC_CATEGORY_INFRASTRUCTURE"]
severity = "HIGH"
finding_category = "BUCKET_VERSIONING_DISABLED"
remediation_steps = "Enable object versioning on the bucket."
supported_cloud_providers = ["GCP"]
rules {
description = "Versioning must be enabled"
rule_action_types = ["RULE_ACTION_TYPE_DETECTIVE"]
cel_expression {
expression = "has(resource.data.versioning.enabled) && resource.data.versioning.enabled == true"
resource_types_values {
values = ["storage.googleapis.com/Bucket"]
}
}
}
}
resource "google_cloud_security_compliance_framework" "custom" {
parent = "organizations/${var.org_id}"
location = "global"
framework_id = "custom-storage-baseline"
display_name = "Custom Storage Baseline"
description = "Custom framework for Cloud Storage checks"
cloud_control_details {
name = google_cloud_security_compliance_cloud_control.bucket_versioning.name
major_revision_id = google_cloud_security_compliance_cloud_control.bucket_versioning.major_revision_id
}
}
resource "google_cloud_security_compliance_framework_deployment" "custom" {
parent = "organizations/${var.org_id}"
location = "global"
framework_deployment_id = "custom-storage-baseline"
framework {
framework = google_cloud_security_compliance_framework.custom.name
major_revision_id = google_cloud_security_compliance_framework.custom.major_revision_id
}
target_resource_config {
existing_target_resource = "projects/${var.project_id}"
}
cloud_control_metadata {
enforcement_mode = "DETECTIVE"
cloud_control_details {
name = google_cloud_security_compliance_cloud_control.bucket_versioning.name
major_revision_id = google_cloud_security_compliance_cloud_control.bucket_versioning.major_revision_id
}
}
}
デプロイ先は組織・フォルダ・プロジェクトから選べます。今回は影響範囲を絞るため、1つのプロジェクトにしました。
CEL の has() は、バージョニングを一度も設定していないバケットも検出するために付けています。
このようなバケットは、Cloud Asset Inventory 上で versioning が {} になり、enabled キーがありません。
has() なしの resource.data.versioning.enabled == true で試したときは、このバケットは2日以上待っても finding になりませんでした。
評価エラーは表示されず、キーがなくて式を評価できなかったためと推測しています(エラー自体は確認できていません)。
has() を付けた式では、このバケットも finding になりました。
terraform applyで上記のリソースをデプロイして、検出結果を確認します。
動作確認: 検出できるか試してみる
コンソールから「Security Command Center」 -> 「コンプライアンス」 -> 「<今回作成したフレームワーク>」の順に選択するとコントロールの状態が表示されます。

現時点ではコントロールのステータスが合格になっていることを確認できます。
検出できるか確認するために、バージョニングを設定しないバケット cm-test-ver-off を gcloud で作りました。
gcloud storage buckets create gs://<BUCKET_NAME> \
--project=<PROJECT_ID> --location=asia-northeast1
今回はデプロイ後すぐに検出されました。
ちなみに、公式ドキュメントには、デプロイ後に finding が出るまで最大6時間かかるとあるため、すぐ出ない場合は時間をおいて確認する必要がありそうです。
After you deploy a framework, it can take up to 6 hours before findings related to detective cloud controls appear.
検出後の画面は次のとおりです。

finding の詳細は以下です。

無事に検出することができました。
削除
検証が終わったらterraform destroy でリソースを削除します。特にエラーは発生せず削除できました。
削除後も、既存の finding は ACTIVE のまま残っていました。
公式ドキュメントには、フレームワークを外すと、ほとんどの finding が7日後に Inactive になるとあります。
When you remove a framework, the state of most of the related findings changes to
Inactiveafter seven days.
おわりに
Terraformで、コントロールの作成からデプロイまで一通り試しました。
未設定のときにキーごと省略されるプロパティは、CEL の式で has() を付けないと検出できないことがありました。
カスタムルールを作る時は、Cloud Asset Inventory 上のデータの形を先に確認しておくと楽そうです。






