使用客户管理的加密密钥 (CMEK)

本页介绍如何执行与以下内容相关的任务: 适用于 Firestore 的客户管理的加密密钥 (CMEK)。如需大致了解 CMEK(包括其启用时间和原因),请参阅 Cloud KMS 文档

准备 CMEK 密钥

在创建受 CMEK 保护的 Firestore 数据库之前, 必须完成以下步骤:

  1. 请求对 Firestore CMEK 功能的访问权限
  2. 创建(或检索)Firestore 服务代理
  3. 创建 CMEK 密钥
  4. 为该密钥配置 IAM 设置

针对每个将含有受 CMEK 保护的项目,完成以下步骤 Firestore 数据库。如果您以后创建新的 CMEK 密钥, 您必须为该密钥配置 IAM 设置。

请求访问权限

在创建 Firestore 服务代理之前,请申请 将此 表单

创建 Firestore 服务代理

在创建 CMEK 密钥之前,您必须拥有 Firestore 服务代理:这是一种由 Google 代管式服务账号, Firestore 用于访问该密钥。

运行 services identity create 命令以 创建 Firestore 用于访问 CMEK 的服务代理 密钥。如果服务账号不存在,此命令将创建并显示该服务账号。

gcloud beta services identity create \
    --service=firestore.googleapis.com \
    --project FIRESTORE_PROJECT

FIRESTORE_PROJECT 替换为您计划的项目 Firestore 数据库的备用凭据。

该命令会显示服务代理 ID,其格式与电子邮件地址类似。记下输出的电子邮件字符串,您将在后面的步骤中用到它。

Service identity created:
service-xxx@gcp-sa-firestore.iam.gserviceaccount.com

创建密钥

您可以使用直接在 Cloud KMS 中创建的密钥,也可以使用由 Cloud External Key Manager 提供的外部管理的密钥。

Cloud KMS 密钥位置必须是 与将要使用的 Firestore 数据库的位置相同

  • 对于区域级数据库位置,请使用 密钥环、密钥和数据库的位置名称相同,因为位置名称 存在一对一的映射关系

    例如,如果要在 Google Cloud 控制台中创建受 CMEK 保护的数据库, us-west1,请在 us-west1 中创建密钥环和密钥。

  • 对于多区域数据库位置,请使用 KMS 多区域位置的位置名称:

    • 使用 Cloud KMS us 多区域位置作为 Firestore nam5 多区域位置。
    • 使用 Cloud KMS europe 多区域位置作为 Firestore eur3 多区域位置。

在您要管理密钥的 Google Cloud 项目中,完成以下操作:

  1. 启用 Cloud KMS API

  2. 使用以下选项之一创建密钥环和密钥:

为密钥配置 IAM 设置

控制台

如需向您的服务代理授予 Cloud KMS 角色,请执行以下操作。如果需要更低的粒度级别,您也可以在密钥级层或密钥环级层授予权限。

  1. 在 Google Cloud 控制台中,前往 IAM 页面。

    转到 IAM 页面

  2. 点击添加

  3. 输入 Firestore 的电子邮件格式的 ID 服务代理。

  4. 选择 Cloud KMS CryptoKey Encrypter/Decrypter 角色。

  5. 点击保存

gcloud

  1. 向您的服务账号授予 cloudkms.cryptoKeyEncrypterDecrypter 角色:

    gcloud kms keys add-iam-policy-binding KMS_KEY \
        --keyring KMS_KEYRING\
        --location KMS_LOCATION \
        --member serviceAccount:SERVICE_AGENT_EMAIL \
        --role roles/cloudkms.cryptoKeyEncrypterDecrypter \
        --project KMS_PROJECT
    

    提供以下信息:

    • KMS_KEY:您为密钥分配的名称
    • KMS_KEYRING:包含密钥的 KMS 密钥环
    • KMS_LOCATION:包含密钥环的区域
    • SERVICE_AGENT_EMAIL:您要向其授予访问权限的服务代理的电子邮件格式标识符
    • KMS_PROJECT:包含密钥的项目

    终端应显示类似于以下内容的响应:

    Updated IAM policy for key KMS_KEY.
    bindings:
    - members:
      - serviceAccount:
        service-{project-number}@gcp-sa-firestore.iam.gserviceaccount.com
    role: roles/cloudkms.cryptoKeyEncrypterDecrypter
    

创建支持 CMEK 的数据库

