Membuat batasan Terraform

Sebelum memulai

Framework Batasan

gcloud beta terraform vet menggunakan kebijakan Framework Batasan, yang terdiri dari batasan dan template batasan. Perbedaan antara keduanya adalah sebagai berikut:

  • Template batasan itu seperti deklarasi fungsi; yaitu menetapkan aturan di Rego dan secara opsional mengambil parameter input.
  • Batasan adalah file yang mereferensikan template batasan dan menentukan parameter input yang akan diteruskan ke template tersebut serta resource yang dicakup oleh kebijakan.

Ini memungkinkan Anda untuk menghindari pengulangan. Anda dapat menulis template batasan dengan kebijakan umum, lalu menulis sejumlah batasan yang memberikan parameter input berbeda atau aturan pencocokan resource yang berbeda.

Membuat template batasan

Untuk membuat template batasan, ikuti langkah-langkah berikut:

  1. Kumpulkan data sampel.
  2. Tulis Rego.
  3. Uji Rego Anda.
  4. Siapkan kerangka template batasan.
  5. Sejajarkan Rego Anda.
  6. Siapkan batasan.

Mengumpulkan data sampel

Untuk menulis template batasan, Anda harus memiliki contoh data untuk beroperasi. Batasan berbasis Terraform beroperasi pada data perubahan resource, yang berasal dari kunci resource_changes pada JSON paket Terraform.

Contohnya, JSON Anda mungkin terlihat seperti ini:

// 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
}

Tulis Rego

Setelah memiliki data contoh, Anda dapat menulis logika untuk template batasan di Rego. Rego Anda harus memiliki aturan violations. Perubahan resource yang sedang ditinjau tersedia sebagai input.review. Parameter batasan tersedia sebagai input.parameters. Contohnya, untuk mengharuskan resource google_compute_address memiliki address_type yang diizinkan, tulis:

# 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.after.address_type} & allowed_address_types) >= 1
  message := sprintf(
    "Compute address %s has a disallowed address_type: %s",
    [resource.address, resource.after.address_type]
  )
  metadata := {"resource": resource.name}
}

Beri nama template batasan Anda

Contoh sebelumnya menggunakan nama TFComputeAddressAddressTypeAllowlistConstraintV1. Ini adalah ID unik untuk setiap template batasan. Sebaiknya ikuti panduan penamaan berikut:

  • Format umum: TF{resource}{feature}Constraint{version}. Gunakan CamelCase. (Dengan kata lain, gunakan huruf besar untuk setiap kata baru.)
  • Untuk batasan resource tunggal, ikuti konvensi penyedia Terraform untuk penamaan produk. Contoh, untuk google_tags_tag, nama produknya adalah tags meskipun nama API-nya resourcemanager.
  • Jika template berlaku untuk lebih dari satu jenis resource, hapus bagian resource dan hanya sertakan fiturnya (contoh: "TFAddressTypeAllowlistConstraintV1").
  • Nomor versi tidak mengikuti format semver; itu hanya satu angka. Cara ini secara efektif membuat setiap versi template menjadi template yang unik.

Sebaiknya gunakan nama untuk file Rego yang cocok dengan nama template batasan, tetapi gunakan snake_case. Dengan kata lain, konversi nama menjadi kata-kata yang menggunakan huruf kecil dan terpisah dengan _. Untuk contoh sebelumnya, nama file yang direkomendasikan adalah tf_compute_address_address_type_allowlist_constraint_v1.rego

Uji Rego Anda

Anda dapat menguji Rego secara manual dengan Rego Playground. Pastikan untuk menggunakan data yang tidak sensitif.

Sebaiknya tulis pengujian otomatis. Masukkan contoh data yang dikumpulkan di validator/test/fixtures/<constraint filename>/resource_changes/data.json dan referensikan data tersebut dalam file pengujian Anda seperti ini:

# 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
}

Tempatkan Rego dan pengujian Anda dalam folder validator di library kebijakan Anda.

Menyiapkan kerangka template batasan

Setelah memiliki aturan Rego yang berfungsi dan diuji, Anda harus mengemasnya sebagai template batasan. Framework Batasan menggunakan Definisi Resource Kustom Kubernetes sebagai container untuk kebijakan Rego.

Template batasan juga menentukan parameter yang diizinkan sebagai input dari batasan, menggunakan skema OpenAPI V3.

Gunakan nama yang sama untuk kerangka seperti yang Anda gunakan untuk Rego. Pada khususnya:

  • Gunakan nama file yang sama seperti untuk Rego Anda. Contoh: tf_compute_address_address_type_allowlist_constraint_v1.yaml
  • spec.crd.spec.names.kind harus berisi nama template
  • metadata.name harus berisi nama template, tetapi ditulis dengan huruf kecil

Tempatkan kerangka template batasan di policies/templates.

Untuk contoh di atas:

# 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

Sejajarkan Rego Anda

Pada tahap ini, mengikuti contoh sebelumnya, tata letak direktori Anda akan terlihat seperti ini:

| 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

Jika meng-clone repositori library kebijakan yang disediakan Google, Anda dapat menjalankan make build untuk mengupdate template batasan secara otomatis di policies/templates dengan Rego yang ditentukan di validator.

Menyiapkan batasan

Batasan berisi tiga informasi yang diperlukan gcloud beta terraform vet untuk menerapkan dan melaporkan pelanggaran dengan benar:

  • severity: low, medium, atau high
  • match: Parameter untuk menentukan apakah batasan berlaku untuk resource tertentu. Parameter pencocokan berikut didukung:
    • addresses: Daftar alamat resource yang akan disertakan menggunakan pencocokan gaya glob
    • excludedAddresses: (Opsional) Daftar alamat resource yang akan dikecualikan menggunakan pencocokan gaya glob.
  • parameters: Nilai untuk parameter input template batasan.

Pastikan kind berisi nama template batasan. Sebaiknya setel metadata.name ke slug deskriptif.

Contohnya, untuk hanya mengizinkan jenis alamat INTERNAL menggunakan contoh template batasan sebelumnya, tulis:

# 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"

Contoh yang cocok:

Pencocok alamat Deskripsi
`module.**` Semua resource dalam modul apa pun
`module.my_module.**` Semuanya dalam modul `my_module`
`**.google_compute_global_forwarding_rule.*` Semua resource google_compute_global_forwarding_rule di modul mana pun
`module.my_module.google_compute_global_forwarding_rule.*` Semua resource google_compute_global_forwarding_rule di `my_module`

Jika alamat resource cocok dengan nilai di addresses dan excludedAddresses, alamat tersebut akan dikecualikan.

Batasan

Data paket Terraform memberikan representasi terbaik dari status sebenarnya setelah penerapan. Namun, dalam banyak kasus, status setelah penerapan mungkin tidak diketahui karena dihitung di sisi server.

Membuat jalur ancestry CAI adalah bagian dari proses saat memvalidasi kebijakan. Gunakan project default yang disediakan untuk menyiasati project ID yang tidak dikenal. Jika project default tidak disediakan, jalur ancestry akan ditetapkan secara default ke organizations/unknown.

Anda dapat melarang ancestry yang tidak diketahui dengan menambahkan batasan berikut:

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: {}

Resource yang didukung

Anda dapat membuat batasan perubahan resource untuk setiap resource Terraform dari penyedia Terraform mana pun.