使用 Cloud KMS 密钥保护数据

默认情况下,BigQuery 会对以静态方式存储的客户内容进行加密。BigQuery 会为您处理和管理这项默认加密作业,您无需进行任何其他操作。首先,系统会使用“数据加密密钥”(DEK) 对 BigQuery 表中的数据进行加密。然后,通过"密钥加密密钥" (KEK) 来对 DEK 进行加密(这称为信封加密)。KEK 不用于直接加密您的数据,而是用于对 Google 用来加密您数据的 DEK 进行加密。如需了解详情,请参阅密钥管理

如果您想自行控制加密,可为 BigQuery 使用客户管理的加密密钥 (CMEK)。您自行控制和管理 Cloud KMS 中保护您数据的密钥加密密钥 (KEK),而不是由 Google 管理。本主题将提供有关这一用法的详细信息。

详细了解 Google Cloud 的加密选项

准备工作

  1. 了解数据集查询

  2. 确定您要在同一个 Google Cloud 项目中还是在不同项目中运行 BigQuery 和 Cloud KMS。为了方便说明,本文的示例将采用下列惯例:

    • project_id 是运行 BigQuery 的项目的 ID
    • project_number 是运行 BigQuery 的项目的编号
    • kms_project_id 是运行 Cloud KMS 的项目的 ID(即使该项目就是运行 BigQuery 的同一个项目)
    如需了解 Google Cloud 项目 ID 和项目编号,请参阅识别项目

  3. 新项目中会自动启用 BigQuery。如果您使用现有项目来运行 BigQuery,请启用 BigQuery API

  4. 对于运行 Cloud KMS 的 Google Cloud 项目:

    1. 启用 Cloud KMS API
    2. 按照创建密钥环和密钥中的说明创建密钥环和密钥。请在与 BigQuery 数据集的位置匹配的位置创建密钥环:
      • 任何多区域数据集都应使用来自匹配位置的多区域密钥环。例如,应使用区域 us 中的密钥环保护位于区域 US 的数据集,使用区域 europe 中的密钥环保护位于区域 EU 的数据集。
      • 区域数据集应使用匹配的区域密钥。例如,应使用区域 asia-northeast1 中的密钥环保护位于区域 asia-northeast1 的数据集。
      • global 区域不支持使用 BigQuery。
      如需详细了解支持 BigQuery 和 Cloud KMS 的位置,请参阅 Cloud 位置

加密规范

用于保护您在 BigQuery 中的数据的 Cloud KMS 密钥是 AES-256 密钥。这类密钥在 BigQuery 中被用作 KEK,其用途是对加密您数据的 DEK 进行加密。

授予加密和解密权限

使用 Google Cloud Console 确定 BigQuery 服务帐号 ID,并为服务帐号提供适当的角色,以使用 Cloud KMS 进行加密和解密。

确定服务帐号 ID

经典版界面

  1. 转到 BigQuery 网页界面。

    转到 BigQuery 网页界面

  2. 在导航窗格中,点击项目名称旁边的向下箭头图标 向下箭头图标,然后点击 Customer-Managed Encryption

  3. 此时,系统会打开用户对话框,显示需要加密和解密权限的服务帐号:

    服务帐号 ID

  4. 点击 Copy 以将服务帐号 ID 复制到剪贴板,然后点击 OK 以关闭用户对话框。

CLI

您可以将 bq show 命令与 --encryption_service_account 标志结合使用以确定服务帐号 ID。

bq show --encryption_service_account

该命令会显示服务帐号 ID:

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

分配 Encrypter/Decrypter 角色

Cloud KMS CryptoKey Encrypter/Decrypter 角色分配给您已复制到剪贴板的 BigQuery 系统服务帐号。该帐号的格式如下:

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

