Protege datos con claves de Cloud KMS

De forma predeterminada, BigQuery encripta contenido de clientes almacenado en reposo. BigQuery controla y administra esta encriptación predeterminada por ti sin que tengas que realizar ninguna acción adicional. Primero, los datos en una tabla de BigQuery se encriptan con una clave de encriptación de datos. Luego, esas claves de encriptación de datos se encriptan con la clave de encriptación de claves. Este proceso se denomina encriptación de sobre. Las claves de encriptación de claves no encriptan tus datos de modo directo, pero se usan para encriptar las claves de encriptación de datos que Google usa a fin de encriptar tus datos. Si deseas obtener más información, consulta Administración de claves.

Si deseas controlar la encriptación por tu cuenta, puedes usar las claves de encriptación administradas por el cliente (CMEK) para BigQuery. En lugar de que Google administre las claves de encriptación de claves que protegen tus datos, tú las controlas y las administras en Cloud KMS. Este tema incluye información detallada sobre esta técnica.

Obtén más información sobre las opciones de encriptación en Google Cloud.

Antes de comenzar

  1. Comprende qué son los conjuntos de datos, las tablas y las consultas.

  2. Decide si ejecutarás BigQuery y Cloud KMS en el mismo proyecto de Google Cloud, o si lo harás en proyectos distintos. Con el propósito de brindar documentación de ejemplo, se usa la siguiente convención:

    • PROJECT_ID: Es el ID del proyecto que ejecuta BigQuery.
    • PROJECT_NUMBER: Es el número del proyecto que ejecuta BigQuery.
    • KMS_PROJECT_ID: Es el ID del proyecto que ejecuta Cloud KMS (incluso si es el mismo proyecto que ejecuta BigQuery).
    Para obtener información sobre los ID de proyectos de Cloud y los números de proyectos, consulta Identifica proyectos.

  3. BigQuery se habilita de forma automática en proyectos nuevos. Si usas un proyecto existente para ejecutar BigQuery, habilita la API de BigQuery.

  4. En el proyecto de Google Cloud que ejecuta Cloud KMS, haz lo siguiente:

    1. Habilita la API de Cloud Key Management Service.
    2. Crea un llavero de claves y una clave como se describe en Crea claves simétricas. Crea el llavero de claves en una ubicación que coincida con la de tu conjunto de datos de BigQuery:
      • Cualquier conjunto de datos multirregional debe usar un llavero de claves multirregional desde una ubicación que coincida. Por ejemplo, un conjunto de datos en la región US debe protegerse con un llavero de claves de la región us, y un conjunto de datos en la región EU debe protegerse con un llavero de claves de la región europe.
      • Los conjuntos de datos regionales deben usar una clave regional que coincida. Por ejemplo, un conjunto de datos en la región asia-northeast1 debe protegerse con un llavero de claves de la región asia-northeast1.
      • La región global no es compatible para usar con BigQuery.
      Si quieres obtener más información sobre las ubicaciones compatibles con BigQuery y Cloud KMS, consulta Ubicaciones de Cloud.

Especificaciones de encriptación

Las claves de Cloud KMS que se usan para proteger tus datos en BigQuery son claves AES-256. Estas claves se usan como claves de encriptación de claves en BigQuery porque encriptan las claves de encriptación de datos que encriptan tus datos.

Otorga permisos de encriptación y desencriptación

A fin de proteger los datos de BigQuery con una clave CMEK, otorga permiso a la cuenta de servicio de BigQuery para encriptar y desencriptar mediante esa clave. La función de encriptador y desencriptador de CryptoKey de Cloud KMS otorga este permiso.

Usa Google Cloud Console para determinar el ID de la cuenta de servicio de BigQuery y proporciona a la cuenta de servicio la función adecuada para encriptar y desencriptar mediante Cloud KMS.

Determina el ID de la cuenta de servicio

El ID de la cuenta de servicio de BigQuery tiene el siguiente formato:

bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com

Con las siguientes técnicas, se muestra cómo puedes determinar el ID de la cuenta de servicio de BigQuery para tu proyecto.

Console

  1. Ve a la página Panel en Cloud Console

    Ir a la página Panel

  2. Haz clic en la lista desplegable Seleccionar una opción en la parte superior de la página. En la ventana Seleccionar una opción que aparece, elige tu proyecto.

  3. El ID y el número del proyecto se muestran en la tarjeta de Información del proyecto (Project info) del panel del proyecto:

    Tarjeta de información del proyecto

  4. En la siguiente string, reemplaza PROJECT_NUMBER por el número de tu proyecto. La string nueva identifica el ID de la cuenta de servicio de BigQuery.

    bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com
    

bq

Usa el comando bq show con la marca --encryption_service_account para determinar el ID de la cuenta de servicio:

bq show --encryption_service_account

El comando muestra el ID de la cuenta de servicio:

                  ServiceAccountID
-------------------------------------------------------------
bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com

Asigna la función Encriptador/Desencriptador

Asigna la función de encriptador y desencriptador de CryptoKey de Cloud KMS a la cuenta de servicio del sistema de BigQuery que copiaste en tu portapapeles. Esta cuenta tiene el formato siguiente:

bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com

