客戶管理的 Cloud KMS 金鑰

根據預設,BigQuery 會加密靜態儲存的內容。BigQuery 會為您處理並管理這個預設加密作業,您不必採取任何其他動作。首先,系統會使用「資料加密金鑰」對 BigQuery 資料表中的資料進行加密,然後使用「金鑰加密金鑰」為資料加密金鑰進行加密,這個方法稱為信封式加密。 金鑰加密金鑰不會直接加密您的資料,其用途是對 Google 用來加密您資料的資料加密金鑰進行加密。

如果您想自行控管加密作業,可以針對 BigQuery 使用客戶代管的加密金鑰 (CMEK)。您可以在 Cloud KMS 中控制及管理用來保護您資料的金鑰加密金鑰,而不是由 Google 擁有及管理。本文詳細說明如何手動建立 BigQuery 適用的 Cloud KMS 金鑰。

進一步瞭解 Google Cloud 的加密選項。如要瞭解 CMEK 的具體資訊,包括優點和限制,請參閱客戶代管加密金鑰

事前準備

  • BigQuery 代管儲存空間中的所有資料資產都支援 CMEK。不過,如果您也查詢儲存在外部資料來源 (例如 Cloud Storage) 的資料,且這些資料已透過 CMEK 加密,則資料加密作業會由 Cloud Storage 管理。舉例來說,BigLake 資料表支援 Cloud Storage 中以 CMEK 加密的資料。

    BigQuery 和 BigLake 資料表不支援客戶提供的加密金鑰 (CSEK)。

  • 決定您要在同一個 Google Cloud 專案或不同的專案中執行 BigQuery 和 Cloud KMS。為了方便說明,本文的範例將採用下列慣例:

    • PROJECT_ID:執行 BigQuery 專案的 ID
    • PROJECT_NUMBER:執行 BigQuery 的專案專案編號
    • KMS_PROJECT_ID:執行 Cloud KMS 的專案 ID (即使這個專案就是執行 BigQuery 的專案)
    如要瞭解 Google Cloud 專案 ID 和專案編號,請參閱「識別專案」。

  • 新專案會自動啟用 BigQuery。如果您是使用現有專案來執行 BigQuery,請啟用 BigQuery API

  • 針對執行 Cloud KMS 的 Google Cloud 專案,啟用 Cloud Key Management Service API

針對 CMEK 加密資料表的每項查詢,系統會使用 Cloud KMS 執行一次解密呼叫。詳情請參閱 Cloud KMS 定價

加密規格

BigQuery 中用來保護您資料的 Cloud KMS 金鑰是 AES-256 金鑰。這類金鑰的用途是對加密您資料的資料加密金鑰進行加密,因此才會在 BigQuery 中當做金鑰加密金鑰使用。

手動或自動建立金鑰

您可以手動建立 CMEK 金鑰,也可以使用 Cloud KMS Autokey。 Autokey 會自動佈建及指派 CMEK 金鑰,簡化金鑰的建立和管理作業。使用 Autokey 時,您不需要事先佈建金鑰環、金鑰和服務帳戶。而是會在建立 BigQuery 資源時,視需要產生。詳情請參閱「Autokey 總覽」。

手動建立金鑰環和金鑰

針對執行 Cloud KMS 的 Google Cloud 專案,按照建立金鑰環和金鑰一文的指示建立金鑰環和金鑰。請在與您 BigQuery 資料集位置相符的位置建立金鑰環:

  • 所有多地區資料集都應使用相符位置的多地區金鑰環。舉例來說,US 地區中的資料集應使用來自 us 地區的金鑰環加以保護,EU 地區中的資料集則應使用 europe 區域中的金鑰環加以保護。

  • 地區資料集應使用相符地區金鑰。舉例來說,asia-northeast1 地區中的資料集應使用來自 asia-northeast1 地區的金鑰環加以保護。

  • 在 Google Cloud 控制台中為 BigQuery 設定 CMEK 時,無法使用 global 區域。不過,使用 bq 指令列工具或 GoogleSQL 為 BigQuery 設定 CMEK 時,可以指定 global 地區。

如要進一步瞭解支援 BigQuery 和 Cloud KMS 的地區,請參閱 Cloud 據點

授予加密和解密權限

如要使用 CMEK 金鑰保護 BigQuery 資料,請授予 BigQuery 服務帳戶使用該金鑰加密及解密的權限。Cloud KMS CryptoKey Encrypter/Decrypter 角色會授予這項權限。

請確認您已建立服務帳戶,然後使用Google Cloud 控制台取得 BigQuery 服務帳戶 ID。接著,請提供適當的角色給該服務帳戶,從而使用 Cloud KMS 進行加密和解密。

觸發服務帳戶建立作業

建立專案時,系統不會一併建立 BigQuery 服務帳戶。如要觸發建立服務帳戶,請輸入使用該帳戶的指令 (例如 bq show --encryption_service_account 指令),或呼叫 projects.getServiceAccount API 方法。例如:

bq show --encryption_service_account --project_id=PROJECT_ID

取得服務帳戶 ID

BigQuery 服務帳戶 ID 的格式如下:

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

