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

本主题讨论了 Secret Manager 中客户管理的加密密钥 (CMEK)。

概览

Secret Manager 提供用于存储、管理和访问应用中的敏感数据的工具。

默认情况下,存储在 Secret Manager 中的密文采用 Google 默认加密技术进行加密。使用 Google 的默认加密方式,在将由 Google 管理的密文载荷写入永久性存储空间前,需先加密,无需配置。对于大多数组织而言,Google 默认加密是最佳选择。

对于希望加强控制的组织,CMEK 支持 Secret Manager 允许您配置 Cloud KMS 密钥,以保护 Secret Manager 存储中的数据(静态数据)。如果您暂时停用或永久销毁 CMEK 密钥,则使用该密钥加密的数据将无法解密,因此无法访问。

CMEK 在 Secret Manager 中的工作原理

在将密文版本写入特定位置的持久性存储空间之前,Secret Manager 会使用唯一的数据加密密钥 (DEK) 对数据进行加密。然后,此 DEK 使用副本专用密钥(称为密钥加密密钥 KEK,由 Secret Manager 服务拥有)进行加密。

将 CMEK 用于 Secret Manager 时,KEK 称为 CMEK 密钥,它是您在 Cloud KMS 中管理的对称密钥。CMEK 密钥必须与其加密的密文副本位于同一 GCP 位置。

本指南介绍了如何配置 Secret Manager 以使用 CMEK。如需大致了解 CMEK(包括其启用时间和原因),请参阅 Cloud Key Management Service 文档

限制

CMEK 仅在 Secret Manager v1 API 和 gCloud 中可用。

准备工作

您可以选择将所有资源存储在同一项目中,或将密文和密钥存储在不同的项目中。阅读 Cloud KMS 职责分离,以更好地了解此决策。

完成以下前提条件,以设置 Secret Manager 和 Cloud KMS:

  • Secret Manager:

    • 创建或使用现有项目来保存您的 Secret Manager 资源。
    • 如有必要,请完成 Secret Manager 快速入门中配置 Secret Manager 部分的步骤。
  • Cloud KMS:

    • 创建或使用现有项目来保留您的 Cloud KMS 资源。
    • 如有必要,请启用 Cloud KMS API

将以下变量设置为 Secret Manager 和 Cloud KMS 项目的项目 ID。

命令行

$ export SM_PROJECT_ID="..."
$ export KMS_PROJECT_ID="..."

向 Google Cloud 进行身份验证:

gcloud

$ gcloud auth login

创建服务帐号

您需要为每个需要 CMEK 的项目创建一个服务帐号。目前,您只能使用 gcloud 命令行工具命令来为 CMEK 创建所需的服务帐号类型。

如需使用 gcloud 命令行工具创建服务帐号,请运行以下命令:

gcloud

$ gcloud beta services identity create \
    --service "secretmanager.googleapis.com" \
    --project "${SM_PROJECT_ID}"

上述命令会按以下格式返回服务帐号名称:

service-[PROJECT_NUMBER]@gcp-sa-secretmanager.iam.gserviceaccount.com

您要向此服务帐号授予对用于加密和解密密文的 CMEK Cloud KMS 密钥的访问权限。

将服务帐号名称保存为环境变量:

命令行

# This is from the output of the command above
$ export SM_SERVICE_ACCOUNT="service-...."

在遵循此程序的全过程中,您必须设置 Secret Manager 项目、Cloud KMS 项目和 Secret Manager 服务帐号的环境变量。

具有自动复制功能的 CMEK

本部分涉及通过自动复制政策配置的密文。

对于使用自动复制政策的密文,您的 CMEK 密钥必须位于全局 Cloud KMS 多区域中。

在全局 Cloud KMS 区域中创建对称 Cloud KMS 密钥,或使用现有密钥。本示例会创建一个名为 secret-manager-cmek 的新密钥环,然后在其上创建名为 my-cmek-key 的新密钥。

gcloud

$ gcloud kms keyrings create "secret-manager-cmek" \
    --project "${KMS_PROJECT_ID}" \
    --location "global"