Console

  1. Abre la página Claves criptográficas en Cloud Console.

    Abrir la página Claves criptográficas

  2. Haz clic en el nombre del llavero de claves que contiene la clave.

  3. Haz clic en la casilla de verificación de la clave de encriptación a la que deseas agregar la función. Se abrirá la pestaña Permisos.

  4. Haz clic en Agregar miembro.

  5. Ingresa la dirección de correo electrónico de la cuenta de servicio, bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com.

    • Si la cuenta de servicio ya se encuentra en la lista de miembros, es porque tiene funciones existentes. Haz clic en la lista desplegable de funciones actuales de la cuenta de servicio bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com.
  6. Haz clic en la lista desplegable y selecciona Selecciona una función. Haz clic en Cloud KMS y, luego, en la función de Encriptador/desencriptador de CryptoKey de Cloud KMS.

  7. Haz clic en Guardar para aplicar la función a la cuenta de servicio bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com.

gcloud

Puedes usar la herramienta de línea de comandos de gcloud para asignar la función:

gcloud kms keys add-iam-policy-binding \
--project=KMS_PROJECT_ID \
--member serviceAccount:bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com \
--role roles/cloudkms.cryptoKeyEncrypterDecrypter \
--location=KMS_KEY_LOCATION \
--keyring=KMS_KEY_RING \
KMS_KEY

Reemplaza lo siguiente:

  • KMS_PROJECT_ID: Es el ID del proyecto de Google Cloud que ejecuta Cloud KMS.
  • PROJECT_NUMBER: Es el número del proyecto (no el ID) del proyecto de Cloud que ejecuta BigQuery.
  • KMS_KEY_LOCATION: Es el nombre de la ubicación de la clave de Cloud KMS.
  • KMS_KEY_RING: Es el nombre del llavero de claves de la clave de Cloud KMS.
  • KMS_KEY: Es el nombre de la clave de Cloud KMS.

ID de recurso de la clave

El ID de recurso de la clave de Cloud KMS es obligatorio para el uso de CMEK, como se muestra en los ejemplos de este tema. Esta clave distingue entre mayúsculas y minúsculas y tiene el siguiente formato:

projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY

Recupera el ID de recurso de la clave

  1. Abre la página Claves criptográficas en Cloud Console.

    Abrir la página Claves criptográficas

  2. Haz clic en el nombre del llavero de claves que contiene la clave.

  3. Para la clave con el ID de recurso que quieres recuperar, haz clic en Más .

  4. Haz clic en Copiar ID de recurso. Se copiará el ID de recurso de la clave en portapapeles.

Crea una tabla protegida por Cloud KMS

Crea una tabla vacía protegida por Cloud KMS

Para crear una tabla protegida por Cloud KMS, sigue estos pasos:

Console

  1. Abre la página de BigQuery en Cloud Console.

    Ir a la página BigQuery

  2. En el panel de navegación, en la sección Recursos, expande tu proyecto y selecciona un conjunto de datos.

  3. Haz clic en Crear tabla.

  4. En la página Crear tabla, completa la información requerida para crear una tabla vacía con una definición de esquema. Antes de hacer clic en Crear tabla, configura el tipo de encriptación y especifica la clave de Cloud KMS que se usará con la tabla:

    1. Haz clic en Opciones avanzadas.
    2. Haz clic en Clave administrada por el cliente.
    3. Selecciona la llave. Si la clave que quieres usar no aparece en la lista, ingresa el ID de recurso de la clave.
  5. Haz clic en Crear tabla.

bq

Puedes usar la herramienta de línea de comandos de bq con la marca --destination_kms_key para crear la tabla. La marca --destination_kms_key especifica el ID de recurso de la clave para usar con la tabla.

Para crear una tabla vacía con un esquema, usa lo siguiente:

bq mk --schema name:string,value:integer -t \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
mydataset.newtable

Como alternativa, puedes usar una declaración de DDL:

bq query --use_legacy_sql=false "
  CREATE TABLE mydataset.newtable (name STRING, value INT64)
  OPTIONS(
    kms_key_name='projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY'
  )
"

Para crear una tabla desde una consulta, usa lo siguiente:

bq query --destination_table=mydataset.newtable \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
"SELECT name,count FROM mydataset.babynames WHERE gender = 'M' ORDER BY count DESC LIMIT 6"

Para obtener más información sobre la herramienta de línea de comandos de bq, consulta Usa la herramienta de línea de comandos de bq.

Go

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// createTableWithCMEK demonstrates creating a table protected with a customer managed encryption key.
func createTableWithCMEK(projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydatasetid"
	// tableID := "mytableid"
	ctx := context.Background()

	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	tableRef := client.Dataset(datasetID).Table(tableID)
	meta := &bigquery.TableMetadata{
		EncryptionConfig: &bigquery.EncryptionConfig{
			// TODO: Replace this key with a key you have created in Cloud KMS.
			KMSKeyName: "projects/cloud-samples-tests/locations/us/keyRings/test/cryptoKeys/test",
		},
	}
	if err := tableRef.Create(ctx, meta); err != nil {
		return err
	}
	return nil
}

Java

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.EncryptionConfiguration;
import com.google.cloud.bigquery.Field;
import com.google.cloud.bigquery.Schema;
import com.google.cloud.bigquery.StandardSQLTypeName;
import com.google.cloud.bigquery.StandardTableDefinition;
import com.google.cloud.bigquery.TableDefinition;
import com.google.cloud.bigquery.TableId;
import com.google.cloud.bigquery.TableInfo;

// Sample to create a cmek table
public class CreateTableCMEK {