控制台

  1. 在 Cloud Console 中打开安全页面。

    打开“安全加密密钥”页面

  2. 选择您的项目并点击继续

  3. 确定要向其添加角色的加密密钥。

    • 如果 bq-project_number@bigquery-encryption.iam.gserviceaccount.com 服务帐号不在成员列表中,则表明该帐号还未被分配任何角色。请点击添加成员,然后输入该服务帐号的电子邮件地址 bq-project_number@bigquery-encryption.iam.gserviceaccount.com
    • 如果该服务帐号已在成员列表中,则表明该帐号已被分配角色。点击 bq-project_number@bigquery-encryption.iam.gserviceaccount.com 服务帐号的当前角色下拉列表。
  4. 依次点击角色下拉列表、Cloud KMSCloud KMS CryptoKey Encrypter/Decrypter 角色。

  5. 点击添加保存以将该角色应用于 bq-project_number@bigquery-encryption.iam.gserviceaccount.com 服务帐号。

CLI

您可以使用 gcloud 命令行工具分配该角色:

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

kms_project_id 替换为运行 Cloud KMS 的 Google Cloud 项目的 ID,将 project_number 替换为运行 BigQuery 的 Google Cloud 项目的项目号(而非项目 ID),然后将 kms_key_locationkms_key_ringkms_key 分别替换为 Cloud KMS 密钥的位置、密钥环和密钥名称。

密钥资源 ID

使用 CMEK 时需要 Cloud KMS 密钥的资源 ID,如本主题的示例所示。此密钥的格式如下:

projects/project_id/locations/location/keyRings/key_ring/cryptoKeys/key

如需了解如何检索密钥资源 ID,请参阅密钥资源 ID

创建受 Cloud KMS 保护的表

创建受 Cloud KMS 保护的空表

要创建受 Cloud KMS 保护的表,请执行以下操作:

经典版界面

  1. 点击 BigQuery 网页界面中数据集名称旁边的向下箭头图标 向下箭头图标,然后点击 Create new table

  2. Create table 页面上,填写创建具有架构定义的空表所需的信息。在您点击 Create table 之前,请设置加密类型并指定要用于表的 Cloud KMS 密钥:

    1. 点击 Encryption Type 下拉列表,并选择 Customer-Managed Encryption
    2. 对于 Customer-Managed Encryption Key,输入密钥的资源 ID
  3. 点击 Create Table

CLI

您可以将 bq 命令行工具与 --destination_kms_key 标志结合使用以创建表。--destination_kms_key 标志指定用于表的密钥的资源 ID

如需创建具有架构的空表,请使用以下命令:

bq mk --schema name:string,value:integer -t \
--destination_kms_key projects/project_id/locations/location/keyRings/key_ring/cryptoKeys/key \
mydataset.newtable

或者,您可以使用 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'
  )
"

如需基于查询创建表,请使用以下命令:

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"

如需详细了解 bq 命令行工具,请参阅 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
}

Python

在创建表之前,将 Table.encryption_configuration 属性设置为 EncryptionConfiguration 对象,以使用 CMEK 保护新表。

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

table_ref = client.dataset(dataset_id).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

查询受 Cloud KMS 密钥保护的表

查询受 Cloud KMS 保护的表无需特殊操作安排。BigQuery 会存储用于加密表内容的密钥的名称,并在受 Cloud KMS 保护的表被查询时使用该密钥。

所有现有工具、BigQuery 控制台和 bq 命令行界面都与默认加密表的运行方式相同,前提是 BigQuery 能够访问用于加密表内容的 Cloud KMS 密钥。

使用 Cloud KMS 密钥保护查询结果

经典版界面

  1. 点击 BigQuery 网页界面中的 Compose query 按钮。

  2. New Query 文本区域中输入有效的 BigQuery SQL 查询。

  3. 点击 Encryption Type,然后选择 Customer-Managed Encryption

  4. 对于 Customer-Managed Encryption Key,输入密钥的资源 ID

  5. 点击 Run Query

CLI

使用 Cloud KMS 密钥指定标记 --destination_kms_key 以保护目标表或查询结果(如果使用临时表)。--destination_kms_key 标志指定用于目标表或生成的表的密钥的资源 ID