以下技巧說明如何判斷專案的 BigQuery 服務帳戶 ID。

主控台

  1. 前往 Google Cloud 控制台的「資訊主頁」頁面

    前往「資訊主頁」頁面

  2. 按一下頁面頂端的 [Select from] (可用的選項) 下拉式清單。在顯示的「Select from」(可用的選項) 視窗中,選取您的專案。

  3. 專案資訊主頁的「Project info」(專案資訊) 卡片會顯示專案 ID 和專案編號。

    專案資訊卡

  4. 在下列字串中,將 PROJECT_NUMBER 替換為您的專案編號。這個新字串會識別您的 BigQuery 服務帳戶 ID。

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

bq

使用 bq show 指令並加上 --encryption_service_account 標記,即可取得服務帳戶 ID:

bq show --encryption_service_account

該指令會顯示服務帳戶 ID:

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

指派加密者/解密者角色

將 Cloud KMS CryptoKey Encrypter/Decrypter 角色指派給您複製到剪貼簿的 BigQuery 系統服務帳戶。這個帳戶的格式如下:

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

主控台

  1. 在 Google Cloud 控制台中開啟「Cryptographic Keys」(加密編譯金鑰) 頁面。

    開啟「Cryptographic Keys」(加密編譯金鑰) 頁面

  2. 按一下包含金鑰的金鑰環名稱。

  3. 按一下要新增角色的加密金鑰核取方塊。系統會開啟「權限」分頁。

  4. 按一下「新增成員」

  5. 輸入服務帳戶的電子郵件地址:bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com

    • 如果服務帳戶已在成員清單中,表示已獲指派角色。請按一下 bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com 服務帳戶目前的角色下拉式清單。
  6. 依序按一下「選取角色」下拉式清單 >「Cloud KMS」>「Cloud KMS 加密編譯金鑰加密者/解密者」角色。

  7. 按一下「儲存」,將角色套用至 bq-PROJECT_NUMBER@bigquery-encryption.iam.gserviceaccount.com 服務帳戶。

gcloud

您可以使用 Google Cloud CLI 指派角色:

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 的專案 ID Google Cloud
  • PROJECT_NUMBER:執行 BigQuery 的專案編號 (不是專案 ID) Google Cloud
  • KMS_KEY_LOCATION:Cloud KMS 金鑰的位置名稱
  • KMS_KEY_RING:Cloud KMS 金鑰的金鑰環名稱
  • KMS_KEY:Cloud KMS 金鑰的名稱

金鑰資源 ID

使用 CMEK 時需要 Cloud KMS 金鑰的資源 ID,如範例所示。這個鍵會區分大小寫,且採用下列格式:

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

擷取金鑰資源 ID

  1. 在 Google Cloud 控制台中開啟「Cryptographic Keys」(加密編譯金鑰) 頁面。

    開啟「Cryptographic Keys」(加密編譯金鑰) 頁面

  2. 按一下包含金鑰的金鑰環名稱。

  3. 找到您要擷取資源 ID 的金鑰環,按一下「更多」圖示

  4. 按一下「複製資源名稱」。金鑰的資源 ID 會複製到剪貼簿。資源 ID 也稱為資源名稱。

建立受 Cloud KMS 保護的資料表

如何建立受 Cloud KMS 保護的資料表:

主控台

  1. 在 Google Cloud 控制台中開啟 BigQuery 頁面。

    前往 BigQuery 頁面

  2. 在「Explorer」面板中展開專案並選取資料集。

  3. 展開「動作」選項,然後按一下「開啟」

  4. 在詳細資料面板中,按一下「建立資料表」

  5. 在「Create table」(建立資料表) 頁面中填寫建立包含結構定義的空白資料表的必要資訊。請先設定加密類型,並完成指定要與資料表搭配使用的 Cloud KMS 金鑰,接著才按一下「建立資料表」

    1. 點選「進階選項」
    2. 按一下「客戶管理的金鑰」
    3. 選取金鑰。如果清單中沒有您要使用的金鑰,請輸入該金鑰的資源 ID
  6. 點選「建立資料表」。

SQL

使用 kms_key_name 選項搭配 CREATE TABLE 陳述式

  1. 前往 Google Cloud 控制台的「BigQuery」頁面。

    前往「BigQuery」

  2. 在查詢編輯器中輸入下列陳述式:

    CREATE TABLE DATASET_ID.TABLE_ID (
      name STRING, value INT64
    ) OPTIONS (
        kms_key_name
          = 'projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY');

  3. 按一下「執行」

如要進一步瞭解如何執行查詢,請參閱「執行互動式查詢」。

bq

您可以使用 bq 指令列工具搭配 --destination_kms_key 旗標來建立資料表。--destination_kms_key 旗標會指定要與資料表搭配使用的金鑰資源 ID

如何建立包含結構定義的空白資料表:

bq mk --schema name:string,value:integer -t \
--destination_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
DATASET_ID.TABLE_ID

如何從查詢建立資料表:

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

如要進一步瞭解 bq 指令列工具,請參閱使用 bq 指令列工具

Terraform

