Create CAI constraints

Preview

This product or feature is subject to the "Pre-GA Offerings Terms" in the General Service Terms section of theService Specific Terms. Pre-GA products and features are available "as is" and might have limited support. For more information, see thelaunch stage descriptions.

Before you begin

Constraint Framework

gcloud beta terraform vet usesConstraint Frameworkpolicies, which consist ofconstraints andconstraint templates. Thedifference between the two is as follows:

  • A constraint template is like a function declaration; it defines a rule inRego and optionally takes input parameters.
  • A constraint is a file that references a constraint template and defines theinput parameters to pass to it and the resources covered by the policy.

This allows you to avoid repetition. You can write a constraint template with ageneric policy, then write any number of constraints that provide differentinput parameters or different resource matching rules.

CAI Assets vs Terraform resources

Cloud Asset Inventory Assets are a standard Google data export format that isavailablefor many Google Cloud resources.CAI data is only usually available after a resource has been created or updated.However, by converting Terraform resource changes to CAI Asset data,gcloud beta terraform vet allows you to write a policy one time and use it bothbefore apply and as an audit check with compatible tools.

Compatible tools

The following tools are not official Google products and are not supported.However, they might be compatible with policies written forgcloud beta terraform vet:

Create a constraint template

Before you develop your constraint template, verify that the Asset you want towrite a policy for is supported by bothCloud Asset Inventoryand bygcloud beta terraform vet.

Creating a constraint template takes the following steps:

  1. Collect sample data.
  2. WriteRego.
  3. Test your Rego.
  4. Set up a constraint template skeleton.
  5. Inline your Rego.
  6. Set up a constraint.

Collect sample data

In order to write a constraint template, you need to have sample data to operateon. CAI-based constraints operate onCAI Asset data. Gather sample data bycreating resources of the appropriate type and exporting those resources asJSON, as described in theCAI quickstart.

Here is an example JSON export for a Compute Address:

[{"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"}}},]

Write Rego

After you have sample data, you can write the logic for your constraint templateinRego.Your Rego must have aviolations rule. The asset being reviewed is availableasinput.review. Constraint parameters are available asinput.parameters.For example, to require thatcompute.googleapis.com/Address assets have anallowedaddressType, write:

# validator/gcp_compute_address_address_type_allowlist_constraint_v1.regopackagetemplates.gcp.GCPComputeAddressAddressTypeAllowlistConstraintV1violation[{"msg":message,"details":metadata,}]{asset:=input.reviewasset.asset_type=="compute.googleapis.com/Address"allowed_address_types:=input.parameters.allowed_address_typescount({asset.resource.data.addressType} &allowed_address_types)>=1message:=sprintf("Compute address %s has a disallowed address_type: %s",[asset.name,asset.resource.data.addressType])metadata:={"asset":asset.name}}

Name your constraint template

The previous example uses the nameGCPComputeAddressAddressTypeAllowlistConstraintV1. This is a unique identifierfor each constraint template. We recommend following these naming guidelines:

  • General format:GCP{resource}{feature}Constraint{version}. Use CamelCase.(In other words, capitalize each new word.)
  • For single-resource constraints, followgcloud group names for resourcenaming. For example, use "compute" instead of "gce", "sql" instead of"cloud-sql", and "container-cluster" instead of "gke".
  • If a template applies to more than one type of resource, omit the resourcepart and only include the feature (example:"GCPAddressTypeAllowlistConstraintV1").
  • The version number does not follow semver form; it is just a single number.This effectively makes every version of a template an unique template.

We recommend using a name for your Rego file that matches the constrainttemplate name, but using snake_case. In other words, convert the name tolowercase separate words with_. For the previous example, the recommendedfilename isgcp_compute_address_address_type_allowlist_constraint_v1.rego

Test your Rego

You can test your Rego manually with theRego Playground. Make sure touse non-sensitive data.

We recommend writingautomated tests.Put your collected sample data invalidator/test/fixtures/<constraintfilename>/assets/data.json and reference it in your test file like this:

# validator/gcp_compute_address_address_type_allowlist_constraint_v1_test.regopackagetemplates.gcp.GCPComputeAddressAddressTypeAllowlistConstraintV1importdata.test.fixtures.gcp_compute_address_address_type_allowlist_constraint_v1_test.assetsasassetstest_violation_with_disallowed_address_type{parameters:={"allowed_address_types":"EXTERNAL"}violations:=violationwithinput.reviewasassets[_]withinput.parametersasparameterscount(violations)==1}