$ gcloud kms keys create "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "global" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

获取密钥的资源名称,并将其设置为环境变量。

命令行

$ export KMS_KEY_NAME="projects/${KMS_PROJECT_ID}/locations/global/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key"

向服务帐号授予 Secret Manager 访问权限,以便使用 CMEK 密钥进行加密和解密。此命令会向服务帐号授予 my-cmek-key Cloud KMS 密钥上的 Cloud KMS 加密/解密角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter)。

gcloud

$ gcloud kms keys add-iam-policy-binding "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "global" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

通过自动复制创建密文。CMEK 密钥的资源名称以密文上的元数据形式存储。

gcloud

$ gcloud beta secrets create my-secret \
    --replication-policy "automatic" \
    --kms-key-name "${KMS_KEY_NAME}" \
    --project "${SM_PROJECT_ID}"

API

replication.automatic.customerManagedEncryption.kmsKeyName 的值设置为 CMEK 密钥的资源名称。

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets?secretId=my-secret" \
    --request "POST" \
    --header "Content-Type: application/json" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --data-binary @- <<EOF
{
  "replication":{
    "automatic":{
      "customerManagedEncryption":{
        "kmsKeyName": "${KMS_KEY_NAME}"
      }
    }
  }
}
EOF

现在,每次在该密文中创建密文版本时,只要该服务帐号有权访问 CMEK 密钥,系统就会使用密钥,在写入密文之前自动使用密钥的载荷进行加密。如果服务帐号失去访问权限,或者密钥不可用,则尝试创建新密文版本或访问现有密文版本会返回错误。

添加新的密文版本。请注意,您未指定 Cloud KMS 密钥的资源名称;从密文的元数据中读取此密钥。

gcloud

$ echo -n "abcd1234" | gcloud beta secrets versions add "my-secret" \
    --project "${SM_PROJECT_ID}" \
    --data-file -

即使调用者无法直接访问 CMEK 密钥,系统也会创建密文版本。Secret Manager(而不是调用者)的服务帐号负责在读取或写入密文时进行加密和解密。

同样,您无需直接访问 CMEK 密钥即可访问密文。服务帐号会访问密钥,并代表您加密或解密密文。

访问您刚刚创建的密文版本:

gcloud

$ gcloud beta secrets versions access latest \
    --project "${SM_PROJECT_ID}" \
    --secret "my-secret"

更新 CMEK 配置

global Cloud KMS 多区域中创建新的对称 KMS 密钥。

gcloud

$ gcloud kms keys create "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "global" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

向服务帐号授予 Secret Manager 访问权限,以便使用新的 CMEK 密钥进行加密和解密。此命令会向服务帐号授予 my-other-key Cloud KMS 密钥上的 Cloud KMS 加密/解密角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter)。

gcloud

$ gcloud kms keys add-iam-policy-binding "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "global" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

使用新的 Cloud KMS 密钥资源名称更新密文副本,以修改密文的 CMEK 配置。

gcloud

$ gcloud beta secrets replication update my-secret \
    --set-kms-key="projects/${KMS_PROJECT_ID}/locations/global/keyRings/secret-manager-cmek/cryptoKeys/my-other-key" \
    --project "${SM_PROJECT_ID}"

API

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/my-secret?updateMask=replication" \
    --request "PATCH" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --header "Content-Type: application/json" \
    --data-binary @- <<EOF
{
  "replication": {
    "automatic":{
      "customerManagedEncryption":{
        "kmsKeyName": "projects/${KMS_PROJECT_ID}/locations/global/keyRings/secret-manager-cmek/cryptoKeys/my-other-key"
      }
    }
  }
}
EOF

具有用户管理器复制功能的 CMEK

本部分介绍了使用用户管理的复制政策配置的密文。借助用户管理的复制政策,您可以控制存储密文的 GCP 位置。密文可以随时从每个 GCP 位置进行访问。