您可以选择使用 --destination_table 标志为查询结果指定目标。如果未使用 --destination_table,查询结果将写入临时表中。

如需查询表,请使用以下命令:

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"

如需详细了解 bq 命令行工具,请参阅 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
}

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")

加载受 Cloud KMS 保护的表

要将数据文件加载到受 Cloud KMS 保护的表中,请使用以下方式:

控制台

在加载表时指定密钥,以使用 CMEK 保护加载作业的目标表。

  1. 在 Cloud Console 中打开 BigQuery 网页界面。
    转到 BigQuery 网页界面
  2. 在导航面板的资源部分中,展开您的项目并选择数据集。
  3. 在窗口右侧的详细信息面板中,点击创建表
  4. 输入要用于加载表的选项,但在点击创建表之前,请先点击高级选项
  5. 加密下选择客户管理的密钥
  6. 点击选择客户管理的密钥下拉列表,然后选择要使用的密钥。如果您没有看到任何可用的密钥,请输入密钥资源 ID

    高级选项

  7. 点击创建表

CLI

设置 --destination_kms_key 标志,以使用 CMEK 保护加载作业的目标表。

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
例如:
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
}

Python

LoadJobConfig.destination_encryption_configuration 属性设置为 EncryptionConfiguration 并加载表,以使用 CMEK 保护加载作业的目标表。

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

dataset_ref = client.dataset(dataset_id)
job_config = bigquery.LoadJobConfig()
job_config.autodetect = True
job_config.source_format = bigquery.SourceFormat.NEWLINE_DELIMITED_JSON

# 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"
)
encryption_config = bigquery.EncryptionConfiguration(kms_key_name=kms_key_name)
job_config.destination_encryption_configuration = encryption_config
uri = "gs://cloud-samples-data/bigquery/us-states/us-states.json"

load_job = client.load_table_from_uri(
    uri,
    dataset_ref.table("us_states"),
    location="US",  # Location must match that of the destination dataset.
    job_config=job_config,
)  # API request

assert load_job.job_type == "load"

load_job.result()  # Waits for table load to complete.

assert load_job.state == "DONE"
table = client.get_table(dataset_ref.table("us_states"))
assert table.encryption_configuration.kms_key_name == kms_key_name

将数据流式插入受 Cloud KMS 保护的表

您可以将数据流式插入受 CMEK 保护的 BigQuery 表中,而无需指定任何其他参数。请注意,系统将使用 Cloud KMS 密钥对缓冲区和最终位置中的此类数据进行加密。在将数据流式插入到 CMEK 表之前,请先查看密钥可用性和可访问性所述的要求。

如需详细了解流式插入,请参阅将数据流式插入 BigQuery 中

将表从默认加密更改为 Cloud KMS 保护

CLI

您可以使用带 --destination_kms_key 标记的 bq cp 命令将受默认加密保护的表复制到新表或受 Cloud KMS 保护的原始表中。--destination_kms_key 标志指定要用于目标表的密钥的资源 ID

要将采用默认加密方式的表复制到受 Cloud KMS 保护的新表,请使用以下命令:

bq cp \
--destination_kms_key projects/project_id/locations/location/keyRings/key_ring/cryptoKeys/key \
sourceDataset.sourceTableId destinationDataset.destinationTableId

要将采用默认加密方式的表复制到受 Cloud KMS 保护的相同表,请使用以下命令:

bq cp -f \
--destination_kms_key projects/project_id/locations/location/keyRings/key_ring/cryptoKeys/key \
sourceDataset.sourceTableId sourceDataset.sourceTableId

如果您想将表格从 Cloud KMS 保护更改为默认加密,请在不使用 --destination_kms_key 标记的情况下运行 bq cp,将文件复制到自身。

如需详细了解 bq 命令行工具,请参阅 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
}

Python

在尝试此示例之前,请按照《BigQuery 快速入门:使用客户端库》中的 Python 设置说明进行操作。如需了解详情,请参阅 BigQuery Python API 参考文档