  public static void runCreateTableCMEK() {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String kmsKeyName = "MY_KEY_NAME";
    Schema schema =
        Schema.of(
            Field.of("stringField", StandardSQLTypeName.STRING),
            Field.of("booleanField", StandardSQLTypeName.BOOL));
    // i.e. projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{cryptoKey}
    EncryptionConfiguration encryption =
        EncryptionConfiguration.newBuilder().setKmsKeyName(kmsKeyName).build();
    createTableCMEK(datasetName, tableName, schema, encryption);
  }

  public static void createTableCMEK(
      String datasetName, String tableName, Schema schema, EncryptionConfiguration configuration) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      TableId tableId = TableId.of(datasetName, tableName);
      TableDefinition tableDefinition = StandardTableDefinition.of(schema);
      TableInfo tableInfo =
          TableInfo.newBuilder(tableId, tableDefinition)
              .setEncryptionConfiguration(configuration)
              .build();

      bigquery.create(tableInfo);
      System.out.println("Table cmek created successfully");
    } catch (BigQueryException e) {
      System.out.println("Table cmek was not created. \n" + e.toString());
    }
  }
}

Python

Para proteger una tabla nueva con una clave de encriptación administrada por el cliente, configura la propiedad Table.encryption_configuration como un objeto EncryptionConfiguration antes de crear la tabla.

# from google.cloud import bigquery
# client = bigquery.Client()
# dataset_id = 'my_dataset'

table_ref = dataset.table("my_table")
table = bigquery.Table(table_ref)

# Set the encryption key to use for the table.
# TODO: Replace this key with a key you have created in Cloud KMS.
kms_key_name = "projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}".format(
    "cloud-samples-tests", "us", "test", "test"
)
table.encryption_configuration = bigquery.EncryptionConfiguration(
    kms_key_name=kms_key_name
)

table = client.create_table(table)  # API request

assert table.encryption_configuration.kms_key_name == kms_key_name

Consulta una tabla protegida por una clave de Cloud KMS

No se necesitan arreglos especiales a fin de consultar una tabla protegida por Cloud KMS. BigQuery almacena el nombre de la clave que se usó para encriptar el contenido de la tabla y la usará cuando se consulte una tabla que protege Cloud KMS.

Todas las herramientas existentes, la consola de BigQuery y la herramienta de línea de comandos de bq se ejecutan de la misma manera que con las tablas encriptadas de forma predeterminada, siempre que BigQuery tenga acceso a la clave de Cloud KMS que se usó para encriptar el contenido de la tabla.

Protege resultados de consultas con una clave de Cloud KMS

Console

  1. Abre la página de BigQuery en Cloud Console.

    Ir a la página de BigQuery

  2. Haz clic en Redactar consulta nueva.

  3. Ingresa una consulta válida de SQL en BigQuery en el área de texto de consulta.

  4. Haz clic en Más, luego, en Configuración de consultas y, por último, en Opciones avanzadas.

  5. Selecciona Customer-managed encryption.

  6. Selecciona la llave. Si la clave que quieres usar no aparece en la lista, ingresa el ID de recurso de la clave.

  7. Haz clic en Guardar.

  8. Haz clic en Ejecutar.

bq

Especifica la marca --destination_kms_key para proteger la tabla de destino o los resultados de las consultas (si usas una tabla temporal) con tu clave de Cloud KMS. La marca --destination_kms_key especifica el ID de recurso de la clave que se debe usar con la tabla de destino o la tabla resultante.

De forma opcional, puedes usar la marca --destination_table para especificar el destino de los resultados de la consulta. Si --destination_table no se usa, los resultados de la consulta se escribirán en una tabla temporal.

Para consultar una tabla, sigue estos pasos:

bq query \
--destination_table=mydataset.newtable \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
"SELECT name,count FROM mydataset.babynames WHERE gender = 'M' ORDER BY count DESC LIMIT 6"

Para obtener más información sobre la herramienta de línea de comandos de bq, consulta Usa la herramienta de línea de comandos de bq.

Go

import (
	"context"
	"fmt"
	"io"

	"cloud.google.com/go/bigquery"
	"google.golang.org/api/iterator"
)

// queryWithDestinationCMEK demonstrates saving query results to a destination table and protecting those results
// by specifying a customer managed encryption key.
func queryWithDestinationCMEK(w io.Writer, projectID, dstDatasetID, dstTableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	q := client.Query("SELECT 17 as my_col")
	q.Location = "US" // Location must match the dataset(s) referenced in query.
	q.QueryConfig.Dst = client.Dataset(dstDatasetID).Table(dstTableID)
	q.DestinationEncryptionConfig = &bigquery.EncryptionConfig{
		// TODO: Replace this key with a key you have created in Cloud KMS.
		KMSKeyName: "projects/cloud-samples-tests/locations/us-central1/keyRings/test/cryptoKeys/test",
	}
	// Run the query and print results when the query job is completed.
	job, err := q.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	if err := status.Err(); err != nil {
		return err
	}
	it, err := job.Read(ctx)
	for {
		var row []bigquery.Value
		err := it.Next(&row)
		if err == iterator.Done {
			break
		}
		if err != nil {
			return err
		}
		fmt.Fprintln(w, row)
	}
	return nil
}

Java

Antes de probar este ejemplo, sigue las instrucciones de configuración para Java que se encuentran en la guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Si deseas obtener más información, consulta la documentación de referencia de la API de BigQuery para Java.

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.EncryptionConfiguration;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableResult;

// Sample to query on destination table with encryption key
public class QueryDestinationTableCMEK {

