事前準備
限制架構
gcloud beta terraform vet
使用限制架構政策,這類政策包含限制和限制範本。兩者差異如下:
- 限制範本類似於函式宣告,可在 Rego 中定義規則,並視需要採用輸入參數。
- 限制是參照限制範本的檔案,用於定義要傳遞至限制範本的輸入參數,以及政策涵蓋的資源。
這樣就能避免重複。您可以編寫含有一般政策的限制範本,然後編寫任意數量的限制,提供不同的輸入參數或不同的資源比對規則。
CAI 資產與 Terraform 資源
Cloud Asset Inventory 資產是標準的 Google 資料匯出格式,適用於許多 Google Cloud 資源。通常只有在資源建立或更新後,才能取得 CAI 資料。
不過,只要將 Terraform 資源變更轉換為 CAI 資產資料,gcloud beta terraform vet
就能讓您編寫一次政策,並在套用前和使用相容工具進行稽核檢查時,一併使用該政策。
相容工具
下列工具並非 Google 官方產品,因此不提供支援。
不過,這些政策可能與為 gcloud beta terraform vet
編寫的政策相容:
建立限制範本
開發限制範本前,請先確認您要編寫政策的資產同時支援 Cloud Asset Inventory 和 gcloud beta terraform vet
。
建立限制範本的步驟如下:
- 收集範例資料。
- 撰寫 Rego。
- 測試 Rego。
- 設定限制範本架構。
- 內嵌 Rego。
- 設定限制。
收集範例資料
如要編寫限制範本,您需要有可供操作的範例資料。CAI 限制會對 CAI 資產資料運作。建立適當類型的資源,然後將這些資源匯出為 JSON 格式,藉此收集範例資料,詳情請參閱 CAI 快速入門指南。
以下是 Compute Address 的 JSON 匯出範例:
[
{
"name": "//compute.googleapis.com/projects/789/regions/us-central1/addresses/my-internal-address",
"asset_type": "compute.googleapis.com/Address",
"ancestors: [
"organization/123",
"folder/456",
"project/789"
],
"resource": {
"version": "v1",
"discovery_document_uri": "https://www.googleapis.com/discovery/v1/apis/compute/v1/rest",
"discovery_name": "Address",
"parent": "//cloudresourcemanager.googleapis.com/projects/789",
"data": {
"address": "10.0.42.42",
"addressType": "INTERNAL",
"name": "my-internal-address",
"region": "projects/789/global/regions/us-central1"
}
}
},
]
撰寫 Rego
取得範例資料後,您可以在 Rego 中為限制範本撰寫邏輯。您的 Rego 必須有 violations
規則。受審查的資產可做為 input.review
使用。限制參數以 input.parameters
形式提供。
舉例來說,如要規定 compute.googleapis.com/Address
資產必須有允許的 addressType
,請編寫:
# validator/gcp_compute_address_address_type_allowlist_constraint_v1.rego
package templates.gcp.GCPComputeAddressAddressTypeAllowlistConstraintV1
violation[{
"msg": message,
"details": metadata,
}] {
asset := input.review
asset.asset_type == "compute.googleapis.com/Address"
allowed_address_types := input.parameters.allowed_address_types
count({asset.resource.data.addressType} & allowed_address_types) >= 1
message := sprintf(
"Compute address %s has a disallowed address_type: %s",
[asset.name, asset.resource.data.addressType]
)
metadata := {"asset": asset.name}
}
為限制範本命名
上一個範例使用 GCPComputeAddressAddressTypeAllowlistConstraintV1
這個名稱。這是每個限制範本的專屬 ID。建議您遵循下列命名規範:
- 一般格式:
GCP{resource}{feature}Constraint{version}
。使用 CamelCase。 (也就是說,每個新字詞都要大寫。) - 如果是單一資源限制,請按照gcloud 群組名稱為資源命名。舉例來說,請使用「compute」而非「gce」,使用「sql」而非「cloud-sql」,以及使用「container-cluster」而非「gke」。
- 如果範本適用於多種資源,請省略資源部分,只加入功能 (例如:「GCPAddressTypeAllowlistConstraintV1」)。
- 版本號碼不符合 SemVer 格式,只包含單一數字。 這表示範本的每個版本都是獨一無二的範本。
建議您為 Rego 檔案命名時,使用與限制範本名稱相符的名稱,但採用 snake_case。也就是說,將名稱轉換為小寫,並以 _
分隔字詞。以上述範例來說,建議的檔案名稱為 gcp_compute_address_address_type_allowlist_constraint_v1.rego
測試 Rego
您可以使用 Rego Playground 手動測試 Rego。請務必使用非機密資料。
建議您編寫自動化測試。將收集到的範例資料放入 validator/test/fixtures/<constraint
filename>/assets/data.json
,並在測試檔案中參照該資料,如下所示:
# validator/gcp_compute_address_address_type_allowlist_constraint_v1_test.rego
package templates.gcp.GCPComputeAddressAddressTypeAllowlistConstraintV1
import data.test.fixtures.gcp_compute_address_address_type_allowlist_constraint_v1_test.assets as assets
test_violation_with_disallowed_address_type {
parameters := {
"allowed_address_types": "EXTERNAL"
}
violations := violation with input.review as assets[_]
with input.parameters as parameters
count(violations) == 1
}
將 Rego 和測試放在政策程式庫的 validator
資料夾中。
設定限制範本架構
在您擁有經過測試且可運作的 Rego 規則後,必須將其封裝為限制範本。限制架構會使用 Kubernetes 自訂資源定義,做為政策 Rego 的容器。
限制範本也會使用 OpenAPI V3 結構定義,定義允許哪些參數做為限制的輸入內容。
請使用與 Rego 相同的名稱做為架構。特別是:
- 請使用與 Rego 相同的檔案名稱。例如:
gcp_compute_address_address_type_allowlist_constraint_v1.yaml
spec.crd.spec.names.kind
必須包含範本名稱metadata.name
必須包含範本名稱,但須為小寫
將限制範本架構放在 policies/templates
中。
以上述範例來說:
# policies/templates/gcp_compute_address_address_type_allowlist_constraint_v1.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: gcpcomputeaddressaddresstypeallowlistconstraintv1
spec:
crd:
spec:
names:
kind: GCPComputeAddressAddressTypeAllowlistConstraintV1
validation:
openAPIV3Schema:
properties:
allowed_address_types:
description: "A list of address_types allowed, for example: ['INTERNAL']"
type: array
items:
type: string
targets:
- target: validation.gcp.forsetisecurity.org
rego: |
#INLINE("validator/gcp_compute_address_address_type_allowlist_constraint_v1.rego")
#ENDINLINE
內嵌 Rego
此時,按照先前的範例,您的目錄版面配置應如下所示:
| policy-library/
|- validator/
||- gcp_compute_address_address_type_allowlist_constraint_v1.rego
||- gcp_compute_address_address_type_allowlist_constraint_v1_test.rego
|- policies
||- templates
|||- gcp_compute_address_address_type_allowlist_constraint_v1.yaml
如果您複製了 Google 提供的 policy-library 存放區,可以執行 make build
,自動更新 policies/templates
中的限制範本,並使用 validator
中定義的 Rego。
設定限制
限制包含三種資訊,gcloud beta terraform vet
需要這些資訊才能正確執行限制並回報違規事項:
severity
:low
、medium
或high
match
:用於判斷限制是否適用於特定資源的參數。系統支援下列比對參數:ancestries
:要納入的祖先路徑清單,使用 glob 樣式比對excludedAncestries
:(選用) 要排除的祖先路徑清單,使用 glob 樣式比對。
parameters
:限制範本輸入參數的值。
請確認 kind
包含限制範本名稱。建議將 metadata.name
設為描述性 Slug。
舉例來說,如要只允許 INTERNAL
位址類型,請使用先前的範例限制範本,並撰寫:
# policies/constraints/gcp_compute_address_internal_only.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: GCPComputeAddressAddressTypeAllowlistConstraintV1
metadata:
name: gcp_compute_address_internal_only
spec:
severity: high
match:
ancestries:
- "**"
parameters:
allowed_address_types:
- "INTERNAL"
相符的範例:
祖先路徑比對器 | 說明 |
---|---|
organizations/** | 所有機構 |
organizations/123/** | 機構 123 中的所有內容 |
organizations/123/folders/** | 機構 123 中資料夾下的所有內容 |
organizations/123/folders/456 | 機構 123 中資料夾 456 的所有內容 |
organizations/123/folders/456/projects/789 | 機構 123 中資料夾 456 內的專案 789 中的所有內容 |
如果資源位址與 ancestries
和 excludedAncestries
中的值相符,就會遭到排除。
限制
Terraform 方案資料可提供套用後實際狀態的最佳可用表示法。不過,在許多情況下,由於狀態是在伺服器端計算,因此可能無法得知套用後的狀態。在這些情況下,轉換後的 CAI 資產也不會提供資料。
建立 CAI 祖先路徑是驗證政策的程序之一。這項工具會使用提供的預設專案,避開不明專案 ID。如果未提供預設專案,祖先路徑會預設為 organizations/unknown
。
您可以新增下列限制,禁止使用不明祖源:
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: GCPAlwaysViolatesConstraintV1
metadata:
name: disallow_unknown_ancestry
annotations:
description: |
Unknown ancestry is not allowed; use --project=<project> to set a
default ancestry
spec:
severity: high
match:
ancestries:
- "organizations/unknown"
parameters: {}
支援的資源
如要gcloud beta terraform vet
新增對不在清單上的資源的支援,請開啟強化要求,並考慮提供程式碼。
支援的資源清單取決於已安裝的 gcloud beta terraform vet
版本。目前支援的資源清單如下:
Terraform 資源 | Cloud Asset Inventory 資產 |
---|---|
google_access_context_manager_access_policy_iam_binding | accesscontextmanager.googleapis.com/AccessPolicy |
google_access_context_manager_access_policy_iam_member | accesscontextmanager.googleapis.com/AccessPolicy |
google_access_context_manager_access_policy_iam_policy | accesscontextmanager.googleapis.com/AccessPolicy |
google_access_context_manager_service_perimeter | accesscontextmanager.googleapis.com/ServicePerimeter |
google_apigee_environment_iam_binding | apigee.googleapis.com/Environment |
google_apigee_environment_iam_member | apigee.googleapis.com/Environment |
google_apigee_environment_iam_policy | apigee.googleapis.com/Environment |
google_bigquery_dataset | bigquery.googleapis.com/Dataset |
google_bigquery_dataset_iam_binding | bigquery.googleapis.com/Dataset |
google_bigquery_dataset_iam_member | bigquery.googleapis.com/Dataset |
google_bigquery_dataset_iam_policy | bigquery.googleapis.com/Dataset |
google_bigquery_table | bigquery.googleapis.com/Table |
google_bigquery_table_iam_binding | bigquery.googleapis.com/Table |
google_bigquery_table_iam_member | bigquery.googleapis.com/Table |
google_bigquery_table_iam_policy | bigquery.googleapis.com/Table |
google_bigtable_instance | bigtableadmin.googleapis.com/Cluster、bigtableadmin.googleapis.com/Instance |
google_binary_authorization_attestor_iam_binding | binaryauthorization.googleapis.com/Attestor |
google_binary_authorization_attestor_iam_member | binaryauthorization.googleapis.com/Attestor |
google_binary_authorization_attestor_iam_policy | binaryauthorization.googleapis.com/Attestor |
google_cloud_run_domain_mapping | run.googleapis.com/DomainMapping |
google_cloud_run_service | run.googleapis.com/Service |
google_cloud_run_service_iam_binding | run.googleapis.com/Service |
google_cloud_run_service_iam_member | run.googleapis.com/Service |
google_cloud_run_service_iam_policy | run.googleapis.com/Service |
google_cloudfunctions_function | cloudfunctions.googleapis.com/CloudFunction |
google_cloudfunctions_function_iam_binding | cloudfunctions.googleapis.com/CloudFunction |
google_cloudfunctions_function_iam_member | cloudfunctions.googleapis.com/CloudFunction |
google_cloudfunctions_function_iam_policy | cloudfunctions.googleapis.com/CloudFunction |
google_compute_address | compute.googleapis.com/Address |
google_compute_backend_service_iam_binding | compute.googleapis.com/BackendService |
google_compute_backend_service_iam_member | compute.googleapis.com/BackendService |
google_compute_backend_service_iam_policy | compute.googleapis.com/BackendService |
google_compute_disk | compute.googleapis.com/Disk |
google_compute_disk_iam_binding | compute.googleapis.com/Disk |
google_compute_disk_iam_member | compute.googleapis.com/Disk |
google_compute_disk_iam_policy | compute.googleapis.com/Disk |
google_compute_firewall | compute.googleapis.com/Firewall |
google_compute_forwarding_rule | compute.googleapis.com/ForwardingRule |
google_compute_global_address | compute.googleapis.com/GlobalAddress |
google_compute_global_forwarding_rule | compute.googleapis.com/GlobalForwardingRule |
google_compute_image_iam_binding | compute.googleapis.com/Image |
google_compute_image_iam_member | compute.googleapis.com/Image |
google_compute_image_iam_policy | compute.googleapis.com/Image |
google_compute_instance | compute.googleapis.com/Instance |
google_compute_instance_iam_binding | compute.googleapis.com/Instance |
google_compute_instance_iam_member | compute.googleapis.com/Instance |
google_compute_instance_iam_policy | compute.googleapis.com/Instance |
google_compute_network | compute.googleapis.com/Network |
google_compute_region_backend_service_iam_binding | compute.googleapis.com/RegionBackendService |
google_compute_region_backend_service_iam_member | compute.googleapis.com/RegionBackendService |
google_compute_region_backend_service_iam_policy | compute.googleapis.com/RegionBackendService |
google_compute_region_disk_iam_binding | compute.googleapis.com/RegionDisk |
google_compute_region_disk_iam_member | compute.googleapis.com/RegionDisk |
google_compute_region_disk_iam_policy | compute.googleapis.com/RegionDisk |
google_compute_security_policy | compute.googleapis.com/SecurityPolicy |
google_compute_snapshot | compute.googleapis.com/Snapshot |
google_compute_ssl_policy | compute.googleapis.com/SslPolicy |
google_compute_subnetwork | compute.googleapis.com/Subnetwork |
google_compute_subnetwork_iam_binding | compute.googleapis.com/Subnetwork |
google_compute_subnetwork_iam_member | compute.googleapis.com/Subnetwork |
google_compute_subnetwork_iam_policy | compute.googleapis.com/Subnetwork |
google_container_cluster | container.googleapis.com/Cluster |
google_container_node_pool | container.googleapis.com/NodePool |
google_data_catalog_entry_group_iam_binding | datacatalog.googleapis.com/EntryGroup |
google_data_catalog_entry_group_iam_member | datacatalog.googleapis.com/EntryGroup |
google_data_catalog_entry_group_iam_policy | datacatalog.googleapis.com/EntryGroup |
google_data_catalog_tag_template_iam_binding | datacatalog.googleapis.com/TagTemplate |
google_data_catalog_tag_template_iam_member | datacatalog.googleapis.com/TagTemplate |
google_data_catalog_tag_template_iam_policy | datacatalog.googleapis.com/TagTemplate |
google_dns_managed_zone | dns.googleapis.com/ManagedZone |
google_dns_policy | dns.googleapis.com/Policy |
google_endpoints_service_consumers_iam_binding | servicemanagement.googleapis.com/ServiceConsumers |
google_endpoints_service_consumers_iam_member | servicemanagement.googleapis.com/ServiceConsumers |
google_endpoints_service_consumers_iam_policy | servicemanagement.googleapis.com/ServiceConsumers |
google_endpoints_service_iam_binding | servicemanagement.googleapis.com/Service |
google_endpoints_service_iam_member | servicemanagement.googleapis.com/Service |
google_endpoints_service_iam_policy | servicemanagement.googleapis.com/Service |
google_filestore_instance | file.googleapis.com/Instance |
google_folder_iam_binding | cloudresourcemanager.googleapis.com/Folder |
google_folder_iam_member | cloudresourcemanager.googleapis.com/Folder |
google_folder_iam_policy | cloudresourcemanager.googleapis.com/Folder |
google_folder_organization_policy | cloudresourcemanager.googleapis.com/Folder |
google_healthcare_consent_store_iam_binding | healthcare.googleapis.com/ConsentStore |
google_healthcare_consent_store_iam_member | healthcare.googleapis.com/ConsentStore |
google_healthcare_consent_store_iam_policy | healthcare.googleapis.com/ConsentStore |
google_iap_tunnel_iam_binding | iap.googleapis.com/Tunnel |
google_iap_tunnel_iam_member | iap.googleapis.com/Tunnel |
google_iap_tunnel_iam_policy | iap.googleapis.com/Tunnel |
google_iap_tunnel_instance_iam_binding | iap.googleapis.com/TunnelInstance |
google_iap_tunnel_instance_iam_member | iap.googleapis.com/TunnelInstance |
google_iap_tunnel_instance_iam_policy | iap.googleapis.com/TunnelInstance |
google_iap_web_iam_binding | iap.googleapis.com/Web |
google_iap_web_iam_member | iap.googleapis.com/Web |
google_iap_web_iam_policy | iap.googleapis.com/Web |
google_kms_crypto_key | cloudkms.googleapis.com/CryptoKey |
google_kms_crypto_key_iam_binding | cloudkms.googleapis.com/CryptoKey |
google_kms_crypto_key_iam_member | cloudkms.googleapis.com/CryptoKey |
google_kms_crypto_key_iam_policy | cloudkms.googleapis.com/CryptoKey |
google_kms_key_ring | cloudkms.googleapis.com/KeyRing |
google_kms_key_ring_iam_binding | cloudkms.googleapis.com/KeyRing |
google_kms_key_ring_iam_member | cloudkms.googleapis.com/KeyRing |
google_kms_key_ring_iam_policy | cloudkms.googleapis.com/KeyRing |
google_monitoring_alert_policy | monitoring.googleapis.com/AlertPolicy |
google_monitoring_notification_channel | monitoring.googleapis.com/NotificationChannel |
google_notebooks_instance_iam_binding | notebooks.googleapis.com/Instance |
google_notebooks_instance_iam_member | notebooks.googleapis.com/Instance |
google_notebooks_instance_iam_policy | notebooks.googleapis.com/Instance |
google_notebooks_runtime_iam_binding | notebooks.googleapis.com/Runtime |
google_notebooks_runtime_iam_member | notebooks.googleapis.com/Runtime |
google_notebooks_runtime_iam_policy | notebooks.googleapis.com/Runtime |
google_organization_iam_binding | cloudresourcemanager.googleapis.com/Organization |
google_organization_iam_custom_role | iam.googleapis.com/Role |
google_organization_iam_member | cloudresourcemanager.googleapis.com/Organization |
google_organization_iam_policy | cloudresourcemanager.googleapis.com/Organization |
google_organization_policy | cloudresourcemanager.googleapis.com/Organization |
google_privateca_ca_pool_iam_binding | privateca.googleapis.com/CaPool |
google_privateca_ca_pool_iam_member | privateca.googleapis.com/CaPool |
google_privateca_ca_pool_iam_policy | privateca.googleapis.com/CaPool |
google_privateca_certificate_template_iam_binding | privateca.googleapis.com/CertificateTemplate |
google_privateca_certificate_template_iam_member | privateca.googleapis.com/CertificateTemplate |
google_privateca_certificate_template_iam_policy | privateca.googleapis.com/CertificateTemplate |
google_project | cloudbilling.googleapis.com/ProjectBillingInfo、cloudresourcemanager.googleapis.com/Project |
google_project_iam_binding | cloudresourcemanager.googleapis.com/Project |
google_project_iam_custom_role | iam.googleapis.com/Role |
google_project_iam_member | cloudresourcemanager.googleapis.com/Project |
google_project_iam_policy | cloudresourcemanager.googleapis.com/Project |
google_project_organization_policy | cloudresourcemanager.googleapis.com/Project |
google_project_service | serviceusage.googleapis.com/Service |
google_pubsub_lite_reservation | pubsublite.googleapis.com/Reservation |
google_pubsub_lite_subscription | pubsublite.googleapis.com/Subscription |
google_pubsub_lite_topic | pubsublite.googleapis.com/Topic |
google_pubsub_schema | pubsub.googleapis.com/Schema |
google_pubsub_subscription | pubsub.googleapis.com/Subscription |
google_pubsub_subscription_iam_binding | pubsub.googleapis.com/Subscription |
google_pubsub_subscription_iam_member | pubsub.googleapis.com/Subscription |
google_pubsub_subscription_iam_policy | pubsub.googleapis.com/Subscription |
google_pubsub_topic | pubsub.googleapis.com/Topic |
google_pubsub_topic_iam_binding | pubsub.googleapis.com/Topic |
google_pubsub_topic_iam_member | pubsub.googleapis.com/Topic |
google_pubsub_topic_iam_policy | pubsub.googleapis.com/Topic |
google_redis_instance | redis.googleapis.com/Instance |
google_secret_manager_secret_iam_binding | secretmanager.googleapis.com/Secret |
google_secret_manager_secret_iam_member | secretmanager.googleapis.com/Secret |
google_secret_manager_secret_iam_policy | secretmanager.googleapis.com/Secret |
google_spanner_database | spanner.googleapis.com/Database |
google_spanner_database_iam_binding | spanner.googleapis.com/Database |
google_spanner_database_iam_member | spanner.googleapis.com/Database |
google_spanner_database_iam_policy | spanner.googleapis.com/Database |
google_spanner_instance | spanner.googleapis.com/Instance |
google_spanner_instance_iam_binding | spanner.googleapis.com/Instance |
google_spanner_instance_iam_member | spanner.googleapis.com/Instance |
google_spanner_instance_iam_policy | spanner.googleapis.com/Instance |
google_sql_database | sqladmin.googleapis.com/Database |
google_sql_database_instance | sqladmin.googleapis.com/Instance |
google_storage_bucket | storage.googleapis.com/Bucket |
google_storage_bucket_iam_binding | storage.googleapis.com/Bucket |
google_storage_bucket_iam_member | storage.googleapis.com/Bucket |
google_storage_bucket_iam_policy | storage.googleapis.com/Bucket |
google_vpc_access_connector | vpcaccess.googleapis.com/Connector |