使用 google_bigquery_table 資源。

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。詳情請參閱「設定用戶端程式庫的驗證機制」。

下列範例會建立名為 mytable 的資料表,並使用 google_kms_crypto_keygoogle_kms_key_ring 資源,為資料表指定 Cloud Key Management Service 金鑰

如要執行這個範例,您必須啟用 Cloud Resource Manager APICloud Key Management Service API

resource "google_bigquery_dataset" "default" {
  dataset_id                      = "mydataset"
  default_partition_expiration_ms = 2592000000  # 30 days
  default_table_expiration_ms     = 31536000000 # 365 days
  description                     = "dataset description"
  location                        = "US"
  max_time_travel_hours           = 96 # 4 days

  labels = {
    billing_group = "accounting",
    pii           = "sensitive"
  }
}

resource "google_bigquery_table" "default" {
  dataset_id          = google_bigquery_dataset.default.dataset_id
  table_id            = "mytable"
  deletion_protection = false # set to "true" in production

  schema = <<EOF
[
  {
    "name": "ID",
    "type": "INT64",
    "mode": "NULLABLE",
    "description": "Item ID"
  },
  {
    "name": "Item",
    "type": "STRING",
    "mode": "NULLABLE"
  }
]
EOF

  encryption_configuration {
    kms_key_name = google_kms_crypto_key.crypto_key.id
  }

  depends_on = [google_project_iam_member.service_account_access]
}

resource "google_kms_crypto_key" "crypto_key" {
  name     = "example-key"
  key_ring = google_kms_key_ring.key_ring.id
}

resource "random_id" "default" {
  byte_length = 8
}

resource "google_kms_key_ring" "key_ring" {
  name     = "${random_id.default.hex}-example-keyring"
  location = "us"
}

# Enable the BigQuery service account to encrypt/decrypt Cloud KMS keys
data "google_project" "project" {
}

resource "google_project_iam_member" "service_account_access" {
  project = data.google_project.project.project_id
  role    = "roles/cloudkms.cryptoKeyEncrypterDecrypter"
  member  = "serviceAccount:bq-${data.google_project.project.number}@bigquery-encryption.iam.gserviceaccount.com"
}

如要在 Google Cloud 專案中套用 Terraform 設定,請完成下列各節的步驟。

準備 Cloud Shell

  1. 啟動 Cloud Shell
  2. 設定要套用 Terraform 設定的預設 Google Cloud 專案。

    每項專案只需要執行一次這個指令,且可以在任何目錄中執行。

    export GOOGLE_CLOUD_PROJECT=PROJECT_ID

    如果您在 Terraform 設定檔中設定明確值,環境變數就會遭到覆寫。

準備目錄

每個 Terraform 設定檔都必須有自己的目錄 (也稱為根模組)。

  1. Cloud Shell 中建立目錄,並在該目錄中建立新檔案。檔案名稱的副檔名必須是 .tf,例如 main.tf。在本教學課程中,這個檔案稱為 main.tf
    mkdir DIRECTORY && cd DIRECTORY && touch main.tf
  2. 如果您正在學習教學課程,可以複製每個章節或步驟中的範例程式碼。

    將範例程式碼複製到新建立的 main.tf

    視需要從 GitHub 複製程式碼。如果 Terraform 程式碼片段是端對端解決方案的一部分,建議您使用這個方法。

  3. 查看並修改範例參數,套用至您的環境。
  4. 儲存變更。
  5. 初始化 Terraform。每個目錄只需執行一次這項操作。
    terraform init

    如要使用最新版 Google 供應商,請加入 -upgrade 選項:

    terraform init -upgrade

套用變更

  1. 檢查設定,確認 Terraform 即將建立或更新的資源符合您的預期:
    terraform plan

    視需要修正設定。

  2. 執行下列指令,並在提示中輸入 yes,即可套用 Terraform 設定:
    terraform apply

    等待 Terraform 顯示「Apply complete!」訊息。

  3. 開啟 Google Cloud 專案即可查看結果。在 Google Cloud 控制台中,前往 UI 中的資源,確認 Terraform 已建立或更新這些資源。

Go

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 BigQuery Go API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Java 設定說明進行操作。詳情請參閱 BigQuery Java API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Python 設定說明進行操作。詳情請參閱 BigQuery Python API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

建立資料表前,請先將 Table.encryption_configuration 屬性設為 EncryptionConfiguration 物件,透過客戶代管的加密金鑰保護新資料表。
from google.cloud import bigquery

client = bigquery.Client()

# TODO(dev): Change table_id to the full name of the table you want to create.
table_id = "your-project.your_dataset.your_table_name"

# 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/your-project/locations/us/keyRings/test/cryptoKeys/test"

table = bigquery.Table(table_id)
table.encryption_configuration = bigquery.EncryptionConfiguration(
    kms_key_name=kms_key_name
)
table = client.create_table(table)  # API request

print(f"Created {table_id}.")
print(f"Key: {table.encryption_configuration.kms_key_name}.")

查詢受 Cloud KMS 金鑰保護的資料表