具有用户管理的复制政策的密文必须使用与密文版本的存储位置完全匹配的 Cloud KMS 密钥。本指南将密文存储在两个单独的位置:us-east1、us-central1。访问密文的请求将传送到其中一个位置。

在两个区域中的一个,创建用于加密的密钥环和 Cloud KMS 密钥,或者使用现有密钥。此示例会创建一个名为 secret-manager-cmek 的新密钥环,然后在每个区域中创建一个名为 my-cmek-key 的密钥。

gcloud

# us-east1
$ gcloud kms keyrings create "secret-manager-cmek" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-east1"

$ gcloud kms keys create "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-east1" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

# us-central1
$ gcloud kms keyrings create "secret-manager-cmek" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-central1"

$ gcloud kms keys create "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-central1" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

通过为每个 CMEK 密钥单独授予或项目中的所有密钥授予 Cloud KMS 加密/解密角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter),为服务帐户授予 Secret Manager 访问权限,以使用 CMEK 密钥加密和解密。

gcloud

# us-east1
$ gcloud kms keys add-iam-policy-binding "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-east1" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

# us-central1
$ gcloud kms keys add-iam-policy-binding "my-cmek-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-central1" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

使用用户管理的复制政策创建启用了 CMEK 的密文。CMEK 密钥的资源名称以密文上的元数据形式存储。

gcloud

$ cat <<EOF > replication-policy.json
{
  "userManaged":{
    "replicas":[
      {
        "location":"us-east1",
        "customerManagedEncryption":{
          "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-east1/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key"
        }
      },
      {
        "location":"us-central1",
        "customerManagedEncryption":{
          "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-central1/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key"
        }
      }
    ]
  }
}
EOF

$ gcloud beta secrets create my-ummr-secret \
    --replication-policy-file replication-policy.json \
    --project "${SM_PROJECT_ID}"

API

replication.userManaged.replicas.customerManagedEncryption.kmsKeyName 的值设置为 CMEK 密钥的资源名称。

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets?secretId=my-ummr-secret" \
--request "POST" \
--header "Content-Type: application/json" \
--header "Authorization: Bearer $(gcloud auth print-access-token)" \
--data-binary @- <<EOF
{
  "replication":{
    "userManaged":{
      "replicas":[
        {
          "location":"us-east1",
          "customerManagedEncryption":{
            "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-east1/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key"
          }
        },
        {
          "location":"us-central1",
          "customerManagedEncryption":{
            "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-central1/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key"
          }
        }
      ]
    }
  }
}
EOF

现在,每次在该密文中创建密文版本时,只要该服务帐号有权访问 CMEK 密钥,系统就会使用密钥,在写入密文之前自动使用密钥的载荷进行加密。如果服务帐号失去访问权限,或者密钥不可用,则尝试创建新密文版本或访问现有密文版本会返回错误。

添加新的密文版本。请注意,您未指定 Cloud KMS 密钥的资源名称;从密文的元数据中读取此密钥。

gcloud

$ echo -n "abcd1234" | gcloud beta secrets versions add "my-ummr-secret" \
    --project "${SM_PROJECT_ID}" \
    --data-file -

即使调用者无法直接访问 CMEK 密钥,系统也会创建密文版本。Secret Manager(而不是调用者)的服务帐号负责在读取或写入密文时进行加密和解密。

同样,您无需直接访问 CMEK 密钥即可访问密文。服务帐号会访问密钥,并代表您加密或解密密文。

访问您刚刚创建的密文版本。

gcloud

$ gcloud beta secrets versions access latest \
    --project "${SM_PROJECT_ID}" \
    --secret "my-ummr-secret"

更新 CMEK 配置

在密钥所属的相同区域中创建两个新的对称 KMS 密钥。

gcloud

# us-east1
$ gcloud kms keys create "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-east1" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

# us-central1
$ gcloud kms keys create "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-central1" \
    --keyring "secret-manager-cmek" \
    --purpose "encryption"

向服务帐号授予 Secret Manager 访问权限,以便使用新的 CMEK 密钥进行加密和解密。此命令会向服务帐号授予 my-other-key Cloud KMS 密钥上的 Cloud KMS 加密/解密角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter)。