  public static void runQueryDestinationTableCMEK() {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String kmsKeyName = "MY_KMS_KEY_NAME";
    String query =
        String.format("SELECT stringField, booleanField FROM %s.%s", datasetName, tableName);
    EncryptionConfiguration encryption =
        EncryptionConfiguration.newBuilder().setKmsKeyName(kmsKeyName).build();
    queryDestinationTableCMEK(query, encryption);
  }

  public static void queryDestinationTableCMEK(String query, EncryptionConfiguration encryption) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      QueryJobConfiguration config =
          QueryJobConfiguration.newBuilder(query)
              // Set the encryption key to use for the destination.
              .setDestinationEncryptionConfiguration(encryption)
              .build();

      TableResult results = bigquery.query(config);

      results
          .iterateAll()
          .forEach(row -> row.forEach(val -> System.out.printf("%s,", val.toString())));
      System.out.println("Query performed successfully with encryption key.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Query not performed \n" + e.toString());
    }
  }
}

Python

from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the destination table.
# table_id = "your-project.your_dataset.your_table_name"

# Set the encryption key to use for the destination.
# TODO(developer): Replace this key with a key you have created in KMS.
# kms_key_name = "projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}".format(
#     your-project, location, your-ring, your-key
# )

job_config = bigquery.QueryJobConfig(
    destination=table_id,
    destination_encryption_configuration=bigquery.EncryptionConfiguration(
        kms_key_name=kms_key_name
    ),
)

# Start the query, passing in the extra configuration.
query_job = client.query(
    "SELECT 17 AS my_col;", job_config=job_config
)  # Make an API request.
query_job.result()  # Wait for the job to complete.

table = client.get_table(table_id)  # Make an API request.
if table.encryption_configuration.kms_key_name == kms_key_name:
    print("The destination table is written using the encryption configuration")

Carga una tabla protegida por Cloud KMS

Para cargar un archivo de datos en una tabla protegida por Cloud KMS, sigue estos pasos:

Console

Especifica la clave cuando cargues una tabla de destino del trabajo de carga para protegerla con una clave de encriptación administrada por el cliente.

  1. Abre la página de BigQuery en Cloud Console.

    Ir a la página BigQuery

  2. En el panel de navegación, en la sección Recursos, expande tu proyecto y selecciona un conjunto de datos.

  3. En el lado derecho de la ventana, en el panel de detalles, haz clic en Crear tabla.

  4. Ingresa las opciones que deseas usar para cargar la tabla, pero antes de hacer clic en Crear tabla, haz clic en Opciones avanzadas (Advanced options).

  5. En Encriptación (Encryption), selecciona Clave administrada por el cliente (Customer-managed key).

  6. Haz clic en la lista desplegable Selecciona una clave administrada por el cliente (Select a customer-managed key) y selecciona la clave que deseas usar. Si no hay claves disponibles, ingresa un ID de recurso de la clave.

    Opciones avanzadas

  7. Haz clic en Crear tabla.

bq

Para proteger una tabla de destino del trabajo de carga con una clave de encriptación administrada por el cliente, configura la marca --destination_kms_key.

bq --location=LOCATION load \
--autodetect \
--source_format=FORMAT \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
DATASET.TABLE \
path_to_source
Por ejemplo:
bq load \
--autodetect \
--source_format=NEWLINE_DELIMITED_JSON \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
test2.table4 \
gs://cloud-samples-data/bigquery/us-states/us-states.json

Go

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// importJSONWithCMEK demonstrates loading newline-delimited JSON from Cloud Storage,
// and protecting the data with a customer-managed encryption key.
func importJSONWithCMEK(projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	gcsRef := bigquery.NewGCSReference("gs://cloud-samples-data/bigquery/us-states/us-states.json")
	gcsRef.SourceFormat = bigquery.JSON
	gcsRef.AutoDetect = true
	loader := client.Dataset(datasetID).Table(tableID).LoaderFrom(gcsRef)
	loader.WriteDisposition = bigquery.WriteEmpty
	loader.DestinationEncryptionConfig = &bigquery.EncryptionConfig{
		// TODO: Replace this key with a key you have created in KMS.
		KMSKeyName: "projects/cloud-samples-tests/locations/us-central1/keyRings/test/cryptoKeys/test",
	}

	job, err := loader.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}

	if status.Err() != nil {
		return fmt.Errorf("job completed with error: %v", status.Err())
	}

	return nil
}

Java

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.EncryptionConfiguration;
import com.google.cloud.bigquery.FormatOptions;
import com.google.cloud.bigquery.Job;
import com.google.cloud.bigquery.JobInfo;
import com.google.cloud.bigquery.LoadJobConfiguration;
import com.google.cloud.bigquery.TableId;

// Sample to load JSON data with configuration key from Cloud Storage into a new BigQuery table
public class LoadJsonFromGCSCMEK {

  public static void runLoadJsonFromGCSCMEK() {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String kmsKeyName = "MY_KMS_KEY_NAME";
    String sourceUri = "gs://cloud-samples-data/bigquery/us-states/us-states.json";
    // i.e. projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{cryptoKey}
    EncryptionConfiguration encryption =
        EncryptionConfiguration.newBuilder().setKmsKeyName(kmsKeyName).build();
    loadJsonFromGCSCMEK(datasetName, tableName, sourceUri, encryption);
  }