不需要任何特殊設定,即可查詢 Cloud KMS 保護的資料表。BigQuery 會儲存用於加密資料表內容的金鑰名稱,並且在查詢受 Cloud KMS 保護的資料表時使用該金鑰。

只要 BigQuery 可存取用來加密資料表內容的 Cloud KMS 金鑰,包括 BigQuery 主控台和 bq 指令列工具在內的所有現有工具,其執行方式都與使用預設加密資料表相同。

使用 Cloud KMS 金鑰保護查詢結果

根據預設,查詢結果會儲存在以Google-owned and Google-managed encryption key加密的暫存資料表中。如果專案已有預設金鑰,系統會將該金鑰套用至臨時 (預設) 查詢結果資料表。如要改用 Cloud KMS 金鑰加密查詢結果,請選取下列其中一個選項:

主控台

  1. 在 Google Cloud 控制台中開啟 BigQuery 頁面。

    前往 BigQuery 頁面

  2. 按一下 [Compose new query] (撰寫新查詢)

  3. 在查詢文字區域中輸入有效的 GoogleSQL 查詢。

  4. 依序點按「更多」、「查詢設定」和「進階選項」

  5. 選取「客戶管理的加密技術」

  6. 選取金鑰。如果清單中沒有您要使用的金鑰,請輸入該金鑰的資源 ID

  7. 按一下 [儲存]

  8. 按一下「執行」

bq

指定 --destination_kms_key 旗標,透過您的 Cloud KMS 金鑰來保護目的地資料表或查詢結果 (如果使用臨時資料表)。 --destination_kms_key 旗標會指定與目的地或結果資料表搭配使用的金鑰資源 ID

(選用) 使用 --destination_table 旗標來指定查詢結果的目的地。如果不使用 --destination_table,則查詢結果會寫入臨時資料表。

如何查詢資料表:

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

如要進一步瞭解 bq 指令列工具,請參閱使用 bq 指令列工具

Go

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 BigQuery Go API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

建立資料表前,請先將 Table.encryption_configuration 屬性設為 EncryptionConfiguration 物件,透過客戶代管的加密金鑰保護新資料表。
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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Java 設定說明進行操作。詳情請參閱 BigQuery Java API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

建立資料表前,請先將 Table.encryption_configuration 屬性設為 EncryptionConfiguration 物件,透過客戶代管的加密金鑰保護新資料表。
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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Python 設定說明進行操作。詳情請參閱 BigQuery Python API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

先將 QueryJobConfig.destination_encryption_configuration 屬性設為 EncryptionConfiguration,透過客戶代管的加密金鑰來保護查詢目的地資料表,接著才執行查詢。

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 保護的資料表中載入資料檔案:

主控台

指定載入資料表時要使用的金鑰,以透過客戶代管的加密金鑰來保護載入工作目的地資料表。

  1. 在 Google Cloud 控制台中開啟 BigQuery 頁面。

    前往 BigQuery 頁面

  2. 在「Explorer」面板中展開專案並選取資料集。

  3. 在詳細資料面板中,按一下「建立資料表」

  4. 輸入載入資料表時要使用的選項,但請先按一下 [Advanced options] (進階選項),再點選 [Create table] (建立資料表)

  5. 在「Encryption」(加密) 底下,選取 [Customer-managed key] (客戶管理的金鑰)。

  6. 按一下「選取客戶代管的金鑰」下拉式選單,然後選取要使用的金鑰。如果找不到任何可用的金鑰,請輸入金鑰資源 ID

    進階選項。

  7. 點選「建立資料表」。

bq

設定 --destination_kms_key 旗標,透過客戶代管的加密金鑰來保護載入工作目的地資料表。

bq --location=LOCATION load \
--autodetect \
--source_format=FORMAT \
--destination_kms_key projects/KMS_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/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
test2.table4 \
gs://cloud-samples-data/bigquery/us-states/us-states.json

Go

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 BigQuery Go API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Java 設定說明進行操作。詳情請參閱 BigQuery Java API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Python 設定說明進行操作。詳情請參閱 BigQuery Python API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

LoadJobConfig.destination_encryption_configuration 屬性設為 EncryptionConfiguration,透過客戶管理的加密金鑰來保護載入工作目的地資料表,然後載入資料表。

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

以串流方式將資料傳入受 Cloud KMS 保護的資料表

您可以直接以串流方式將資料傳入受 CMEK 保護的 BigQuery 資料表,而不必指定任何其他參數。請注意,系統會在緩衝區和最終位置中,使用您的 Cloud KMS 金鑰對這些資料進行加密。在搭配 CMEK 資料表使用串流功能前,請先瞭解要符合哪些條件才能確保金鑰可供使用及存取

如要進一步瞭解串流功能,請參閱使用 BigQuery Storage Write API 串流資料

將資料表的保護機制從預設加密改成 Cloud KMS 防護

bq

您可以使用 bq cp 指令搭配 --destination_kms_key 旗標,將受預設加密保護的資料表複製到新資料表或受 Cloud KMS 保護的原始資料表中。--destination_kms_key 旗標會指定要與目的地資料表搭配使用的金鑰資源 ID

如何將採預設加密機制的資料表複製到受 Cloud KMS 保護的新資料表:

bq cp \
--destination_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
SOURCE_DATASET_ID.SOURCE_TABLE_ID DESTINATION_DATASET_ID.DESTINATION_TABLE_ID

如何將採預設加密機制的資料表複製到受 Cloud KMS 保護的相同資料表:

bq cp -f \
--destination_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
DATASET_ID.TABLE_ID DATASET_ID.TABLE_ID

如要將資料表的保護機制從 Cloud KMS 防護改成預設加密,請在不使用 --destination_kms_key 旗標的情況下,直接執行 bq cp 將檔案複製到同一個檔案。

如要進一步瞭解 bq 指令列工具,請參閱使用 bq 指令列工具

Go

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 BigQuery Go API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Java 設定說明進行操作。詳情請參閱 BigQuery Java API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Python 設定說明進行操作。詳情請參閱 BigQuery Python API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

QueryJobConfig.destination_encryption_configuration 屬性設為 EncryptionConfiguration,透過客戶管理的加密金鑰來保護資料表複本目的地,然後複製資料表。

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. 在 Google Cloud 控制台中,按一下資料集左側的藍色箭號以展開選單,或按兩下資料集名稱。畫面會隨即顯示資料集中的資料表和檢視表。

  2. 按一下資料表名稱。

  3. 按一下 [Details] (詳細資料)。「Table Details」(資料表詳細資料) 頁面會顯示資料表的說明和相關資訊。

  4. 如果資料表受 Cloud KMS 保護,「Customer-Managed Encryption Key」(客戶代管的加密金鑰) 欄位會顯示金鑰資源 ID。

    受保護的資料表。

您可以透過金鑰使用情形追蹤功能,查看您建立或用來保護資料表的金鑰,以及這些金鑰保護的資源。詳情請參閱「查看金鑰用量」。

變更 BigQuery 資料表的 Cloud KMS 金鑰

如要變更現有受 CMEK 保護的資料表中的 Cloud KMS 金鑰,您可執行 ALTER TABLE 查詢、使用 API,或使用 bq 指令列工具。 使用 API 和 bq 指令列工具來修改 Cloud KMS 金鑰有兩種方式:updatecp

如使用 update,則可以變更受 CMEK 保護資料表中所使用的 Cloud KMS 金鑰。

如使用 cp,則可以變更受 CMEK 保護資料表中所使用的 Cloud KMS 金鑰,將資料表從預設加密變更為 CMEK 保護,也可將資料表從 CMEK 保護變更為預設加密。

update 的優點是比 cp 更快,且支援使用資料表修飾符

SQL

使用 ALTER TABLE SET OPTIONS 陳述式更新資料表的 kms_key_name 欄位:

  1. 前往 Google Cloud 控制台的「BigQuery」頁面。

    前往「BigQuery」

  2. 在查詢編輯器中輸入下列陳述式:

    ALTER TABLE DATASET_ID.mytable
    SET OPTIONS (
      kms_key_name
        = 'projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY');

  3. 按一下「執行」

如要進一步瞭解如何執行查詢,請參閱「執行互動式查詢」。

bq

您可以使用 bq cp 指令搭配 --destination_kms_key 旗標,變更受 Cloud KMS 保護的資料表金鑰。--destination_kms_key 旗標會指定要與資料表搭配使用的金鑰資源 ID

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

Go

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Go 設定說明進行操作。詳情請參閱 BigQuery Go API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Java 設定說明進行操作。詳情請參閱 BigQuery Java API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

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

先將 Table.encryption_configuration 屬性變更為新的 EncryptionConfiguration 物件,以變更資料表的客戶代管加密金鑰,然後更新資料表。

在試行這個範例之前,請先按照 BigQuery 快速入門導覽課程:使用用戶端程式庫中的 Python 設定說明進行操作。詳情請參閱 BigQuery Python API 參考說明文件

如要向 BigQuery 進行驗證,請設定應用程式預設憑證。 詳情請參閱「設定用戶端程式庫的驗證機制」。

# 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 金鑰。不過預設金鑰不適用於現有的資料表。變更預設金鑰並不會修改任何現有資料表,只會套用至在變更後建立的新資料表。

您可以透過下列操作套用、變更或移除資料集預設金鑰:

  • 呼叫 datasets.insertdatasets.patch 方法時,在 EncryptionConfiguration.kmsKeyName 欄位中指定預設金鑰

  • 執行 bq mk --dataset 指令時,在 --default_kms_key 旗標中指定預設金鑰。

    bq mk \
    --default_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
    --dataset DATASET_ID
    
    bq update \
    --default_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
    --dataset DATASET_ID
    

設定專案預設金鑰

您可以設定專案預設 Cloud KMS 金鑰,該金鑰會套用至專案中該位置的所有查詢結果和新建立的資料表,除非您指定其他 Cloud KMS 金鑰。不過預設金鑰不適用於現有的資料表。變更預設金鑰並不會修改任何現有資料表,只會套用至在變更後建立的新資料表。

SQL