QueryJobConfig.destination_encryption_configuration 属性设置为 EncryptionConfiguration 以使用 CMEK 保护表副本的目标,然后再复制表。

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")

确定表是否受 Cloud KMS 保护

  1. 在 BigQuery 网页界面中,点击数据集左侧的蓝色箭头以展开数据集,或双击数据集名称。这将显示数据集中的表和视图。

  2. 点击表名称。

  3. 点击 DetailsTable Details 页面会显示表说明和表信息。

  4. 如果表受 Cloud KMS 保护,则 Customer-Managed Encryption Key 字段将显示密钥资源 ID。

    受保护的表

更改 BigQuery 表的 Cloud KMS 密钥

要更改现有受 CMEK 保护的表的 Cloud KMS 密钥,您可以运行 ALTER TABLE 查询,使用 API 或使用 bq 命令行工具。有两种使用 API 和命令行工具修改 Cloud KMS 密钥的方法:updatecp。如果使用 update,则可以更改用于受 KMS 保护的表的 Cloud KMS 密钥。如果使用 cp,则可以更改用于受 CMEK 保护的表的 Cloud KMS 密钥,将表从默认加密更改为 CMEK 保护,也可以将表从 CMEK 保护更改为默认加密。update 的一个优点是速度比 cp 更快,并且支持使用表装饰器

经典版界面

  1. 转到 BigQuery 网页界面。

    转到 BigQuery 网页界面

  2. 点击 Compose query

  3. New Query 文本区域中输入 DDL 语句。对于 kms_key_name 值,请指定要用于保护表的密钥的资源 ID

    #standardSQL
    ALTER TABLE mydataset.mytable
    SET OPTIONS (
    kms_key_name="projects/[PROJECT_ID]/locations/[LOCATION]/keyRings/[KEYRING]/cryptoKeys/[KEY]"
    )
    

CLI

您可以将 bq cp 命令与 --destination_kms_key 标志一起使用,以更改受 Cloud KMS 保护的表的密钥。--destination_kms_key 标志指定要用于表的密钥的资源 ID

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
}

Python

Table.encryption_configuration 属性更改为新的 EncryptionConfiguration 对象以更改表的 CMEK,然后再更新表。

# 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

设置数据集默认密钥

除非在创建表时指定了不同的 Cloud KMS 密钥,否则您可以设置数据集范围的默认 Cloud KMS 密钥,该密钥将应用到数据集中所有新创建的表。默认密钥不会应用到现有的表。如果更改默认密钥,则系统不会修改现有的任何表,并且更改后的密钥只会应用到更改默认密钥后创建的新表。

您可以通过以下方式应用、更改或移除数据集的默认密钥:

撤消 BigQuery 对 Cloud KMS 密钥的访问权限

您可以随时移除 BigQuery 对 Cloud KMS 密钥的访问权限,方法是撤消该密钥的 IAM 权限。

如果 BigQuery 失去对 Cloud KMS 密钥的访问权限,用户体验可能会受到严重影响,并且可能发生数据丢失:

  • 这些受 CMEK 保护的表中的数据将不再能够访问 - querycpextracttabledata.list 命令全部都将失败。

  • 新数据无法再添加到这些受 CMEK 保护的表中。

  • 即使重新授予访问权限,对这些表所执行的查询的性能也可能在数天内都有所下降。

Cloud KMS 密钥轮替的影响

当与表关联的 Cloud KMS 密钥轮替时,BigQuery 不会自动轮替表加密密钥。现有表继续使用创建时所用的密钥版本。新表将使用当前的密钥版本。

限制

BigQuery 对 Cloud KMS 密钥的访问权限

如果符合以下条件,Cloud KMS 密钥会被视为可由 BigQuery 使用和访问:

  • 密钥已启用
  • BigQuery 服务帐号拥有该密钥的加密和解密权限

以下部分介绍当密钥不可访问时,对流式插入和长期无法访问的数据所造成的影响。

对流式插入的影响

