Antes de comenzar
Constraint Framework
gcloud beta terraform vet
usa políticas de Constraint Framework, que constan de restricciones y plantillas de restricciones. La diferencia entre ambas es la siguiente:
- Una plantilla de restricciones es como una declaración de función. Define una regla en Rego y, de forma opcional, toma parámetros de entrada.
- Una restricción es un archivo que hace referencia a una plantilla de restricciones y define los parámetros de entrada para pasarla a ella y los recursos que cubre la política.
Esto te permite evitar la repetición. Puedes escribir una plantilla de restricciones con una política genérica y, luego, escribir cualquier cantidad de restricciones que proporcionen diferentes parámetros de entrada o reglas de coincidencia de recursos.
Comparación entre los recursos de CAI y los de Terraform
Los recursos de Cloud Asset Inventory son un formato de exportación de datos estándar de Google que está disponible para muchos recursos de Google Cloud.
Los datos de CAI solo están disponibles después de crear o actualizar un recurso.
Sin embargo, mediante la conversión de los cambios de recursos de Terraform a los datos de elementos de CAI, gcloud beta terraform vet
te permite escribir una política una vez y usarla antes de aplicarla y como una verificación de auditoría con herramientas compatibles.
Herramientas compatibles
Las siguientes herramientas no son productos oficiales de Google y no son compatibles.
Sin embargo, pueden ser compatibles con las políticas escritas para gcloud beta terraform vet
.
Crea una plantilla de restricción
Antes de desarrollar tu plantilla de restricciones, verifica que el recurso para el que deseas escribir una política sea compatible con Cloud Asset Inventory y gcloud beta terraform vet
..
Para crear una plantilla de restricciones, sigue estos pasos:
- Recopila datos de muestra.
- Escribe Rego.
- Prueba tu Rego.
- Configura un esqueleto de plantilla de restricciones.
- Intercala tu Rego.
- Configura una restricción.
Recopila datos de muestra
Para escribir una plantilla de restricciones, debes tener datos de muestra con los cuales operar. Las restricciones basadas en CAI operan con datos de elementos de CAI. Para recopilar datos de muestra, crea recursos del tipo adecuado y expórtalos como JSON, como se describe en la Guía de inicio rápido de CAI.
Este es un ejemplo de exportación JSON para una dirección de Compute:
[
{
"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"
}
}
},
]
Escribe Rego
Una vez que tengas los datos de muestra, puedes escribir la lógica para la plantilla de restricciones en Rego.
Tu Rego debe tener una regla violations
. El elemento que se revisa está disponible como input.review
. Los parámetros de restricción están disponibles como input.parameters
.
Por ejemplo, para requerir que los elementos compute.googleapis.com/Address
tengan un addressType
permitido, escribe lo siguiente:
# 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}
}
Asigna un nombre a la plantilla de restricción
En el ejemplo anterior, se usa el nombre GCPComputeAddressAddressTypeAllowlistConstraintV1
. Este es un identificador único para cada plantilla de restricciones. Recomendamos seguir estos lineamientos para asignar nombres:
- Formato general:
GCP{resource}{feature}Constraint{version}
. Usa CamelCase. (En otras palabras, usa mayúsculas cada palabra nueva). - Para restricciones de recursos únicos, sigue los nombres de grupos de gcloud a fin de asignar nombres a recursos. Por ejemplo, usa “compute” en lugar de “gce”, “sql” en lugar de “cloud-sql” y “container-cluster” en lugar de “gke”.
- Si una plantilla se aplica a más de un tipo de recurso, omite la parte del recurso y solo incluye la función (ejemplo: "GCPAddressTypeAllowlistConstraintV1").
- El número de versión no sigue el formulario semver; es solo un número. Esto hace que efectivamente cada versión de una plantilla sea única.
Recomendamos usar un nombre para el archivo Rego que coincida con el nombre de la plantilla de restricción, pero con snake_case. En otras palabras, convierte el nombre en palabras en minúscula separadas con _
. Para el ejemplo anterior, el nombre de archivo recomendado es gcp_compute_address_address_type_allowlist_constraint_v1.rego
Prueba tu Rego
Puedes probar tu Rego de forma manual con Rego Playground. Asegúrate de usar datos no sensibles.
Te recomendamos escribir pruebas automatizadas.
Coloca los datos de muestra recopilados en validator/test/fixtures/<constraint
filename>/assets/data.json
y haz referencia a ellos en el archivo de prueba de la siguiente manera:
# 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
}
Coloca tu Rego y tu prueba en la carpeta validator
en tu biblioteca de políticas.
Configura un esqueleto de plantilla de restricciones
Una vez que tengas una regla de Rego que funcione y esté probada, debes empaquetarla como una plantilla de restricción. Constraint Framework usa las definiciones de recursos personalizados de Kubernetes como el contenedor para el Rego de la política.
La plantilla de restricciones también define qué parámetros están permitidos como entradas de restricciones, mediante el esquema OpenAPI V3.
Usa para el esqueleto el mismo nombre que usaste para el Rego. En particular:
- Usa el mismo nombre de archivo que tu Rego. Ejemplo:
gcp_compute_address_address_type_allowlist_constraint_v1.yaml
spec.crd.spec.names.kind
debe contener el nombre de la plantilla.metadata.name
debe contener el nombre de la plantilla, pero en minúsculas.
Coloca el esqueleto de la plantilla de restricción en policies/templates
.
Para el ejemplo anterior:
# 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
Intercala tu Rego
En este punto, según el ejemplo anterior, el diseño de tu directorio se ve de la siguiente manera:
| 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
Si clonaste el repositorio de bibliotecas de políticas proporcionado por Google, puedes ejecutar make build
para actualizar de manera automática tus plantillas de restricciones en policies/templates
con el Rego definido en validator
.
Configura una restricción
Las restricciones contienen tres datos que gcloud beta terraform vet
necesita para aplicar y denunciar los incumplimientos de forma correcta:
severity
:low
,medium
ohigh
match
: parámetros para determinar si una restricción se aplica a un recurso en particular. Se admiten los siguientes parámetros de coincidencia:ancestries
: una lista de rutas de principales para incluir con coincidencias de estilo globexcludedAncestries
: (opcional) una lista de rutas de principales para excluir mediante coincidencias de estilo glob.
parameters
: valores para los parámetros de entrada de la plantilla de restricción.
Asegúrate de que kind
contenga el nombre de la plantilla de restricción. Recomendamos configurar metadata.name
como una slug descriptiva.
Por ejemplo, para permitir solo tipos de direcciones INTERNAL
con la plantilla de restricción del ejemplo anterior, escribe lo siguiente:
# 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"
Ejemplos de coincidencias:
Comparador de rutas de principales | Descripción |
---|---|
organizations/** | Todas las organizaciones |
organizations/123/** | Todo en la organización 123 |
organizations/123/folders/** | Todo en la organización 123 que se encuentra en una carpeta |
organizations/123/folders/456 | Todo en la carpeta 456 de la organización 123 |
organizations/123/folders/456/projects/789 | Todo en el proyecto 789 en la carpeta 456 de la organización 123 |
Si una dirección de recurso coincide con los valores de ancestries
y excludedAncestries
, se excluye.
Limitaciones
Los datos del plan de Terraform proporcionan la mejor representación disponible del estado real después de aplicarlo. Sin embargo, en muchos casos, es posible que el estado después de aplicar no se conozca porque se calcula en el lado del servidor. En estos casos, los datos tampoco están disponibles en los elementos de CAI convertidos.
Compilar rutas de principales de CAI es parte del proceso cuando se validan políticas. Usa el proyecto predeterminado que se proporciona para evitar los ID de proyectos desconocidos. En el caso de que no se proporcione un proyecto predeterminado, la ruta principal se establece de forma predeterminada en organizations/unknown
.
Para inhabilitar una entidad principal desconocida, agrega la siguiente restricción:
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: {}
Recursos admitidos
Si deseas que gcloud beta terraform vet
agregue compatibilidad con un recurso que no está en esta lista, abre una solicitud de mejora y considera contribuir con código.
La lista de recursos compatibles depende de la versión de gcloud beta terraform vet
que esté instalada. La lista actual de recursos compatibles es la siguiente:
Recurso de Terraform | Recursos de 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 |