  public static void loadJsonFromGCSCMEK(
      String datasetName, String tableName, String sourceUri, EncryptionConfiguration encryption) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      TableId tableId = TableId.of(datasetName, tableName);
      LoadJobConfiguration loadConfig =
          LoadJobConfiguration.newBuilder(tableId, sourceUri)
              // Set the encryption key to use for the destination.
              .setDestinationEncryptionConfiguration(encryption)
              .setFormatOptions(FormatOptions.json())
              .setAutodetect(true)
              .build();

      // Load data from a GCS JSON file into the table
      Job job = bigquery.create(JobInfo.of(loadConfig));
      // Blocks until this load table job completes its execution, either failing or succeeding.
      job = job.waitFor();
      if (job.isDone()) {
        System.out.println("Table loaded succesfully from GCS with configuration key");
      } else {
        System.out.println(
            "BigQuery was unable to load into the table due to an error:"
                + job.getStatus().getError());
      }
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Column not added during load append \n" + e.toString());
    }
  }
}

Python

Para proteger una tabla de destino del trabajo de carga con una clave de encriptación administrada por el cliente, configura la propiedad LoadJobConfig.destination_encryption_configuration como una EncryptionConfiguration y carga la tabla.

from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set table_id to the ID of the table to create.
# table_id = "your-project.your_dataset.your_table_name

# Set the encryption key to use for the destination.
# TODO: Replace this key with a key you have created in KMS.
# kms_key_name = "projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}".format(
#     "cloud-samples-tests", "us", "test", "test"
# )

job_config = bigquery.LoadJobConfig(
    autodetect=True,
    source_format=bigquery.SourceFormat.NEWLINE_DELIMITED_JSON,
    destination_encryption_configuration=bigquery.EncryptionConfiguration(
        kms_key_name=kms_key_name
    ),
)

uri = "gs://cloud-samples-data/bigquery/us-states/us-states.json"

load_job = client.load_table_from_uri(
    uri,
    table_id,
    location="US",  # Must match the destination dataset location.
    job_config=job_config,
)  # Make an API request.

assert load_job.job_type == "load"

load_job.result()  # Waits for the job to complete.

assert load_job.state == "DONE"
table = client.get_table(table_id)

if table.encryption_configuration.kms_key_name == kms_key_name:
    print("A table loaded with encryption configuration key")

Transmite datos en una tabla protegida por Cloud KMS

Puedes transmitir datos a tu tabla de BigQuery protegida por CMEK sin especificar ningún parámetro adicional. Ten en cuenta que estos datos se encriptaron con tu clave de Cloud KMS en el búfer, así como en la ubicación final. Antes de usar la transmisión con una tabla de CMEK, revisa los requisitos sobre la disponibilidad y accesibilidad de la clave.

Para obtener más información sobre la transmisión, consulta Transmite datos a BigQuery.

Cambia una tabla de encriptación predeterminada a protección de Cloud KMS

bq

Puedes usar el comando bq cp con la marca --destination_kms_key para copiar una tabla protegida por encriptación predeterminada en una tabla nueva o en la tabla original, protegida por Cloud KMS. La marca --destination_kms_key especifica el ID de recurso de la clave que se debe usar con la tabla de destino.

Para copiar una tabla con encriptación predeterminada a una tabla nueva con protección de Cloud KMS, usa un comando como este:

bq cp \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
sourceDataset.sourceTableId destinationDataset.destinationTableId

Si quieres copiar una tabla con encriptación predeterminada a la misma tabla con la protección de Cloud KMS, usa un comando como este:

bq cp -f \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
sourceDataset.sourceTableId sourceDataset.sourceTableId

Si deseas cambiar la protección de una tabla de Cloud KMS a la encriptación predeterminada, copia el archivo a sí mismo y ejecuta bq cp sin la marca --destination_kms_key.

Para obtener más información sobre la herramienta de línea de comandos de bq, consulta Usa la herramienta de línea de comandos de bq.

Go

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// copyTableWithCMEK demonstrates creating a copy of a table and ensuring the copied data is
// protected with a customer managed encryption key.
func copyTableWithCMEK(projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydataset"
	// tableID := "mytable"
	ctx := context.Background()
	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	srcTable := client.DatasetInProject("bigquery-public-data", "samples").Table("shakespeare")
	copier := client.Dataset(datasetID).Table(tableID).CopierFrom(srcTable)
	copier.DestinationEncryptionConfig = &bigquery.EncryptionConfig{
		// TODO: Replace this key with a key you have created in Cloud KMS.
		KMSKeyName: "projects/cloud-samples-tests/locations/us-central1/keyRings/test/cryptoKeys/test",
	}
	job, err := copier.Run(ctx)
	if err != nil {
		return err
	}
	status, err := job.Wait(ctx)
	if err != nil {
		return err
	}
	if err := status.Err(); err != nil {
		return err
	}
	return nil
}

Java

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.CopyJobConfiguration;
import com.google.cloud.bigquery.EncryptionConfiguration;
import com.google.cloud.bigquery.Job;
import com.google.cloud.bigquery.JobInfo;
import com.google.cloud.bigquery.TableId;

// Sample to copy a cmek table
public class CopyTableCMEK {

