Antes de empezar
Framework de restricciones
gcloud beta terraform vet
usa políticas del framework de restricciones, que constan de restricciones y plantillas de restricciones. La diferencia entre ambos es la siguiente:
- Una plantilla de restricción es como una declaración de función: define una regla en Rego y, opcionalmente, toma parámetros de entrada.
- Una restricción es un archivo que hace referencia a una plantilla de restricción y define los parámetros de entrada que se le deben enviar y los recursos que abarca la política.
De esta forma, no tendrás que repetir la misma información. Puedes escribir una plantilla de restricción con una política genérica y, a continuación, escribir cualquier número de restricciones que proporcionen diferentes parámetros de entrada o reglas de coincidencia de recursos.
Recursos de CAI Assets y 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 Google Cloud recursos.
Los datos de CAI solo suelen estar disponibles después de que se haya creado o actualizado un recurso.
Sin embargo, al convertir los cambios de recursos de Terraform en datos de recursos de CAI,gcloud beta terraform vet
puedes escribir una política una vez y usarla tanto antes de aplicar como para hacer una comprobación de auditoría con herramientas compatibles.
Herramientas compatibles
Las siguientes herramientas no son productos oficiales de Google y no se admiten.
Sin embargo, es posible que sean compatibles con las políticas escritas para gcloud beta terraform vet
:
Crear una plantilla de restricción
Antes de desarrollar tu plantilla de restricción, verifica que el recurso para el que quieres escribir una política sea compatible con Cloud Asset Inventory y con gcloud beta terraform vet
.
Para crear una plantilla de restricción, sigue estos pasos:
- Recoge datos de muestra.
- Escribe Rego.
- Prueba tu Rego.
- Configura un esqueleto de plantilla de restricción.
- Incluye tu Rego.
- Configura una restricción.
Recoger datos de muestra
Para escribir una plantilla de restricción, necesitas tener datos de muestra con los que trabajar. Las restricciones basadas en CAI operan en datos de recursos de CAI. Recoge datos de muestra creando recursos del tipo adecuado y exportándolos como JSON, tal como se describe en la guía de inicio rápido de CAI.
A continuación se muestra un ejemplo de exportación JSON de 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"
}
}
},
]
Escribir Rego
Una vez que tengas datos de ejemplo, puedes escribir la lógica de tu plantilla de restricción en Rego.
Tu Rego debe tener una regla violations
. El recurso que se está revisando está disponible
como input.review
. Los parámetros de restricción están disponibles como input.parameters
.
Por ejemplo, para requerir que los recursos 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}
}
Ponle un nombre a la plantilla de restricción.
En el ejemplo anterior se usa el nombre
GCPComputeAddressAddressTypeAllowlistConstraintV1
. Es un identificador único de cada plantilla de restricción. Te recomendamos que sigas estas directrices para elegir nombres:
- Formato general:
GCP{resource}{feature}Constraint{version}
. Usa CamelCase. Es decir, escribe con mayúscula inicial cada palabra nueva. - En el caso de las restricciones de un solo recurso, sigue las convenciones de nomenclatura de recursos de los nombres de grupo de gcloud. 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 e incluye solo la función (por ejemplo, "GCPAddressTypeAllowlistConstraintV1").
- El número de versión no sigue el formato de semver, sino que es un solo número. De esta forma, cada versión de una plantilla se convierte en una plantilla única.
Te recomendamos que uses un nombre para tu archivo Rego que coincida con el nombre de la plantilla de restricción, pero en formato snake_case. Es decir, convierte el nombre a minúsculas y separa las palabras con _
. En el ejemplo anterior, el nombre de archivo recomendado es gcp_compute_address_address_type_allowlist_constraint_v1.rego
.
Probar tu Rego
Puedes probar tu Rego manualmente con el Rego Playground. Asegúrate de usar datos no sensibles.
Te recomendamos que escribas pruebas automatizadas.
Coloca los datos de muestra recogidos en validator/test/fixtures/<constraint
filename>/assets/data.json
y haz referencia a ellos en el archivo de prueba de esta forma:
# 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
de tu biblioteca de políticas.
Configurar un esqueleto de plantilla de restricción
Una vez que tengas una regla Rego que funcione y hayas probado, debes empaquetarla como una plantilla de restricción. Constraint Framework usa definiciones de recursos personalizados de Kubernetes como contenedor de la política Rego.
La plantilla de restricción también define qué parámetros se permiten como entradas de las restricciones mediante el esquema OpenAPI V3.
Usa el mismo nombre para el esqueleto que usaste para tu Rego. En particular:
- Usa el mismo nombre de archivo que en tu Rego. Ejemplo:
gcp_compute_address_address_type_allowlist_constraint_v1.yaml
spec.crd.spec.names.kind
debe contener el nombre de la plantillametadata.name
debe contener el nombre de la plantilla, pero en minúsculas
Coloca el esqueleto de la plantilla de restricción en policies/templates
.
En 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
Incluir tu Rego
En este punto, siguiendo el ejemplo anterior, el diseño de tu directorio sería el siguiente:
| 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 has clonado el repositorio de la biblioteca de políticas proporcionado por Google, puedes ejecutar make build
para actualizar automáticamente tus plantillas de restricciones en policies/templates
con el Rego definido en validator
.
Configurar una restricción
Las restricciones contienen tres datos que gcloud beta terraform vet
necesita para aplicar correctamente las restricciones e informar de las infracciones:
severity
:low
,medium
ohigh
match
: parámetros para determinar si una restricción se aplica a un recurso concreto. Se admiten los siguientes parámetros de coincidencia:ancestries
: lista de rutas de ancestros que se incluirán mediante la coincidencia de estilo globexcludedAncestries
: (Opcional) Lista de rutas de ancestros que se van a excluir mediante la coincidencia de estilo glob.
parameters
: valores de 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. Te recomendamos que asignes a metadata.name
un slug descriptivo.
Por ejemplo, para permitir solo los tipos de dirección 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:
Buscador de rutas de ascendencia | Descripción |
---|---|
organizations/** | Todas las organizaciones |
organizations/123/** | Todo en la organización 123 |
organizations/123/folders/** | Todo lo que haya en la organización 123 que esté en una carpeta |
organizations/123/folders/456 | Todo lo que haya en la carpeta 456 de la organización 123 |
organizations/123/folders/456/projects/789 | Todo lo que hay en el proyecto 789 de 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 ofrecen la mejor representación disponible del estado real después de aplicar los cambios. Sin embargo, en muchos casos, el estado después de aplicar puede no conocerse porque se calcula del lado del servidor. En estos casos, los datos tampoco están disponibles en los recursos de CAI convertidos.
La creación de rutas de ancestros de CAI forma parte del proceso de validación de las políticas. Usa el proyecto predeterminado proporcionado para evitar los IDs de proyecto desconocidos. Si no se proporciona ningún proyecto predeterminado, la ruta de ancestro será organizations/unknown
de forma predeterminada.
Para inhabilitar la ascendencia desconocida, añade 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 compatibles
Si quieres que gcloud beta terraform vet
añada compatibilidad con un recurso que no está en esta lista, abre una solicitud de mejora y considera la posibilidad de contribuir con código.
La lista de recursos admitidos depende de la versión de gcloud beta terraform vet
que esté instalada. Esta es la lista de recursos admitidos actualmente:
Recurso de Terraform | Recursos de Inventario de Recursos de Cloud |
---|---|
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 |