CAI 制約を作成する

始める前に

制約フレームワーク

gcloud beta terraform vet制約フレームワーク ポリシーを使用します。これは、制約と制約テンプレートで構成されます。この 2 つの違いは次のとおりです。

  • 制約テンプレートは関数宣言に似ています。Rego でルールを定義し、必要に応じて入力パラメータを受け取ります。
  • 制約は、制約テンプレートを参照し、それに渡す入力パラメータとポリシーの対象となるリソースを定義するファイルです。

これにより、繰り返しを回避できます。一般的なポリシーを使用して制約テンプレートを作成した後、任意の数の制約を作成し、さまざまな入力パラメータやリソース マッチング ルールを指定できます。

CAI アセットと Terraform リソース

Cloud Asset Inventory アセットは、多くの Google Cloud のリソースで使用できる標準の Google データ エクスポート形式です。CAI データは通常、リソースの作成または更新後にのみ使用できます。ただし、Terraform リソースの変更を CAI アセットデータに変換すると、gcloud beta terraform vet でポリシーを 1 回だけ記述し、適用前と互換性のあるツールの監査チェックの両方で使用できます。

互換性のあるツール

次のツールは Google の公式サービスではないため、サポートの対象外です。ただし、gcloud beta terraform vet で作成されたポリシーと互換性がある場合もあります。

制約テンプレートを作成する

制約テンプレートを開発する前に、ポリシーを作成するアセットが Cloud Asset Inventorygcloud beta terraform vet の両方でサポートされていることを確認します。

制約テンプレートの作成手順は次のとおりです。

  1. サンプルデータを収集します。
  2. Rego を作成します。
  3. Rego をテストします。
  4. 制約テンプレートのスケルトンを設定します。
  5. Rego をインライン化します。
  6. 制約を設定します。

サンプルデータを収集する

制約テンプレートを作成するには、サンプルデータが必要です。CAI ベースの制約は、CAI アセットデータに対して機能します。CAI クイックスタートで説明されているように、適切なタイプのリソースを作成し、それらのリソースを JSON としてエクスポートすることで、サンプルデータを収集します。

Compute アドレス用の 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 という名前を使用しています。これは、各制約テンプレートの固有識別子です。命名のガイドラインに従うことをおすすめします。

  • 一般的な形式: GCP{resource}{feature}Constraint{version}キャメルケースを使用してください(つまり、各単語の先頭を大文字にします)。
  • 単一リソースの制約については、gcloud グループ名のリソース命名規則に従います。たとえば、「gce」の代わりに「compute」、「cloud-sql」の代わりに「sql」、「gke」の代わりに「container-cluster」を使用します。
  • テンプレートが複数のタイプのリソースに適用される場合は、リソースの部分を省略し、機能のみを含めます(例: GCPAddressTypeAllowlistConstraintV1)。
  • バージョン番号が semver 形式に準拠していません。これは 1 個の数字です。これにより、テンプレートのすべてのバージョンを効率的に一意のテンプレートにすることができます。

制約テンプレート名と一致する Rego ファイルの名前を使用することをおすすめしますが、スネークケースを使用します。つまり、名前を _ を使って小文字の個別の単語に変換します。上記の例では、推奨されるファイル名は gcp_compute_address_address_type_allowlist_constraint_v1.rego です。

Rego をテストする

Rego を手動でテストするには、Rego Playground を使用します。機密でないデータを使用してください。

自動テストを作成することをおすすめします。収集したサンプルデータを 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 ルールのテストが完了したら、これを制約テンプレートとしてパッケージ化する必要があります。制約フレームワークでは、ポリシー Rego のコンテナとして Kubernetes カスタム リソース定義を使用します。

制約テンプレートは、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 提供のポリシー ライブラリ リポジトリのクローンを作成した場合は、make build を実行して、validator で定義された Rego を使用して、policies/templates の制約テンプレートを自動的に更新します。

制約を設定する

制約には、gcloud beta terraform vet が適切に適用され、違反を報告するために必要な 3 つの情報が含まれています。

  • severity: lowmedium、または high
  • match: 制約が特定のリソースに適用されるかどうかを判断するためのパラメータ。次の一致パラメータがサポートされています。
    • ancestries: glob スタイルのマッチングを使用して含める祖先パスのリスト
    • excludedAncestries: (省略可)glob スタイル マッチングを使用して除外する祖先パスのリスト。
  • parameters: 制約テンプレートの入力パラメータの値。

kind に制約テンプレート名が含まれていることを確認します。metadata.name には、説明的なスラッグを設定することをおすすめします。

たとえば、前述の制約テンプレートのサンプルを使用して 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 内のすべて

リソース アドレスが ancestriesexcludedAncestries の値と一致する場合、リソース アドレスは除外されます。

制限事項

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