  public static void runCopyTableCMEK() {
    // TODO(developer): Replace these variables before running the sample.
    String destinationDatasetName = "MY_DESTINATION_DATASET_NAME";
    String destinationTableId = "MY_DESTINATION_TABLE_NAME";
    String sourceDatasetName = "MY_SOURCE_DATASET_NAME";
    String sourceTableId = "MY_SOURCE_TABLE_NAME";
    String kmsKeyName = "MY_KMS_KEY_NAME";
    EncryptionConfiguration encryption =
        EncryptionConfiguration.newBuilder().setKmsKeyName(kmsKeyName).build();
    copyTableCMEK(
        sourceDatasetName, sourceTableId, destinationDatasetName, destinationTableId, encryption);
  }

  public static void copyTableCMEK(
      String sourceDatasetName,
      String sourceTableId,
      String destinationDatasetName,
      String destinationTableId,
      EncryptionConfiguration encryption) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      TableId sourceTable = TableId.of(sourceDatasetName, sourceTableId);
      TableId destinationTable = TableId.of(destinationDatasetName, destinationTableId);

      // For more information on CopyJobConfiguration see:
      // https://googleapis.dev/java/google-cloud-clients/latest/com/google/cloud/bigquery/JobConfiguration.html
      CopyJobConfiguration configuration =
          CopyJobConfiguration.newBuilder(destinationTable, sourceTable)
              .setDestinationEncryptionConfiguration(encryption)
              .build();

      // For more information on Job see:
      // https://googleapis.dev/java/google-cloud-clients/latest/index.html?com/google/cloud/bigquery/package-summary.html
      Job job = bigquery.create(JobInfo.of(configuration));

      // Blocks until this job completes its execution, either failing or succeeding.
      Job completedJob = job.waitFor();
      if (completedJob == null) {
        System.out.println("Job not executed since it no longer exists.");
        return;
      } else if (completedJob.getStatus().getError() != null) {
        System.out.println(
            "BigQuery was unable to copy table due to an error: \n" + job.getStatus().getError());
        return;
      }
      System.out.println("Table cmek copied successfully.");
    } catch (BigQueryException | InterruptedException e) {
      System.out.println("Table cmek copying job was interrupted. \n" + e.toString());
    }
  }
}

Python

Antes de probar esta muestra, sigue las instrucciones de configuración para Python incluidas en la Guía de inicio rápido de BigQuery sobre cómo usar bibliotecas cliente. Si deseas obtener más información, consulta la documentación de referencia de la API de BigQuery para Python.

Para proteger el destino de una copia de tabla con una clave de encriptación administrada por el cliente, configura la propiedad QueryJobConfig.destination_encryption_configuration como una EncryptionConfiguration y copia la tabla.

from google.cloud import bigquery

# Construct a BigQuery client object.
client = bigquery.Client()

# TODO(developer): Set dest_table_id to the ID of the destination table.
# dest_table_id = "your-project.your_dataset.your_table_name"

# TODO(developer): Set orig_table_id to the ID of the original table.
# orig_table_id = "your-project.your_dataset.your_table_name"

# Set the encryption key to use for the destination.
# TODO(developer): Replace this key with a key you have created in KMS.
# kms_key_name = "projects/{}/locations/{}/keyRings/{}/cryptoKeys/{}".format(
#     your-project, location, your-ring, your-key
# )

job_config = bigquery.CopyJobConfig(
    destination_encryption_configuration=bigquery.EncryptionConfiguration(
        kms_key_name=kms_key_name
    )
)
job = client.copy_table(orig_table_id, dest_table_id, job_config=job_config)
job.result()  # Wait for the job to complete.

dest_table = client.get_table(dest_table_id)  # Make an API request.
if dest_table.encryption_configuration.kms_key_name == kms_key_name:
    print("A copy of the table created")

Determina si una tabla está protegida por Cloud KMS

  1. En Cloud Console, haz clic en la flecha azul a la izquierda del conjunto de datos para expandirlo, o haz doble clic en el nombre del conjunto. Esto muestra las tablas y vistas en el conjunto de datos.

  2. Haz clic en el nombre de la tabla.

  3. Haz clic en Detalles. En la página Detalles de la tabla, se muestra la descripción y la información de la tabla.

  4. Si la tabla está protegida por Cloud KMS, el campo Customer-Managed Encryption Key mostrará el ID de recurso de la clave.

    Tabla protegida

Cambia la clave de Cloud KMS de una tabla de BigQuery

Si deseas cambiar la clave de Cloud KMS de una tabla existente protegida con CMEK, puedes ejecutar una consulta ALTER TABLE, usar la API o usar la herramienta de línea de comandos de bq. Hay dos maneras de modificar la clave de Cloud KMS mediante la API y la herramienta de línea de comandos de bq: update o cp. Si usas update, puedes cambiar la clave de Cloud KMS que se usa para una tabla protegida con KMS. Si usas cp, puedes cambiar la clave de Cloud KMS que se usa para una tabla protegida con CMEK, cambiar una tabla de la encriptación predeterminada a la protección con CMEK y, también, cambiar una tabla protegida con CMEK a la encriptación predeterminada. Una ventaja de update es que es más rápido que cp y te permite usar decoradores de tabla.

Console

  1. Abre la página de BigQuery en Cloud Console.

    Ir a la página de BigQuery

  2. Haz clic en Redactar consulta nueva.

  3. Escribe tu declaración DDL en el área de texto Consulta nueva. Para el valor kms_key_name, especifica el ID de recurso de la clave que quieres usar a fin de proteger la tabla.

    #standardSQL
    ALTER TABLE mydataset.mytable
    SET OPTIONS (
    kms_key_name="projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY"
    )
    
  4. Haz clic en Ejecutar.

bq