Place your Rego and your test in thevalidator folder in your policy library.

Set up a constraint template skeleton

After you have a working and tested Rego rule, you must package it as aconstraint template. Constraint Framework uses Kubernetes Custom ResourceDefinitions as the container for the policy Rego.

The constraint template also defines what parameters are allowed as inputs fromconstraints, using theOpenAPI V3 schema.

Use the same name for the skeleton as you used for your Rego. In particular:

  • Use the same filename as for your Rego. Example:gcp_compute_address_address_type_allowlist_constraint_v1.yaml
  • spec.crd.spec.names.kind must contain the template name
  • metadata.name must contain the template name, but lower-cased

Place the constraint template skeleton inpolicies/templates.

For the example above:

# policies/templates/gcp_compute_address_address_type_allowlist_constraint_v1.yamlapiVersion:templates.gatekeeper.sh/v1beta1kind:ConstraintTemplatemetadata:name:gcpcomputeaddressaddresstypeallowlistconstraintv1spec:crd:spec:names:kind:GCPComputeAddressAddressTypeAllowlistConstraintV1validation:openAPIV3Schema:properties:allowed_address_types:description:"A list of address_types allowed, for example: ['INTERNAL']"type:arrayitems:type:stringtargets:-target:validation.gcp.forsetisecurity.orgrego:|            #INLINE("validator/gcp_compute_address_address_type_allowlist_constraint_v1.rego")            #ENDINLINE

Inline your Rego

At this point, following the previous example, your directory layout looks likethis:

|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

If you cloned theGoogle-provided policy-library repository,you can runmake build to automatically update your constraint templates inpolicies/templates with the Rego defined invalidator.

Set up a constraint

Constraints contain three pieces of information thatgcloud beta terraform vet needsto properly enforce and report violations:

  • severity:low,medium, orhigh
  • match: parameters for determining if a constraint applies to a particularresource. The following match parameters are supported:
    • ancestries: A list of ancestry paths to include using glob-stylematching
    • excludedAncestries: (Optional) A list of ancestry paths to excludeusing glob-style matching.
  • parameters: Values for the constraint template's input parameters.

Make sure thatkind contains the constraint template name. We recommendsettingmetadata.name to a descriptive slug.

For example, to only allowINTERNAL address types using the previous exampleconstraint template, write:

# policies/constraints/gcp_compute_address_internal_only.yamlapiVersion:constraints.gatekeeper.sh/v1beta1kind:GCPComputeAddressAddressTypeAllowlistConstraintV1metadata:name:gcp_compute_address_internal_onlyspec:severity:highmatch:ancestries:-"**"parameters:allowed_address_types:-"INTERNAL"

Matching examples:

Ancestry path matcherDescription
organizations/**All organizations
organizations/123/**Everything in organization 123
organizations/123/folders/**Everything in organization 123 that is under a folder
organizations/123/folders/456Everything in folder 456 in organization 123
organizations/123/folders/456/projects/789Everything in project 789 in folder 456 in organization 123

If a resource address matches values inancestries andexcludedAncestries,it is excluded.

Limitations

Terraform plan data gives the best available representation of actual stateafter apply. However, in many cases, the state after apply might not be knownbecause it is calculated on the server side. In these cases, the data is notavailable in the converted CAI Assets either.

Building CAI ancestry paths is part of the process when validating policies. Ituses the default project provided to get around unknown project IDs. In thecase where a default project is not provided, the ancestry path defaults toorganizations/unknown.

You can disallow unknown ancestry by adding the following constraint:

apiVersion:constraints.gatekeeper.sh/v1beta1kind:GCPAlwaysViolatesConstraintV1metadata:name:disallow_unknown_ancestryannotations:description:|Unknownancestryisnotallowed;use--project=<project>tosetadefaultancestryspec:severity:highmatch:ancestries:-"organizations/unknown"parameters:{}

Supported resources

If you wantgcloud beta terraform vet to add support for a resource that is not onthis list, open anenhancement request and considercontributing code.

The list of supported resources depends on which version ofgcloud beta terraform vetis installed. The current list of supported resources follows:

Terraform resourceCloud Asset Inventory Assets
google_access_context_manager_access_policy_iam_bindingaccesscontextmanager.googleapis.com/AccessPolicy
google_access_context_manager_access_policy_iam_memberaccesscontextmanager.googleapis.com/AccessPolicy
google_access_context_manager_access_policy_iam_policyaccesscontextmanager.googleapis.com/AccessPolicy
google_access_context_manager_service_perimeteraccesscontextmanager.googleapis.com/ServicePerimeter
google_apigee_environment_iam_bindingapigee.googleapis.com/Environment
google_apigee_environment_iam_memberapigee.googleapis.com/Environment
google_apigee_environment_iam_policyapigee.googleapis.com/Environment
google_bigquery_datasetbigquery.googleapis.com/Dataset
google_bigquery_dataset_iam_bindingbigquery.googleapis.com/Dataset
google_bigquery_dataset_iam_memberbigquery.googleapis.com/Dataset
google_bigquery_dataset_iam_policybigquery.googleapis.com/Dataset
google_bigquery_tablebigquery.googleapis.com/Table
google_bigquery_table_iam_bindingbigquery.googleapis.com/Table
google_bigquery_table_iam_memberbigquery.googleapis.com/Table
google_bigquery_table_iam_policybigquery.googleapis.com/Table
google_bigtable_instancebigtableadmin.googleapis.com/Cluster, bigtableadmin.googleapis.com/Instance
google_binary_authorization_attestor_iam_bindingbinaryauthorization.googleapis.com/Attestor
google_binary_authorization_attestor_iam_memberbinaryauthorization.googleapis.com/Attestor
google_binary_authorization_attestor_iam_policybinaryauthorization.googleapis.com/Attestor
google_cloud_run_domain_mappingrun.googleapis.com/DomainMapping
google_cloud_run_servicerun.googleapis.com/Service
google_cloud_run_service_iam_bindingrun.googleapis.com/Service
google_cloud_run_service_iam_memberrun.googleapis.com/Service
google_cloud_run_service_iam_policyrun.googleapis.com/Service
google_cloudfunctions_functioncloudfunctions.googleapis.com/CloudFunction
google_cloudfunctions_function_iam_bindingcloudfunctions.googleapis.com/CloudFunction
google_cloudfunctions_function_iam_membercloudfunctions.googleapis.com/CloudFunction
google_cloudfunctions_function_iam_policycloudfunctions.googleapis.com/CloudFunction
google_compute_addresscompute.googleapis.com/Address
google_compute_backend_service_iam_bindingcompute.googleapis.com/BackendService
google_compute_backend_service_iam_membercompute.googleapis.com/BackendService
google_compute_backend_service_iam_policycompute.googleapis.com/BackendService
google_compute_diskcompute.googleapis.com/Disk
google_compute_disk_iam_bindingcompute.googleapis.com/Disk
google_compute_disk_iam_membercompute.googleapis.com/Disk
google_compute_disk_iam_policycompute.googleapis.com/Disk
google_compute_firewallcompute.googleapis.com/Firewall
google_compute_forwarding_rulecompute.googleapis.com/ForwardingRule
google_compute_global_addresscompute.googleapis.com/GlobalAddress
google_compute_global_forwarding_rulecompute.googleapis.com/GlobalForwardingRule
google_compute_image_iam_bindingcompute.googleapis.com/Image
google_compute_image_iam_membercompute.googleapis.com/Image
google_compute_image_iam_policycompute.googleapis.com/Image
google_compute_instancecompute.googleapis.com/Instance
google_compute_instance_iam_bindingcompute.googleapis.com/Instance
google_compute_instance_iam_membercompute.googleapis.com/Instance
google_compute_instance_iam_policycompute.googleapis.com/Instance
google_compute_networkcompute.googleapis.com/Network
google_compute_region_backend_service_iam_bindingcompute.googleapis.com/RegionBackendService
google_compute_region_backend_service_iam_membercompute.googleapis.com/RegionBackendService
google_compute_region_backend_service_iam_policycompute.googleapis.com/RegionBackendService
google_compute_region_disk_iam_bindingcompute.googleapis.com/RegionDisk
google_compute_region_disk_iam_membercompute.googleapis.com/RegionDisk
google_compute_region_disk_iam_policycompute.googleapis.com/RegionDisk
google_compute_security_policycompute.googleapis.com/SecurityPolicy
google_compute_snapshotcompute.googleapis.com/Snapshot
google_compute_ssl_policycompute.googleapis.com/SslPolicy
google_compute_subnetworkcompute.googleapis.com/Subnetwork
google_compute_subnetwork_iam_bindingcompute.googleapis.com/Subnetwork
google_compute_subnetwork_iam_membercompute.googleapis.com/Subnetwork
google_compute_subnetwork_iam_policycompute.googleapis.com/Subnetwork
google_container_clustercontainer.googleapis.com/Cluster
google_container_node_poolcontainer.googleapis.com/NodePool
google_data_catalog_entry_group_iam_bindingdatacatalog.googleapis.com/EntryGroup
google_data_catalog_entry_group_iam_memberdatacatalog.googleapis.com/EntryGroup
google_data_catalog_entry_group_iam_policydatacatalog.googleapis.com/EntryGroup
google_data_catalog_tag_template_iam_bindingdatacatalog.googleapis.com/TagTemplate
google_data_catalog_tag_template_iam_memberdatacatalog.googleapis.com/TagTemplate
google_data_catalog_tag_template_iam_policydatacatalog.googleapis.com/TagTemplate
google_dns_managed_zonedns.googleapis.com/ManagedZone
google_dns_policydns.googleapis.com/Policy
google_endpoints_service_consumers_iam_bindingservicemanagement.googleapis.com/ServiceConsumers
google_endpoints_service_consumers_iam_memberservicemanagement.googleapis.com/ServiceConsumers
google_endpoints_service_consumers_iam_policyservicemanagement.googleapis.com/ServiceConsumers
google_endpoints_service_iam_bindingservicemanagement.googleapis.com/Service
google_endpoints_service_iam_memberservicemanagement.googleapis.com/Service
google_endpoints_service_iam_policyservicemanagement.googleapis.com/Service
google_filestore_instancefile.googleapis.com/Instance
google_folder_iam_bindingcloudresourcemanager.googleapis.com/Folder
google_folder_iam_membercloudresourcemanager.googleapis.com/Folder
google_folder_iam_policycloudresourcemanager.googleapis.com/Folder
google_folder_organization_policycloudresourcemanager.googleapis.com/Folder
google_healthcare_consent_store_iam_bindinghealthcare.googleapis.com/ConsentStore
google_healthcare_consent_store_iam_memberhealthcare.googleapis.com/ConsentStore
google_healthcare_consent_store_iam_policyhealthcare.googleapis.com/ConsentStore
google_iap_tunnel_iam_bindingiap.googleapis.com/Tunnel
google_iap_tunnel_iam_memberiap.googleapis.com/Tunnel
google_iap_tunnel_iam_policyiap.googleapis.com/Tunnel
google_iap_tunnel_instance_iam_bindingiap.googleapis.com/TunnelInstance
google_iap_tunnel_instance_iam_memberiap.googleapis.com/TunnelInstance
google_iap_tunnel_instance_iam_policyiap.googleapis.com/TunnelInstance
google_iap_web_iam_bindingiap.googleapis.com/Web
google_iap_web_iam_memberiap.googleapis.com/Web
google_iap_web_iam_policyiap.googleapis.com/Web
google_kms_crypto_keycloudkms.googleapis.com/CryptoKey
google_kms_crypto_key_iam_bindingcloudkms.googleapis.com/CryptoKey
google_kms_crypto_key_iam_membercloudkms.googleapis.com/CryptoKey
google_kms_crypto_key_iam_policycloudkms.googleapis.com/CryptoKey
google_kms_key_ringcloudkms.googleapis.com/KeyRing
google_kms_key_ring_iam_bindingcloudkms.googleapis.com/KeyRing
google_kms_key_ring_iam_membercloudkms.googleapis.com/KeyRing
google_kms_key_ring_iam_policycloudkms.googleapis.com/KeyRing
google_monitoring_alert_policymonitoring.googleapis.com/AlertPolicy
google_monitoring_notification_channelmonitoring.googleapis.com/NotificationChannel
google_notebooks_instance_iam_bindingnotebooks.googleapis.com/Instance
google_notebooks_instance_iam_membernotebooks.googleapis.com/Instance
google_notebooks_instance_iam_policynotebooks.googleapis.com/Instance
google_notebooks_runtime_iam_bindingnotebooks.googleapis.com/Runtime
google_notebooks_runtime_iam_membernotebooks.googleapis.com/Runtime
google_notebooks_runtime_iam_policynotebooks.googleapis.com/Runtime
google_organization_iam_bindingcloudresourcemanager.googleapis.com/Organization
google_organization_iam_custom_roleiam.googleapis.com/Role
google_organization_iam_membercloudresourcemanager.googleapis.com/Organization
google_organization_iam_policycloudresourcemanager.googleapis.com/Organization
google_organization_policycloudresourcemanager.googleapis.com/Organization
google_privateca_ca_pool_iam_bindingprivateca.googleapis.com/CaPool
google_privateca_ca_pool_iam_memberprivateca.googleapis.com/CaPool
google_privateca_ca_pool_iam_policyprivateca.googleapis.com/CaPool
google_privateca_certificate_template_iam_bindingprivateca.googleapis.com/CertificateTemplate
google_privateca_certificate_template_iam_memberprivateca.googleapis.com/CertificateTemplate
google_privateca_certificate_template_iam_policyprivateca.googleapis.com/CertificateTemplate
google_projectcloudbilling.googleapis.com/ProjectBillingInfo, cloudresourcemanager.googleapis.com/Project
google_project_iam_bindingcloudresourcemanager.googleapis.com/Project
google_project_iam_custom_roleiam.googleapis.com/Role
google_project_iam_membercloudresourcemanager.googleapis.com/Project
google_project_iam_policycloudresourcemanager.googleapis.com/Project
google_project_organization_policycloudresourcemanager.googleapis.com/Project
google_project_serviceserviceusage.googleapis.com/Service
google_pubsub_lite_reservationpubsublite.googleapis.com/Reservation
google_pubsub_lite_subscriptionpubsublite.googleapis.com/Subscription
google_pubsub_lite_topicpubsublite.googleapis.com/Topic
google_pubsub_schemapubsub.googleapis.com/Schema
google_pubsub_subscriptionpubsub.googleapis.com/Subscription
google_pubsub_subscription_iam_bindingpubsub.googleapis.com/Subscription
google_pubsub_subscription_iam_memberpubsub.googleapis.com/Subscription
google_pubsub_subscription_iam_policypubsub.googleapis.com/Subscription
google_pubsub_topicpubsub.googleapis.com/Topic
google_pubsub_topic_iam_bindingpubsub.googleapis.com/Topic
google_pubsub_topic_iam_memberpubsub.googleapis.com/Topic
google_pubsub_topic_iam_policypubsub.googleapis.com/Topic
google_redis_instanceredis.googleapis.com/Instance
google_secret_manager_secret_iam_bindingsecretmanager.googleapis.com/Secret
google_secret_manager_secret_iam_membersecretmanager.googleapis.com/Secret
google_secret_manager_secret_iam_policysecretmanager.googleapis.com/Secret
google_spanner_databasespanner.googleapis.com/Database
google_spanner_database_iam_bindingspanner.googleapis.com/Database
google_spanner_database_iam_memberspanner.googleapis.com/Database
google_spanner_database_iam_policyspanner.googleapis.com/Database
google_spanner_instancespanner.googleapis.com/Instance
google_spanner_instance_iam_bindingspanner.googleapis.com/Instance
google_spanner_instance_iam_memberspanner.googleapis.com/Instance
google_spanner_instance_iam_policyspanner.googleapis.com/Instance
google_sql_databasesqladmin.googleapis.com/Database
google_sql_database_instancesqladmin.googleapis.com/Instance
google_storage_bucketstorage.googleapis.com/Bucket
google_storage_bucket_iam_bindingstorage.googleapis.com/Bucket
google_storage_bucket_iam_memberstorage.googleapis.com/Bucket
google_storage_bucket_iam_policystorage.googleapis.com/Bucket
google_vpc_access_connectorvpcaccess.googleapis.com/Connector

Except as otherwise noted, the content of this page is licensed under theCreative Commons Attribution 4.0 License, and code samples are licensed under theApache 2.0 License. For details, see theGoogle Developers Site Policies. Java is a registered trademark of Oracle and/or its affiliates.

Last updated 2025-12-15 UTC.