使用 ALTER PROJECT SET OPTIONS 陳述式更新專案的 default_kms_key_name 欄位。您可以在 Cloud KMS 頁面找到金鑰的資源名稱。

  1. 前往 Google Cloud 控制台的「BigQuery」頁面。

    前往「BigQuery」

  2. 在查詢編輯器中輸入下列陳述式:

    ALTER PROJECT PROJECT_ID
    SET OPTIONS (
      `region-LOCATION.default_kms_key_name`
        = 'projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY');

  3. 按一下「執行」

如要進一步瞭解如何執行查詢,請參閱「執行互動式查詢」。

bq

您可以使用 bq 指令執行 ALTER PROJECT SET OPTIONS 陳述式,更新專案的 default_kms_key_name 欄位:

bq query --nouse_legacy_sql \
  'ALTER PROJECT PROJECT_ID
  SET OPTIONS (
  `region-LOCATION.default_kms_key_name`
    ="projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY");'

使用 CMEK 保護 BigQuery ML 模型

BigQuery ML 支援 CMEK。除了 BigQuery 提供的預設加密功能,您也可以使用自己的 Cloud Key Management Service 金鑰加密機器學習模型,包括匯入的 TensorFlow 模型。

使用 Cloud KMS 金鑰建立加密模型

如要建立加密模型,請使用 CREATE MODEL 陳述式,並在訓練選項中指定 KMS_KEY_NAME

    CREATE MODEL my_dataset.my_model
    OPTIONS(
      model_type='linear_reg',
      input_label_cols=['your_label'],
      kms_key_name='projects/my_project/locations/my_location/keyRings/my_ring/cryptoKeys/my_key')
    AS SELECT * FROM my_dataset.my_data

匯入的 TensorFlow 模型也適用相同語法:

    CREATE MODEL my_dataset.my_model
    OPTIONS(
      model_type='tensorflow',
      path='gs://bucket/path/to/saved_model/*',
      kms_key_name='projects/my_project/locations/my_location/keyRings/my_ring/cryptoKeys/my_key')
    AS SELECT * FROM my_dataset.my_data

限制

使用客戶管理的加密金鑰加密機器學習模型時,有下列限制:

將模型的保護機制從預設加密改成 Cloud KMS 防護

您可以搭配使用 bq cp 指令--destination_kms_key 旗標,將受預設加密保護的模型複製到受 Cloud KMS 保護的新模型。或者,您也可以搭配使用 bq cp 指令和 -f 旗標,覆寫受預設加密保護的模型,並更新為改用 Cloud KMS 保護。--destination_kms_key 旗標會指定要與目的地模型搭配使用的金鑰資源 ID

如何將採預設加密機制的模型複製到受 Cloud KMS 保護的新模型:

bq cp \
--destination_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
SOURCE_DATASET_ID.SOURCE_MODEL_ID DESTINATION_DATASET_ID.DESTINATION_MODEL_ID

如要將採預設加密機制的模型覆寫為受 Cloud KMS 保護的相同模型,請按照下列步驟操作:

bq cp -f \
--destination_kms_key projects/KMS_PROJECT_ID/locations/LOCATION/keyRings/KEY_RING/cryptoKeys/KEY \
DATASET_ID.MODEL_ID DATASET_ID.MODEL_ID

如要將模型從 Cloud KMS 防護改為預設加密,請按照下列步驟操作:

bq cp -f \
DATASET_ID.MODEL_ID DATASET_ID.MODEL_ID

如要進一步瞭解 bq 指令列工具,請參閱使用 bq 指令列工具

判斷模型是否受 Cloud KMS 保護

使用 bq show 指令,查看模型是否受到 Cloud KMS 金鑰保護。加密金鑰位於 kmsKeyName 欄位。

bq show -m my_dataset.my_model

您也可以使用 Google Cloud 控制台,找出加密模型的 Cloud KMS 金鑰。如要查看 CMEK 資訊,請前往模型「詳細資料」窗格的「模型詳細資料」部分,查看「客戶管理的金鑰」欄位。

變更加密模型的 Cloud KMS 金鑰

使用 bq update 指令搭配 --destination_kms_key 旗標,變更受 Cloud KMS 保護的模型金鑰:

bq update --destination_kms_key \
projects/my_project/locations/my_location/keyRings/my_ring/cryptoKeys/my_key \
-t my_dataset.my_model

使用預設專案或資料集金鑰

如果您在專案或資料集層級設定預設 Cloud KMS 金鑰,BigQuery ML 會在建立模型時自動使用這項金鑰。如不想使用預設金鑰,請使用 CREATE MODEL 陳述式指定其他金鑰來加密模型。

搭配加密模型使用 BigQuery ML 函式

您可以使用所有 BigQuery ML 函式處理加密模型,不必指定加密金鑰。

使用 CMEK 保護 BigQuery Connection API

如果是 Cloud SQL 連線,您可以使用 CMEK 保護 BigQuery Connection API 憑證。

如要進一步瞭解如何建立受 CMEK 保護的連線,請參閱「建立 Cloud SQL 連線」。

移除 BigQuery 對 Cloud KMS 金鑰的存取權

透過撤銷 Cloud KMS 金鑰的 Identity and Access Management (IAM) 權限,您隨時可以移除 BigQuery 對 Cloud KMS 金鑰的存取權。

