事前準備
限制架構
gcloud beta terraform vet
使用限制架構政策,這類政策包含限制和限制範本。兩者差異如下:
- 限制範本類似於函式宣告,可在 Rego 中定義規則,並視需要採用輸入參數。
- 限制是參照限制範本的檔案,用於定義要傳遞至限制範本的輸入參數,以及政策涵蓋的資源。
這樣就能避免重複。您可以編寫含有一般政策的限制範本,然後編寫任意數量的限制,提供不同的輸入參數或不同的資源比對規則。
建立限制範本
如要建立限制範本,請按照下列步驟操作:
- 收集範例資料。
- 撰寫 Rego。
- 測試 Rego。
- 設定限制範本架構。
- 內嵌 Rego。
- 設定限制。
收集範例資料
如要編寫限制範本,您需要有可供操作的範例資料。以 Terraform 為基礎的限制會對資源變更資料進行運算,這些資料來自 Terraform 方案 JSON 的 resource_changes
鍵。
舉例來說,您的 JSON 可能如下所示:
// tfplan.json
{
"format_version": "0.2",
"terraform_version": "1.0.10",
"resource_changes": [
{
"address": "google_compute_address.internal_with_subnet_and_address",
"mode": "managed",
"type": "google_compute_address",
"name": "internal_with_subnet_and_address",
"provider_name": "registry.terraform.io/hashicorp/google",
"change": {
"actions": [
"create"
],
"before": null,
"after": {
"address": "10.0.42.42",
"address_type": "INTERNAL",
"description": null,
"name": "my-internal-address",
"network": null,
"prefix_length": null,
"region": "us-central1",
"timeouts": null
},
"after_unknown": {
"creation_timestamp": true,
"id": true,
"network_tier": true,
"project": true,
"purpose": true,
"self_link": true,
"subnetwork": true,
"users": true
},
"before_sensitive": false,
"after_sensitive": {
"users": []
}
}
}
],
// other data
}
撰寫 Rego
取得範例資料後,您可以在 Rego 中為限制範本撰寫邏輯。您的 Rego 必須有 violations
規則。受審查的資源變更可做為 input.review
使用。限制參數可做為 input.parameters
。舉例來說,如要規定 google_compute_address
資源必須具有允許的 address_type
,請編寫:
# validator/tf-compute-address-address-type-allowlist-constraint-v1.rego
package templates.gcp.TFComputeAddressAddressTypeAllowlistConstraintV1
violation[{
"msg": message,
"details": metadata,
}] {
resource := input.review
resource.type == "google_compute_address"
allowed_address_types := input.parameters.allowed_address_types
count({resource.change.after.address_type} & allowed_address_types) >= 1
message := sprintf(
"Compute address %s has a disallowed address_type: %s",
[resource.address, resource.change.after.address_type]
)
metadata := {"resource": resource.name}
}
為限制範本命名
上一個範例使用 TFComputeAddressAddressTypeAllowlistConstraintV1
這個名稱。這是每個限制範本的專屬 ID。建議您遵循下列命名規範:
- 一般格式:
TF{resource}{feature}Constraint{version}
。使用 CamelCase。 (也就是說,每個新字詞都要大寫。) - 如果是單一資源限制,請遵循
Terraform 供應商
的產品命名慣例。舉例來說,雖然 API 名稱為
resourcemanager
,但google_tags_tag
的產品名稱為tags
。 - 如果範本適用於多種資源,請省略資源部分,只加入功能 (例如:「TFAddressTypeAllowlistConstraintV1」)。
- 版本號碼不符合 SemVer 格式,只包含單一數字。 這表示範本的每個版本都是獨一無二的範本。
建議您為 Rego 檔案命名時,使用與限制範本名稱相符的名稱,但採用 snake_case。也就是說,將名稱轉換為小寫,並以 _
分隔字詞。以上述範例來說,建議的檔案名稱為 tf-compute-address-address-type-allowlist-constraint-v1.rego
測試 Rego
您可以使用 Rego Playground 手動測試 Rego。請務必使用非機密資料。
建議您編寫自動化測試。將收集到的樣本資料放入 validator/test/fixtures/<constraint
filename>/resource_changes/data.json
,並在測試檔案中參照該資料,如下所示:
# validator/tf-compute-address-address-type-allowlist-constraint-v1-test.rego
package templates.gcp.TFComputeAddressAddressTypeAllowlistConstraintV1
import data.test.fixtures.tf-compute-address-address-type-allowlist-constraint-v1-test.resource_changes as resource_changes
test_violation_with_disallowed_address_type {
parameters := {
"allowed_address_types": "EXTERNAL"
}
violations := violation with input.review as resource_changes[_]
with input.parameters as parameters
count(violations) == 1
}
將 Rego 和測試放在政策程式庫的 validator
資料夾中。
設定限制範本架構
在您擁有經過測試且可運作的 Rego 規則後,必須將其封裝為限制範本。限制架構會使用 Kubernetes 自訂資源定義,做為政策 Rego 的容器。
限制範本也會使用 OpenAPI V3 結構定義,定義允許哪些參數做為限制的輸入內容。
請使用與 Rego 相同的名稱做為架構。特別是:
- 請使用與 Rego 相同的檔案名稱。例如:
tf-compute-address-address-type-allowlist-constraint-v1.yaml
spec.crd.spec.names.kind
必須包含範本名稱metadata.name
必須包含範本名稱,但須為小寫
將限制範本架構放在 policies/templates
中。
例如:
# policies/templates/tf-compute-address-address-type-allowlist-constraint-v1.yaml
apiVersion: templates.gatekeeper.sh/v1beta1
kind: ConstraintTemplate
metadata:
name: tfcomputeaddressaddresstypeallowlistconstraintv1
spec:
crd:
spec:
names:
kind: TFComputeAddressAddressTypeAllowlistConstraintV1
validation:
openAPIV3Schema:
properties:
allowed_address_types:
description: "A list of address_types allowed, for example: ['INTERNAL']"
type: array
items:
type: string
targets:
- target: validation.resourcechange.terraform.cloud.google.com
rego: |
#INLINE("validator/tf-compute-address-address-type-allowlist-constraint-v1.rego")
#ENDINLINE
內嵌 Rego
此時,按照先前的範例,您的目錄版面配置應如下所示:
| policy-library/
|- validator/
||- tf-compute-address-address-type-allowlist-constraint-v1.rego
||- tf-compute-address-address-type-allowlist-constraint-v1-test.rego
|- policies
||- templates
|||- tf-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
:用於判斷限制是否適用於特定資源的參數。系統支援下列比對參數:addresses
:要納入的資源位址清單,使用 glob 樣式比對excludedAddresses
:(選用) 要排除的資源位址清單,使用 glob 樣式比對。
parameters
:限制範本輸入參數的值。
請確認 kind
包含限制範本名稱。建議將 metadata.name
設為描述性 Slug。
舉例來說,如要只允許 INTERNAL
位址類型,請使用先前的範例限制範本,並撰寫:
# policies/constraints/tf_compute_address_internal_only.yaml
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: TFComputeAddressAddressTypeAllowlistConstraintV1
metadata:
name: tf_compute_address_internal_only
spec:
severity: high
match:
addresses:
- "**"
parameters:
allowed_address_types:
- "INTERNAL"
相符的範例:
地址比對器 | 說明 |
---|---|
module.** |
任何模組中的所有資源 |
module.my_module.**
|
模組 my_module 中的所有內容 |
**.google_compute_global_forwarding_rule.*
|
任何模組中的所有 google_compute_global_forwarding_rule 資源 |
module.my_module.google_compute_global_forwarding_rule.* |
`my_module` 中的所有 google_compute_global_forwarding_rule 資源 |
如果資源地址與 addresses
和 excludedAddresses
中的值相符,系統就會排除該地址。
限制
Terraform 方案資料可提供套用後實際狀態的最佳可用表示法。不過,在許多情況下,由於狀態是在伺服器端計算,因此可能不知道套用後的狀態。
建立 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: {}
支援的資源
您可以為任何 Terraform 供應商外掛程式的任何 Terraform 資源,建立資源變更限制。