在流式插入请求之后的 48 小时内,Cloud KMS 密钥必须至少连续 24 小时可用且可访问。如果不能使用和访问密钥,流式插入的数据可能会无法完整保留,并且可能会丢失。如需详细了解流式插入,请参阅将数据流式插入到 BigQuery 中

对长期无法访问的数据的影响

由于 BigQuery 提供托管式存储空间,因此长期无法访问的数据与 BigQuery 的架构是不兼容的。如果连续 60 天无法使用和访问特定 BigQuery 表的 Cloud KMS 密钥,BigQuery 可能会选择删除该表及其关联的数据。在删除数据之前,BigQuery 会提前至少 7 天向与结算帐号关联的电子邮件地址发送电子邮件。

使用表修饰器

如果您通过为 loadcpquery 操作使用 WRITE_TRUNCATE 这一写入处置方式来替换受 Cloud KMS 保护的表中的数据,则根据快照修饰器时间,您可能无法通过表修饰器查询该表。

假设表在时间 T 被替换并且快照修饰器 snapshot_time 对应的时间小于 T,下表显示了您是否可以对 snapshot_time 进行查询:

T 之前的加密类型 T 之后的加密类型 snapshot_time
Cloud KMS 加密 Cloud KMS 加密 无法查询
默认加密 Cloud KMS 加密 可以查询
Cloud KMS 加密 默认加密 无法查询

请注意,当使用范围修饰器时,类似的逻辑也适用于 <time2>

常见问题解答

谁需要 Cloud KMS 密钥的权限?

使用 CMEK 时,您无需重复指定权限。只要 BigQuery 服务帐号有权使用 Cloud KMS 密钥进行加密和解密,任何拥有 BigQuery 表权限的人都可以访问数据(即使无法直接访问 Cloud KMS 密钥)。

使用哪个服务帐号?

与表的 Google Cloud 项目关联的 BigQuery 服务帐号将用于解密该表的数据。BigQuery 服务帐号对每个项目都是唯一的。如果作业将数据写入受 Cloud KMS 保护的匿名表中,则将使用该作业的项目的服务帐号。

例如,假设有三个受 CMEK 保护的表:table1table2table3。如需在将 {project3.table3} 用作目标表的情况下查询 {project1.table1, project2.table2} 中的数据,请按以下指示操作:

  • 对于 project1.table1,使用 project1 服务帐号
  • 对于 project2.table2,使用 project2 服务帐号
  • 对于 project3.table3,使用 project3 服务帐号

BigQuery 可以通过哪些方式使用我的 Cloud KMS 密钥?

BigQuery 将使用 Cloud KMS 密钥解密数据来响应用户查询,例如 tabledata.listjobs.insert

BigQuery 还可以将密钥用于数据维护和存储优化任务,例如将数据转换为读取优化格式。

使用了哪些加密库?

BigQuery 依赖于 Cloud KMS 来实现 CMEK 功能。 Cloud KMS 使用 Tink 进行加密。

如何获取更多帮助?

如果您还有尚未得到解答的其他疑问,请参阅 BigQuery 支持Cloud KMS 支持

排查错误

下面描述了常见错误和建议的缓解措施。

错误 建议
请授予 Cloud KMS CryptoKey Encrypter/Decrypter 角色 与项目关联的 BigQuery 服务帐号没有足够的 Cloud IAM 权限,无法对指定的 Cloud KMS 密钥执行操作。请按照错误消息或本文档中的说明进行操作,授予适当的 Cloud IAM 权限。
现有表加密设置与请求中指定的加密设置不匹配 如果目标表的加密设置与请求中的加密设置不匹配,则可能会发生这种情况。作为缓解措施,可使用 TRUNCATE 这一写入处置方式来替换该表,或指定其他目标表。
此区域不受支持 Cloud KMS 密钥的区域与目标表的 BigQuery 数据集的区域不匹配。作为缓解措施,可选择与数据集匹配的区域中的密钥,或加载与密钥区域匹配的数据集。