如果 BigQuery 無法存取 Cloud KMS 金鑰,則使用者體驗可能會受到嚴重影響,且資料可能會遺失:

  • 您將無法再存取這些受 CMEK 保護資料表中的資料:querycpextracttabledata.list 都會發生錯誤。

  • 您將無法在這些受 CMEK 保護的資料表中新增任何資料。

  • 即使重新授予存取權,查詢效能也可能會在一開始的幾天受到影響。

使用機構政策控管 CMEK 使用情形

BigQuery 會整合 CMEK 機構政策限制,讓您指定機構中 BigQuery 資源的加密法規遵循要求。

這項整合可讓您執行下列操作:

  • 專案中的所有 BigQuery 資源都必須使用 CMEK。

  • 限制可用於保護專案中資源的 Cloud KMS 金鑰。

要求所有資源都使用 CMEK

常見政策是要求使用 CMEK 保護特定專案集中的所有資源。您可以使用 constraints/gcp.restrictNonCmekServices 限制,在 BigQuery 中強制執行這項政策。

如果設定這項機構政策,所有未指定 Cloud KMS 金鑰的資源建立要求都會失敗。

設定這項政策後,只會套用至專案中的新資源。如果現有資源未設定 Cloud KMS 金鑰,仍可繼續存在並正常存取。

主控台

  1. 開啟「機構政策」頁面。

    前往「機構政策」

  2. 在「Filter」(篩選器) 欄位中輸入 constraints/gcp.restrictNonCmekServices,然後按一下「Restrict which services may create resources without CMEK」(限制哪些服務可以在沒有 CMEK 的情況下建立資源)

  3. 按一下「Edit」(編輯)

  4. 選取「自訂」,然後選取「取代」,然後按一下「新增規則」

  5. 選取「自訂」,然後按一下「拒絕」

  6. 在「Custom Value」(自訂值) 欄位中輸入 is:bigquery.googleapis.com

  7. 依序按一下 [完成] 及 [儲存]

gcloud

  gcloud resource-manager org-policies --project=PROJECT_ID \
    deny gcp.restrictNonCmekServices is:bigquery.googleapis.com

如要確認政策是否成功套用,請嘗試在專案中建立資料表。除非您指定 Cloud KMS 金鑰,否則程序會失敗。

這項政策也適用於專案中的查詢結果表格。您可以指定專案預設金鑰,這樣使用者每次在專案中執行查詢時,就不必手動指定金鑰。

限制 BigQuery 專案的 Cloud KMS 金鑰

您可以使用 constraints/gcp.restrictCmekCryptoKeyProjects 限制,限制可用於保護 BigQuery 專案中資源的 Cloud KMS 金鑰。

您可以指定規則,例如「對於 projects/my-company-data-project 中的所有 BigQuery 資源,這個專案中使用的 Cloud KMS 金鑰必須來自 projects/my-company-central-keys 或 projects/team-specific-keys」。

主控台

  1. 開啟「機構政策」頁面。

    前往「機構政策」

  2. 在「Filter」(篩選器) 欄位中輸入 constraints/gcp.restrictCmekCryptoKeyProjects,然後按一下「Restrict which projects may supply KMS CryptoKeys for CMEK」(限制哪些專案可提供 CMEK 的 KMS CryptoKey)

  3. 按一下「Edit」(編輯)

  4. 選取「自訂」,然後選取「取代」,然後按一下「新增規則」

  5. 選取「自訂」,然後按一下「允許」

  6. 在「Custom Value」(自訂值) 欄位中輸入 under:projects/<var>KMS_PROJECT_ID</var>

  7. 依序按一下 [完成] 及 [儲存]

gcloud

  gcloud resource-manager org-policies --project=PROJECT_ID \
    allow gcp.restrictCmekCryptoKeyProjects under:projects/KMS_PROJECT_ID

如要確認政策是否已順利套用,您可以嘗試使用其他專案的 Cloud KMS 金鑰建立資料表。程序會失敗。

機構政策的限制

設定機構政策時,請注意以下限制:

傳播延遲

設定或更新機構政策後,新政策最多可能需要 15 分鐘才會生效。BigQuery 會快取政策,以免對查詢和資料表建立延遲時間造成負面影響。

設定機構政策所需的權限

您可能難以取得設定或更新機構政策的權限,以進行測試。您必須獲授予機構政策管理員角色,這個角色只能在機構層級授予 (而非專案或資料夾層級)。

雖然必須在機構層級授予角色,但仍可指定僅適用於特定專案或資料夾的政策。

Cloud KMS 金鑰輪替的影響

與資料表關聯的 Cloud KMS 金鑰輪替時,BigQuery 不會自動輪替資料表加密金鑰。現有資料表中的所有資料,會繼續受到建立時所用金鑰版本的保護。

新建立的資料表會使用建立時的主要金鑰版本。

如要更新資料表以使用最新金鑰版本,請使用相同的 Cloud KMS 金鑰更新資料表。這項更新不會檢查任何機構政策。 只有更新金鑰時,系統才會檢查組織政策。

