事前準備
約束條件架構
gcloud beta terraform vet
會使用 Constraint Framework 政策,其中包含限制和限制範本。兩者之間的差異如下:
- 限制範本就像函式宣告一樣,會在 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 供應商的產品命名慣例。舉例來說,對於
google_tags_tag
,產品名稱為tags
,但 API 名稱為resourcemanager
。 - 如果範本適用於多種資源類型,請省略資源部分,只包含功能 (例如「TFAddressTypeAllowlistConstraintV1」)。
- 版本號碼不遵循 semver 格式,只是單一數字。這樣一來,每個範本版本都會成為獨立的範本。
建議您為 Rego 檔案使用與限制範本名稱相符的名稱,但請使用蛇形命名法。換句話說,請使用 _
將名稱轉換為小寫字母分隔的字詞。在上述範例中,建議的檔案名稱為 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 提供的政策程式庫存放區,可以執行 make build
,自動更新 policies/templates
中的限制範本,並使用 validator
中定義的 Rego。
設定限制條件
限制包含 gcloud beta terraform vet
需要的三項資訊,才能正確執行並回報違規情形:
severity
:low
、medium
或high
match
:用於判斷限制是否適用於特定資源的參數。支援下列比對參數:addresses
:要納入的資源位址清單,使用 glob 樣式比對excludedAddresses
:(選用) 要排除的資源位址清單,使用 glob 樣式比對。
parameters
:約束範本的輸入參數值。
請確認 kind
包含限制範本名稱。建議將 metadata.name
設為描述性短代碼。
舉例來說,如要只允許使用上述範例限制範本的 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 資源建立資源變更限制。