创建和配置 CMEK 密钥后,您可以创建受 CMEK 保护的 CMEK 数据库。受以下项保护的现有 Firestore 数据库: Google 默认加密方式无法转换为使用 CMEK;您只能选择 加密类型和密钥。

gcloud

gcloud alpha firestore databases create --location=FIRESTORE_DATABASE_LOCATION \
      --database=DATABASE_ID \
      --kms-key-name=KMS_KEY_NAME \
      --project=FIRESTORE_PROJECT

提供以下信息:

  • FIRESTORE_DATABASE_LOCATION:数据库的 Firestore 位置
  • DATABASE_ID:数据库的 ID
  • KMS_KEY_NAME:您分配给密钥的名称。为密钥使用完整资源名称,格式如下:

    projects/KMS_PROJECT/locations/KMS_LOCATION/keyRings/KMS_KEYRING_ID/cryptoKeys/KMS_KEY_ID

  • FIRESTORE_PROJECT:要用于您的 Firestore 数据库

REST API

HTTP 请求:

POST https://firestore.googleapis.com/v1/projects/{FIRESOTRE_PROJECT}/databases

在请求正文的 cmek_config.kms_key_name 字段中配置 CMEK。

设置为 Cloud KMS 密钥的完整资源 ID。同一 位置,因为此数据库是允许的。

此值应为 Cloud KMS 密钥资源 ID,格式为 projects/{KMS_PROJECT}/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}

如需详细了解其他字段,请参阅 database create 页面

示例请求:

curl -X POST 'https://firestore.googleapis.com/v1/projects/FIRESTORE_PROJECT/databases?databaseId={DATABASE_ID}' \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-type: application/json" \
-d '{
  "type":"FIRESTORE_NATIVE",
  "locationId":"{FIRESTORE_DATABASE_LOCATION}",
  "cmekConfig": {
    "kmsKeyName":"projects/KMS_PROJECT/locations/KMS_LOCATION/keyRings/KMS_KEYRING_ID/cryptoKeys/KMS_KEY_ID"
  }
}'

Terraform

如需创建支持 CMEK 的数据库,请使用 google_firestore_database 资源。有关详情和示例,请参阅 google_firestore_database.

resource "google_firestore_database" "database" {
  project     = "FIRESTORE_PROJECT"
  name        = "DATABASE_ID"
  location_id = "FIRESTORE_DATABASE_LOCATION"
  type        = "DATABASE_TYPE"

  cmek_config {
    kms_key_name = "KMS_KEY_NAME"
  }

}

提供以下信息:

  • FIRESTORE_PROJECT:要用于您的 Firestore 数据库
  • DATABASE_ID:数据库的 ID
  • FIRESTORE_DATABASE_LOCATION:数据库的 Firestore 位置
  • DATABASE_TYPE:FIRESTORE_NATIVE(对于原生模式)或 DATASTORE_MODE(对于 Datastore 模式)。
  • KMS_KEY_NAME:您分配给密钥的名称。为密钥使用完整资源名称,格式如下:

    projects/KMS_PROJECT/locations/KMS_LOCATION/keyRings/KMS_KEYRING_ID/cryptoKeys/KMS_KEY_ID

访问受 CMEK 保护的数据库

发送到受 CMEK 保护的数据库的所有读取、写入和查询操作 运作方式应与使用 Google 默认加密数据库时相同。 例如,您无需为每个请求提供密钥。

查看正在使用的密钥

gcloud

您可以使用 databases describe gcloud CLI 命令以确认数据库 CMEK 配置:

gcloud firestore databases describe --database=DATABASE_ID --project=FIRESTORE_PROJECT

您应该会在响应的 cmekConfig 字段中看到 CMEK 信息 类似于以下内容:

cmekConfig:
    activeKeyVersion:
    - projects/PROJECT_ID/locations/us/keyRings/KEYRING_NAME/cryptoKeys/KEY_NAME/cryptoKeyVersions/1
    kmsKeyName: projects/PROJECT_ID/locations/us/keyRings/KEYRING_NAME/cryptoKeys/KEY_NAME
  locationId: nam5
  name: projects/PROJECT_ID/databases/DATABASE_ID

响应包含以下信息:

  • kmsKeyName:用于加密的密钥的完整密钥资源名称 受 CMEK 保护的数据库。
  • activeKeyVersion:当前正在使用的所有密钥版本的列表 受 CMEK 保护的数据库。在密钥轮替期间, 可以有多个有效的密钥版本。

REST API

HTTP 请求:

GET https://firestore.googleapis.com/v1/{name=projects/FIRESTORE_PROJECT/databases/DATABASE_ID}

在请求正文的 cmek_config.kms_key_name 字段中配置 CMEK。 设置为 Cloud KMS 密钥的完整资源 ID。同一 位置,因为此数据库是允许的。

此值应为 Cloud KMS 密钥资源 ID,格式为 projects/{KMS_PROJECT}/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}

如需详细了解其他字段,请参阅 database create 页面

请求和响应示例:

curl 'https://firestore.googleapis.com/v1/projects/FIRESTORE_PROJECT/databases/{DATABASE_ID}' \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-type: application/json"

—----------------------------------------- Response —--------------------------------------------
{
  "name": "projects/FIRESTORE_PROJECT/databases/{DATABASE_ID}",
  "locationId": "{FIRESTORE_DATABASE_LOCATION}",
  "type": "FIRESTORE_NATIVE",
  "cmekConfig": {
    "kmsKeyName": "projects/{KMS_PROJECT}/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}",
    "activeKeyVersion": [
      "projects/{KMS_PROJECT}/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}/cryptoKeyVersions/1"
    ]
  },
  ……
}

停用密钥

如需停用与数据库关联的密钥,请完成以下步骤:

  1. 查看数据库使用的密钥版本
  2. 停用这些密钥版本
  3. 等待更改生效,并检查数据是否不再 可访问性。更改通常会在几分钟内生效 但最多可能需要 3 小时。

当数据库使用的某个密钥停用时,应该会收到 FAILED_PRECONDITION 异常,错误消息中包含其他详细信息, 例如:

{
  "error": {
    "code": 400,
    "message": "The customer-managed encryption key required by the requested resource is not accessible. Error reason:  generic::permission_denied: Permission 'cloudkms.cryptoKeyVersions.useToEncrypt' denied on resource 'projects/FIRESTORE_PROJECT/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}' (or it may not exist).",
    "status": "FAILED_PRECONDITION",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.DebugInfo",
        "detail": "The customer-managed encryption key required by the requested resource is not accessible. Error reason:  generic::permission_denied: Permission 'cloudkms.cryptoKeyVersions.useToEncrypt' denied on resource 'projects/FIRESTORE_PROJECT/locations/{KMS_LOCATION}/keyRings/{KMS_KEYRING_ID}/cryptoKeys/{KMS_KEY_ID}' (or it may not exist)"
      }
    ]
  }
}

启用密钥

如需重新启用与数据库关联的密钥,请完成以下步骤:

  1. 查看数据库使用的密钥版本
  2. 启用这些密钥版本
  3. 等待更改生效,并检查数据是否不再 可访问性。更改通常会在几分钟内生效 但最多可能需要 3 小时。

查看 Cloud KMS 密钥的审核日志

启用 Cloud KMS 数据访问审核日志之前,您应先熟悉 Cloud Audit Logs

Cloud KMS 数据访问审核日志会显示 Firestore 或配置为使用 CMEK 密钥用于对 Cloud KMS 执行加密/解密调用。 Firestore 不会对每个数据发出加密/解密调用 而是维护一个定期检查密钥的轮询器。轮询结果将显示在审核日志中。

您可以在 Google Cloud 控制台中设置审核日志并与之交互:

  1. 确保针对您的项目中的 Cloud KMS API 启用日志记录

  2. 在 Google Cloud 控制台中,前往 Cloud Logging

    前往 Cloud Logging

  3. 通过将以下行添加到查询构建器,将日志条目限制为 Cloud KMS 密钥:

    resource.type="cloudkms_cryptokey"
    resource.labels.key_ring_id = KMS_KEYRING
    resource.labels.crypto_key_id = KMS_KEY
    resource.labels.location=KMS_LOCATION
    

    提供以下信息:

    • KMS_KEY:CMEK 密钥的名称
    • KMS_KEYRING:包含密钥的 KMS 密钥环
    • KMS_LOCATION:密钥和密钥环的位置

    日志大约每五分钟会为每个数据库显示几条日志条目。 日志条目类似于以下示例:

    Info 2021-03-20 08:02:24.869 EDT Cloudkms.googleapis.com Decrypt projects/cloud-kms-project/locations/us-central1/keyRings/firestore-keys/cryptoKeys/my-cmek-key service-123456789123@gcp-sa-firestore.iam.gserviceaccount.com
    audit_log, method: "Decrypt", principal_email: "service-1234567891011@gcp-sa-firestore.iam.gserviceaccount.com"
    
    Info 2021-03-20 08:02:24.913 EDT Cloudkms.googleapis.com Encrypt projects/cloud-kms-project/locations/us-central1/keyRings/firestore-keys/cryptoKeys/my-cmek-key service-123456789123@gcp-sa-firestore.iam.gserviceaccount.com
    audit_log, method: "Encrypt", principal_email: "service-123456789123@gcp-sa-firestore.iam.gserviceaccount.com"
    