gcloud

# us-east1
$ gcloud kms keys add-iam-policy-binding "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-east1" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

# us-central1
$ gcloud kms keys add-iam-policy-binding "my-other-key" \
    --project "${KMS_PROJECT_ID}" \
    --location "us-central1" \
    --keyring "secret-manager-cmek" \
    --member "serviceAccount:${SM_SERVICE_ACCOUNT}" \
    --role "roles/cloudkms.cryptoKeyEncrypterDecrypter"

使用新的 Cloud KMS 密钥资源名称更新密文副本,以修改密文的 CMEK 配置。

gcloud

$ gcloud beta secrets replication update my-ummr-secret \
    --set-kms-key="projects/${KMS_PROJECT_ID}/locations/us-east1/keyRings/secret-manager-cmek/cryptoKeys/my-other-key" \
    --location=us-east1 \
    --project "${SM_PROJECT_ID}"

$ gcloud beta secrets replication update my-ummr-secret \
    --set-kms-key="projects/${KMS_PROJECT_ID}/locations/us-central1/keyRings/secret-manager-cmek/cryptoKeys/my-other-key" \
    --location=us-central1 \
    --project "${SM_PROJECT_ID}"

要同时更新密文中的多个密钥,您可以通过文件获取和设置复制政策。

gcloud

$ gcloud beta secrets replication get my-ummr-secret --project "${SM_PROJECT_ID}" --format=json > replication-policy.json

# update the file to reflect desired CMEK configuration
$ edit replication-policy json

$ gcloud beta secrets replication set my-ummr-secret \
    --replication-policy-file=replication-policy.json \
    --project "${SM_PROJECT_ID}"

API

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/my-ummr-secret?updateMask=replication" \
    --request "PATCH" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --header "Content-Type: application/json" \
    --data-binary @- <<EOF
{
  "replication":{
    "userManaged":{
      "replicas":[
        {
          "location":"us-east1",
          "customerManagedEncryption":{
            "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-east1/keyRings/secret-manager-cmek/cryptoKeys/my-other-key"
          }
        },
        {
          "location":"us-central1",
          "customerManagedEncryption":{
            "kmsKeyName":"projects/${KMS_PROJECT_ID}/locations/us-central1/keyRings/secret-manager-cmek/cryptoKeys/my-other-key"
          }
        }]
      }
    }
  }
EOF

查看密文版本 CMEK 配置

如需检查密文版本的元数据(包括密文版本是否启用 CMEK 和 CMEK 密钥版本的资源名称),请查看其元数据。

gcloud

$ gcloud beta secrets versions describe latest --secret my-secret --project "${SM_PROJECT_ID}"

API

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/my-secret/versions/latest" \
    --request "GET" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --header "Content-Type: application/json"

这将返回用于加密密文版本的密钥版本的完整 Cloud KMS 资源名称。

{
  "name": "projects/[PROJECT_NUMBER]/secrets/my-secret/versions/1",
  "createTime": "2020-07-...",
  "state": "ENABLED",
  "replicationStatus": {
    "automatic": {
      "customerManagedEncryption": {
        "kmsKeyVersionName": "projects/[KMS_PROJECT]/locations/global/keyRings/secret-manager-cmek/cryptoKeys/my-cmek-key/cryptoKeyVersions/1"
      }
    }
  }
}

停用 CMEK

通过更新复制政策,从密文中移除 CMEK 配置。

gcloud

$ gcloud beta secrets replication update my-secret --remove-cmek --project "${SM_PROJECT_ID}"

API

$ curl "https://secretmanager.googleapis.com/v1/projects/${SM_PROJECT_ID}/secrets/my-secret?updateMask=replication" \
    --request "PATCH" \
    --header "Authorization: Bearer $(gcloud auth print-access-token)" \
    --header "Content-Type: application/json" \
    --data-binary @- <<EOF
{
  "replication":{
    "automatic":{}
  }
}
EOF

后续步骤