始める前に
制約フレームワーク
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 Inventory と gcloud beta terraform vet
の両方でサポートされていることを確認します。
制約テンプレートの作成手順は次のとおりです。
- サンプルデータを収集します。
- Rego を作成します。
- Rego をテストします。
- 制約テンプレートのスケルトンを設定します。
- Rego をインライン化します。
- 制約を設定します。
サンプルデータを収集する
制約テンプレートを作成するには、サンプルデータが必要です。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
:low
、medium
、または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 内のすべて |
リソース アドレスが 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 |