如需详细了解如何解读审核日志,请参阅了解审核日志

配置 CMEK 组织政策

指定 Firestore 的加密合规性要求 数据库,请使用 CMEK 组织政策限制条件

需要 CMEK 保护

constraints/gcp.restrictNonCmekServices 配置为要求使用 CMEK 创建 Firestore 数据库。将约束条件设置为 deny, 将 firestore.googleapis.com 添加到拒绝名单,例如:

 gcloud resource-manager org-policies deny gcp.restrictNonCmekServices  is:firestore.googleapis.com --project=FIRESTORE_PROJECT

FIRESTORE_PROJECT 替换为要限制的项目。

如需详细了解如何配置组织政策,请参阅创建和修改政策

政策生效后,如果您尝试在受影响的项目下创建非 CMEK 数据库,则会收到 FAILED_PRECONDITION 异常和错误消息。例如,异常如下所示:

{
  "error": {
    "code": 400,
    "message": "Constraint 'constraints/gcp.restrictNonCmekServices' violated for 'projects/FIRESTORE_PROJECT' attempting to perform the operation 'google.firestore.admin.v1.FirestoreAdmin.CreateDatabase' with violated value 'firestore.googleapis.com'. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information.",
    "status": "FAILED_PRECONDITION",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.PreconditionFailure",
        "violations": [
          {
            "type": "constraints/gcp.restrictNonCmekServices",
            "subject": "orgpolicy:projects/FIRESTORE_PROJECT",
            "description": "Constraint 'constraints/gcp.restrictNonCmekServices' violated for 'projects/FIRESTORE_PROJECT' attempting to perform the operation 'google.firestore.admin.v1.FirestoreAdmin.CreateDatabase' with violated value 'firestore.googleapis.com'. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information."
          }
        ]

限制将密钥用于 CMEK

如需限制用于 CMEK 保护的 Cloud KMS 密钥,请执行以下操作: 配置 constraints/gcp.restrictCmekCryptoKeyProjects 限制条件。

作为列表限制条件,接受的值是资源层次结构指示符( 示例:projects/PROJECT_IDunder:folders/FOLDER_IDunder:organizations/ORGANIZATION_ID).您可以通过配置 资源层次结构指示器的列表,并将限制条件设置为 Allow。 此配置会限制支持的服务,以便可以选择 CMEK 密钥 仅从列出的项目、文件夹和组织中导出。创建请求 配置的服务中受 CMEK 保护的资源在没有 某个允许的资源中的 Firestore 键。

以下示例仅允许指定项目中受 CMEK 保护的数据库来自 ALLOWED_KEY_PROJECT_ID 的密钥:

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

政策生效后,您会收到 FAILED_PRECONDITION 异常 如果您违反限制条件,系统会显示错误消息。异常 如下所示:

{
  "error": {
    "code": 400,
    "message": "Constraint 'constraints/gcp.restrictCmekCryptoKeyProjects' violated for 'projects/FIRESTORE_PROJECT' attempting to perform the operation 'google.firestore.admin.v1.FirestoreAdmin.CreateDatabase' with violated value 'projects/{NOT_ALLOWED_KEY_PROJECT}'. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information.",
    "status": "FAILED_PRECONDITION",
    "details": [
      {
        "@type": "type.googleapis.com/google.rpc.PreconditionFailure",
        "violations": [
          {
            "type": "constraints/gcp.restrictCmekCryptoKeyProjects",
            "subject": "orgpolicy:projects/FIRESTORE_PROJECT",
            "description": "Constraint 'constraints/gcp.restrictCmekCryptoKeyProjects' violated for 'projects/FIRESTORE_PROJECT' attempting to perform the operation 'google.firestore.admin.v1.FirestoreAdmin.CreateDatabase' with violated value 'projects/{NOT_ALLOWED_KEY_PROJECT}'. See https://cloud.google.com/resource-manager/docs/organization-policy/org-policy-constraints for more information."
          }
        ]
      }
    ]
  }
}

后续步骤