Puedes usar el comando bq cp con la marca --destination_kms_key para cambiar la clave de una tabla que tiene protección de Cloud KMS. La marca --destination_kms_key especifica el ID de recurso de la clave que se debe usar con la tabla.

bq update \
--destination_kms_key projects/PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
-t DATASET_ID.TABLE_ID

Go

import (
	"context"
	"fmt"

	"cloud.google.com/go/bigquery"
)

// updateTableChangeCMEK demonstrates how to change the customer managed encryption key that protects a table.
func updateTableChangeCMEK(projectID, datasetID, tableID string) error {
	// projectID := "my-project-id"
	// datasetID := "mydatasetid"
	// tableID := "mytableid"
	ctx := context.Background()

	client, err := bigquery.NewClient(ctx, projectID)
	if err != nil {
		return fmt.Errorf("bigquery.NewClient: %v", err)
	}
	defer client.Close()

	tableRef := client.Dataset(datasetID).Table(tableID)
	meta, err := tableRef.Metadata(ctx)
	if err != nil {
		return err
	}
	update := bigquery.TableMetadataToUpdate{
		EncryptionConfig: &bigquery.EncryptionConfig{
			// TODO: Replace this key with a key you have created in Cloud KMS.
			KMSKeyName: "projects/cloud-samples-tests/locations/us-central1/keyRings/test/cryptoKeys/otherkey",
		},
	}
	if _, err := tableRef.Update(ctx, update, meta.ETag); err != nil {
		return err
	}
	return nil
}

Java

import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.EncryptionConfiguration;
import com.google.cloud.bigquery.Table;
import com.google.cloud.bigquery.TableId;

// Sample to update a cmek table
public class UpdateTableCMEK {

  public static void runUpdateTableCMEK() {
    // TODO(developer): Replace these variables before running the sample.
    String datasetName = "MY_DATASET_NAME";
    String tableName = "MY_TABLE_NAME";
    String kmsKeyName = "MY_KEY_NAME";
    // Set a new encryption key to use for the destination.
    // i.e. projects/{project}/locations/{location}/keyRings/{key_ring}/cryptoKeys/{cryptoKey}
    EncryptionConfiguration encryption =
        EncryptionConfiguration.newBuilder().setKmsKeyName(kmsKeyName).build();
    updateTableCMEK(datasetName, tableName, encryption);
  }

  public static void updateTableCMEK(
      String datasetName, String tableName, EncryptionConfiguration encryption) {
    try {
      // Initialize client that will be used to send requests. This client only needs to be created
      // once, and can be reused for multiple requests.
      BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();

      Table table = bigquery.getTable(TableId.of(datasetName, tableName));
      bigquery.update(table.toBuilder().setEncryptionConfiguration(encryption).build());
      System.out.println("Table cmek updated successfully");
    } catch (BigQueryException e) {
      System.out.println("Table cmek was not updated. \n" + e.toString());
    }
  }
}

Python

Para cambiar la clave de encriptación administrada por el cliente de una tabla, cambia la propiedad Table.encryption_configuration a un objeto EncryptionConfiguration nuevo y actualiza la tabla.

# from google.cloud import bigquery
# client = bigquery.Client()

assert table.encryption_configuration.kms_key_name == original_kms_key_name

# Set a new encryption key to use for the destination.
# TODO: Replace this key with a key you have created in KMS.
updated_kms_key_name = (
    "projects/cloud-samples-tests/locations/us/keyRings/test/cryptoKeys/otherkey"
)
table.encryption_configuration = bigquery.EncryptionConfiguration(
    kms_key_name=updated_kms_key_name
)

table = client.update_table(table, ["encryption_configuration"])  # API request

assert table.encryption_configuration.kms_key_name == updated_kms_key_name
assert original_kms_key_name != updated_kms_key_name

Configura una clave predeterminada para el conjunto de datos

Puedes configurar una clave de Cloud KMS predeterminada para todo el conjunto de datos que se aplicará a todas las tablas recién creadas dentro de este, a menos que se especifique una clave de Cloud KMS diferente cuando se crea la tabla. La clave predeterminada no se aplica a las tablas existentes. Cambiar la clave predeterminada no modifica las tablas existentes y solo se aplica a las tablas nuevas creadas después del cambio.

Tienes las siguientes opciones para aplicar una clave predeterminada a un conjunto de datos, cambiarla o quitarla:

Quita el acceso de BigQuery a la clave de Cloud KMS

Puedes quitar el acceso de BigQuery a la clave de Cloud KMS en cualquier momento si revocas el permiso de IAM de esa clave.

Si BigQuery pierde acceso a la clave de Cloud KMS, la experiencia del usuario puede verse afectada de manera significativa, y es posible que se pierdan datos:

  • Ya no se podrá acceder a los datos de estas tablas protegidas con CMEK. Los comandos query, cp, extract y tabledata.list fallarán.

  • No se podrán agregar datos nuevos a estas tablas protegidas con CMEK.

  • Después de otorgar el acceso otra vez, el rendimiento de las consultas a estas tablas queda degradado durante varios días.

Efecto de la rotación de claves de Cloud KMS

BigQuery no rota la clave de encriptación de una tabla de forma automática cuando se rota una clave de Cloud KMS asociada a la tabla. Las tablas existentes continúan usando la versión de la clave con la que se crearon. Las tablas nuevas usan la versión actual de la clave.

Limitaciones

Acceso de BigQuery a la clave de Cloud KMS

