When you create a custom cloud control, you use Common Expression Language (CEL) expressions to create the rules that evaluate the properties of the scanned resource. Supported resources are Cloud Asset Inventory resource types. REST APIs are not supported.
Your expressions can be checks of a single value or more complex
compound expressions that check multiple values or conditions. Either way,
the expression must resolve to a boolean false to trigger a finding.
CEL expressions that evaluate resource properties must conform to the following rules:
The properties that you specify in a CEL expression must be properties of the scanned resource, as defined in the API definition of the resource type.
All enums in a CEL expression must be represented as strings. For example, the following is a valid expression for the
cloudkms.googleapis.com/CryptoKeyVersionresource type:resource.data.state = "PENDING_GENERATION"
The result of the CEL expressions that you define in the
conditionproperty must be a Boolean. A finding is triggered only if the result isfalse.
To find the name for a resource, see Asset types.
For more information about CEL, see the following:
Example CEL expressions
The following table lists some CEL expressions that you can use to evaluate resource properties.
| Resource type | Description | CEL expression |
|---|---|---|
cloudkms.googleapis.com/CryptoKey |
Check the Cloud KMS key rotation period | has(resource.data.rotationPeriod) && resource.data.rotationPeriod < duration('60h') |
compute.googleapis.com/Network |
Match Virtual Private Cloud peering rule to network peers | resource.data.selfLink.matches('https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/default') || resource.data.peerings.exists(p, p.network.matches('https://www.googleapis.com/compute/v1/projects/PROJECT_ID/global/networks/shared$')) |
cloudfunctions.googleapis.com/CloudFunction |
Only allow internal ingress traffic for a Cloud Run function | has(resource.data.ingressSettings) && resource.data.ingressSettings.matches('ALLOW_INTERNAL_ONLY') |
compute.googleapis.com/Instance |
Resource name matches pattern | resource.data.name.matches('^gcp-vm-(linux|windows)-v\\\\d+$') |
serviceusage.googleapis.com/Service |
Only allow storage-related APIs to be enabled | resource.data.state == 'ENABLED' && !( resource.data.name.matches('storage-api.googleapis.com') || resource.data.name.matches('bigquery-json.googleapis.com') || resource.data.name.matches('bigquery.googleapis.com') || resource.data.name.matches('sql-component.googleapis.com') || resource.data.name.matches('spanner.googleapis.com'))
|
sqladmin.googleapis.com/Instance
|
Only permit public IP addresses that are on the allowlist | (resource.data.instanceType == 'CLOUD_SQL_INSTANCE' && resource.data.backendType == 'SECOND_GEN' && resource.data.settings.ipConfiguration.ipv4Enabled ) && (resource.data.ipAddresses.all(ip, ip.type != 'PRIMARY' || ip.ipAddress.matches('IP_ADDRESS')))
|
dataproc.googleapis.com/Cluster |
Check if project IDs in a Managed Service for Apache Spark cluster contain
the substrings testing or development |
has(resource.data.projectId) && !resource.data.projectId.contains('testing') || !resource.data.projectId.contains('development') |