對 Cloud KMS 帳單的影響

建立或截斷受 CMEK 保護的資料表時,BigQuery 會產生中繼金鑰加密金鑰,然後使用指定的 Cloud KMS 金鑰加密。

就帳單而言,這表示您對 Cloud KMS 的呼叫和相關費用都不會隨表格大小而調整。如果是受 CMEK 保護的資料表,每次建立或截斷資料表時,系統會呼叫一次 Cloud KMS cryptoKeys.encrypt,每次查詢資料表時,系統會呼叫一次 Cloud KMS cryptoKeys.decrypt。這兩種方法都屬於Cloud KMS 定價中列出的「金鑰作業:密碼編譯」類別。

讀取或寫入現有的 CMEK 保護資料表時,系統會叫用 Cloud KMS cryptoKeys.decrypt,因為必須解密中繼金鑰。

限制

BigQuery 對 Cloud KMS 金鑰的存取權

在符合以下條件的情況下,BigQuery 會將 Cloud KMS 金鑰判定為可供使用及存取:

  • 金鑰已啟用
  • BigQuery 服務帳戶具備該金鑰的加密和解密權限

以下各節將說明如果不能存取金鑰,將會對串流資料插入和長期無法存取的資料造成什麼影響。

對串流資料插入造成的影響

在提出串流資料插入要求後的 48 小時內,Cloud KMS 金鑰必須可供使用及存取至少連續 24 個小時。如果不能使用及存取金鑰,串流資料可能會無法完整留存且可能會遺失。如要進一步瞭解串流資料插入,請參閱以串流方式將資料傳入 BigQuery 一文。

對長期無法存取的資料造成的影響

由於 BigQuery 提供受管理的儲存空間,因此長期無法存取的資料與 BigQuery 的架構並不相容。如果連續 60 天無法使用及存取特定 BigQuery 資料表的 Cloud KMS 金鑰,BigQuery 可能會選擇刪除資料表及相關聯的資料。BigQuery 會在刪除資料前至少 7 天,傳送電子郵件至與帳單帳戶相關聯的電子郵件地址。

使用外部資料來源

如果您查詢儲存在外部資料來源 (例如 Cloud Storage) 中的資料,且這些資料已透過 CMEK 加密,則資料加密作業是由 Cloud Storage 管理。舉例來說,BigLake 資料表支援 Cloud Storage 中以 CMEK 加密的資料。

BigQuery 和 BigLake 資料表不支援客戶提供的加密金鑰 (CSEK)。

在受 CMEK 保護和預設加密之間切換

您無法在預設加密和 CMEK 加密之間切換資料表。如要切換加密方式,請複製資料表並設定目的地加密資訊,或使用 SELECT * 查詢,以 WRITE_TRUNCATE 處置將資料表選取至本身。

使用資料表裝飾器

如果您使用 Cloud KMS 保護資料表,然後透過 loadcpquery 作業的 WRITE_TRUNCATE 值取代資料表中的資料,則範圍修飾符無法跨越加密變更界線運作。您仍可使用資料表裝飾符 (包括範圍裝飾符) 查詢邊界之前或之後的資料,或查詢特定時間點的快照。

萬用字元資料表查詢

您無法使用萬用字元後置字串查詢受 CMEK 保護的資料表。

指令碼支援

指令碼無法為 CMEK 作業定義目標資料表。

支援的版本

BigQuery 的 CMEK 支援功能僅適用於 BigQuery Enterprise、BigQuery Enterprise Plus 和 BigQuery On-Demand。

BigQuery Studio 支援

BigQuery Studio 程式碼資產 (包括已儲存的查詢筆記本) 不支援 CMEK。

常見問題

誰需要 Cloud KMS 金鑰的存取權?

使用客戶管理的加密金鑰時,您不需要重複指定權限。只要 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 加密編譯金鑰加密者/解密者角色 與專案相關聯的 BigQuery 服務帳戶沒有足夠的 IAM 權限,無法對指定的 Cloud KMS 金鑰進行操作。請按照錯誤訊息或這份說明文件中的指示操作,授予適當的 IAM 權限。
現有資料表加密設定與要求中指定的加密設定不一致 如果目的地資料表的加密設定與您要求中的加密設定不一致,就可能會出現這類錯誤。如要解決這類問題,請使用寫入配置 TRUNCATE 取代資料表,或指定其他目的地資料表。
不支援這個區域 Cloud KMS 金鑰的區域與目的地資料表的 BigQuery 資料集區域不一致。如要解決這類問題,請在與資料集相同的區域選取金鑰,或載入與金鑰區域相符的資料集。
管理員要求您為專案 PROJECT_ID. 中的查詢指定加密金鑰 機構政策禁止建立資源或執行查詢。 如要進一步瞭解這項政策,請參閱「在 BigQuery 專案中,對所有資源強制使用 CMEK」。
管理員禁止使用專案 KMS_PROJECT_ID 的 KMS 金鑰,保護專案 PROJECT_ID 中的資源。 機構政策禁止建立資源或執行查詢。如要進一步瞭解這項政策,請參閱限制 BigQuery 專案的 Cloud KMS 金鑰