Se considera que una clave de Cloud KMS está disponible y que BigQuery puede acceder a ella si se dan las siguientes condiciones:

  • La clave está habilitada.
  • La cuenta de servicio de BigQuery tiene permisos de encriptación y desencriptación en la clave.

En las secciones que se incluyen a continuación, se describe el impacto en las inserciones de transmisión y los datos inaccesibles a largo plazo cuando no se puede acceder a una clave.

Impacto en las inserciones de transmisión

La clave de Cloud KMS debe estar disponible y se debe tener acceso a ella durante al menos 24 horas consecutivas en el período de 48 horas posterior a una solicitud de inserción de transmisión. Si la clave no está disponible o no se puede acceder a ella, puede que los datos transmitidos se pierdan por no ser completamente persistentes. Para obtener más información sobre la inserción de transmisión, consulta Transmite datos a BigQuery.

Impacto en los datos inaccesibles a largo plazo

Como BigQuery proporciona almacenamiento administrado, los datos inaccesibles a largo plazo no son compatibles con su arquitectura. Si la clave de Cloud KMS de una tabla de BigQuery determinada no está disponible y no se puede acceder a ella durante 60 días consecutivos, BigQuery podría optar por borrar la tabla y sus datos asociados. Al menos 7 días antes de que se borren los datos, BigQuery envía un correo electrónico a la dirección de correo electrónico que está asociada a la cuenta de facturación.

Usa decoradores de tablas

Cuando los datos de una tabla protegida con Cloud KMS se reemplazan mediante la disposición de escritura WRITE_TRUNCATE en las operaciones load, cp o query, no se puede acceder a la tabla para la consulta mediante decoradores de tabla, que dependen del tiempo del decorador de instantáneas.

Si suponemos que se reemplazó una tabla en el momento T, y que el decorador de instantáneas snapshot_time es para un tiempo menor que T, la siguiente tabla muestra si puedes consultar durante snapshot_time:

Tipo de encriptación antes de T Tipo de encriptación después de T snapshot_time
Con encriptación de Cloud KMS Con encriptación de Cloud KMS No se puede consultar
Con encriptación predeterminada Con encriptación de Cloud KMS Se puede consultar
Con encriptación de Cloud KMS Con encriptación predeterminada No se puede consultar

Ten en cuenta que una lógica similar se aplica a <time2> cuando se usa un decorador de rango.

Preguntas frecuentes

¿Quién necesita permiso para la clave de Cloud KMS?

Con las claves de encriptación administradas por el cliente, no se necesita especificar permisos repetidas veces. Siempre que la cuenta de servicio de BigQuery tenga permiso para usar la clave de Cloud KMS a fin de encriptar y desencriptar, cualquier persona con permiso en la tabla de BigQuery puede acceder a los datos, incluso si no tienen acceso directo a la clave de Cloud KMS.

¿Qué cuenta de servicio se usa?

La cuenta de servicio de BigQuery asociada con el proyecto de Cloud de la tabla se usa para desencriptar los datos de la tabla. Las cuentas de servicio de BigQuery son únicas para cada proyecto. En el caso de un trabajo que escribe datos en una tabla anónima con protección de Cloud KMS, se usa la cuenta de servicio correspondiente al proyecto de ese trabajo.

Como ejemplo, considera tres tablas protegidas por CMEK: table1, table2 y table3. Para consultar datos desde {project1.table1, project2.table2} con la tabla de destino {project3.table3}:

  • Usa la cuenta de servicio de project1 para project1.table1.
  • Usa la cuenta de servicio de project2 para project2.table2.
  • Usa la cuenta de servicio de project3 para project3.table3.

¿Cómo puede usar BigQuery mi clave de Cloud KMS?

BigQuery usará la clave de Cloud KMS para desencriptar datos en respuesta a una consulta del usuario, como tabledata.list o jobs.insert.

BigQuery también puede usar la clave para realizar mantenimiento de datos y tareas de optimización de almacenamiento, como la conversión de datos a un formato optimizado para la lectura.

¿Qué bibliotecas de criptografía se usan?

BigQuery utiliza de Cloud KMS para la funcionalidad de CMEK. Cloud KMS usa Tink para la encriptación.

¿Cómo obtener más ayuda?

Si tienes preguntas que no aparecen aquí, consulta Asistencia de BigQuery o Asistencia de Cloud KMS.

Soluciona errores

A continuación, se describen errores comunes y mitigaciones recomendadas.

Error Recomendación
Otorga la función de Encriptador/Desencriptador claves de encriptación de Cloud KMS. La cuenta de servicio de BigQuery asociada a tu proyecto no tiene los permisos de IAM suficientes para operar en la clave de Cloud KMS especificada. Sigue las instrucciones en el error o en esta documentación para otorgar los permisos de IAM adecuados.
Las opciones de configuración de encriptación de la tabla existentes no coinciden con las opciones de configuración de encriptación que se especificaron en la solicitud. Esto puede suceder en situaciones en que la tabla de destino tiene una configuración de encriptación que no coincide con la configuración de encriptación en tu solicitud. Como mitigación, use la disposición de escritura TRUNCATE para reemplazar la tabla o especifica una tabla de destino diferente.
Esta región no es compatible. La región de la clave de Cloud KMS no coincide con la región del conjunto de datos de BigQuery de la tabla de destino. Como mitigación, selecciona una clave en una región que coincida con tu conjunto de datos o carga en un conjunto de datos que coincida con la región de la clave.