1. 简介
概览
Cloud Functions 是一个轻量级计算解决方案,可供开发者创建单一用途的独立函数,无需管理服务器或运行时环境即可对云端事件作出响应。
您可以使用 Cloud Key Management Service 客户管理的加密密钥 (CMEK) 来保护 Cloud Functions 和相关静态数据。部署具有 CMEK 的函数后,您可以使用完全由您控制的加密密钥保护与其关联的数据。这种类型的加密使您能够满足某些行业(例如金融服务)的合规性要求。由于密钥由您自己拥有,并且不受 Google 控制,因此在停用或销毁密钥时,没有人(包括您)可以访问受这些加密密钥保护的数据。
对于 Cloud Functions,CMEK 会加密以下内容:
- 上传用于部署且由 Google 存储在 Cloud Storage 中的函数源代码,这些源代码将用于构建流程。
- 函数构建流程的结果,包括通过函数源代码构建的容器映像、已部署的函数的每个实例。
- 内部事件传输渠道的静态数据(仅限第 1 代)。
如需详细了解哪些数据会加密,请参阅 Cloud Functions CMEK 文档。
构建内容
此 Codelab 展示了如何部署使用 CMEK 加密的 Cloud Functions 函数(第 1 代或第 2 代)。本 Codelab 使用公开的 Cloud Function(即不需要身份验证的 Cloud Function)进行演示。您可以像调用任何其他需要进行身份验证的 Cloud Functions 函数一样,调用已启用 CMEK 的经过身份验证的函数。
学习内容
- 如何在现有对称密钥环中创建 CMEK 密钥
- 如何创建 Artifact Registry 代码库
- 如何为第 1 代和第 2 代 Cloud Functions 配置 CMEK
2. 设置和要求
前提条件
- 您已登录 Cloud 控制台
- 您之前已部署 HTTP 触发的 Cloud Function(以验证您是否拥有适当的角色并已启用相应的 API)
激活 Cloud Shell
- 在 Cloud Console 中,点击激活 Cloud Shell
。

如果您是第一次启动 Cloud Shell,系统会显示一个介绍其功能的过渡页面。如果您看到了过渡页面,请点击继续。

预配和连接到 Cloud Shell 只需花几分钟时间。

这个虚拟机已加载了所需的所有开发工具。它提供了一个持久的 5 GB 主目录,并且在 Google Cloud 中运行,大大增强了网络性能和身份验证。只需使用一个浏览器即可完成本 Codelab 中的大部分工作。
连接到 Cloud Shell 后,您应该会看到自己已通过身份验证,并且相关项目已设置为您的项目 ID。
- 在 Cloud Shell 中运行以下命令以确认您已通过身份验证:
gcloud auth list
命令输出
Credentialed Accounts
ACTIVE ACCOUNT
* <my_account>@<my_domain.com>
To set the active account, run:
$ gcloud config set account `ACCOUNT`
- 在 Cloud Shell 中运行以下命令,以确认 gcloud 命令了解您的项目:
gcloud config list project
命令输出
[core] project = <PROJECT_ID>
如果不是上述结果,您可以使用以下命令进行设置:
gcloud config set project <PROJECT_ID>
命令输出
Updated property [core/project].
3. 为 Cloud Functions 创建新的密钥环和密钥
运行以下命令,确保 Cloud KMS API 已启用:
gcloud services enable cloudkms.googleapis.com
首先,创建环境变量以包含密钥环名称、密钥名称、区域和此 Codelab 中使用的其他变量。
KEYRING_NAME="keyring-functions" REGION="us-central1" KEY_NAME="key-encrypted-function" PROJECT_ID=$(gcloud config get-value project) PROJECT_NUMBER="$(gcloud projects describe $PROJECT_ID --format='value(projectNumber)')" USER_EMAIL="$(gcloud config list account --format "value(core.account)")"
接下来,创建 密钥环,它是 Cloud KMS 密钥和密钥版本的根资源。
gcloud kms keyrings create $KEYRING_NAME --location $REGION
最后,您现在可以在 Cloud KMS 中新创建的密钥环内创建对称密钥。
gcloud kms keys create $KEY_NAME --keyring $KEYRING_NAME --location $REGION --purpose "encryption"
4. 创建启用 CMEK 的 Docker 格式 Artifact Registry 代码库
在本部分中,您将在 Artifact Registry 中创建一个启用 CMEK 的 Docker 格式代码库。此密钥将与用于部署 Cloud Functions 函数的密钥相同。
首先,您需要 Artifact Registry 的服务账号。您可以通过运行以下命令来创建该文件:
gcloud beta services identity create --service=artifactregistry.googleapis.com --project=$PROJECT_ID
使用以下命令向 Artifact Registry 服务账号授予 CryptoKey Encrypter/Decrypter IAM 角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter),以便该服务账号拥有对密钥的权限:
gcloud kms keys add-iam-policy-binding \ $KEY_NAME --location $REGION --keyring=$KEYRING_NAME \ --member serviceAccount:service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com \ --role roles/cloudkms.cryptoKeyEncrypterDecrypter
并将该角色授予将在 Artifact Registry 中创建 Repo 的主账号,例如您当前使用的活跃账号。您可以运行 gcloud auth list 来验证当前活跃的账号。
gcloud kms keys add-iam-policy-binding \
$KEY_NAME --location $REGION --keyring=$KEYRING_NAME \
--member user:$USER_EMAIL \
--role roles/cloudkms.cryptoKeyEncrypterDecrypter
现在,您可以创建启用了 CMEK 的 Docker 格式代码库。
注意:该区域必须与 CMEK 密钥位于同一区域。
REPO_NAME=my-cmek-encrypted-repo
KEY_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/keyRings/"$KEYRING_NAME"/cryptoKeys/"$KEY_NAME"
gcloud artifacts repositories create $REPO_NAME \
--repository-format=docker \
--location=$REGION \
--kms-key=$KEY_FULLPATH \
--async
您可以运行以下命令来查看新的 Artifact Registry 代码库:
gcloud artifacts repositories describe $REPO_NAME --location=$REGION
5. 向服务账号授予对密钥的访问权限(第 2 代)
本部分介绍了如何为第 2 代函数创建服务账号。如果您要创建第 1 代函数,请继续学习下一部分。
您必须授予多个服务代理对密钥的访问权限,方法是授予 CryptoKey Encrypter/Decrypter IAM 角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter)。这些服务代理用于获取对 Cloud Storage 中存储的源代码的访问权限、在 Artifact Registry 中受 CMEK 保护的代码库中存储函数映像,以及部署经过 CMEK 加密的 Cloud Functions 函数。
第 2 代函数的步骤
- 向 Cloud Run 服务代理授予对密钥的访问权限:
CLOUDRUN_SA=service-$PROJECT_NUMBER@serverless-robot-prod.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$CLOUDRUN_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
- 向 Eventarc 服务代理授予对密钥的访问权限:
EVENTARC_SA=service-$PROJECT_NUMBER@gcp-sa-eventarc.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$EVENTARC_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
- 向 Artifact Registry 服务代理授予对密钥的访问权限:
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$AR_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
- 向 Cloud Storage 服务代理授予对密钥的访问权限:
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$STORAGE_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
在下一部分中,您将了解如何创建和部署 CMEK 加密函数。
6. 向服务账号授予对密钥的访问权限(第 1 代)
本部分介绍如何为第 1 代函数创建服务账号。如果您之前已为第 2 代函数创建服务账号,请继续前往下一部分。
您必须授予多个服务代理对密钥的访问权限,方法是授予 CryptoKey Encrypter/Decrypter IAM 角色 (roles/cloudkms.cryptoKeyEncrypterDecrypter)。这些服务代理用于获取对 Cloud Storage 中存储的源代码的访问权限、在 Artifact Registry 中受 CMEK 保护的代码库中存储函数映像,以及部署经过 CMEK 加密的 Cloud Functions 函数。
第 1 代函数的步骤
- 向 Cloud Functions 服务代理授予对密钥的访问权限:
FUNCTION_SA=service-$PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$FUNCTION_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
- 向 Artifact Registry 服务代理授予对密钥的访问权限:
AR_SA=service-$PROJECT_NUMBER@gcp-sa-artifactregistry.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$AR_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
- 向 Cloud Storage 服务代理授予对密钥的访问权限:
STORAGE_SA=service-$PROJECT_NUMBER@gs-project-accounts.iam.gserviceaccount.com gcloud kms keys add-iam-policy-binding $KEY_NAME \ --keyring=$KEYRING_NAME \ --location=$REGION \ --member=serviceAccount:$STORAGE_SA \ --role=roles/cloudkms.cryptoKeyEncrypterDecrypter
在下一部分中,您将了解如何创建和部署 CMEK 加密函数。
7. 创建 CMEK 加密的函数(第 2 代)
本部分介绍了如何创建第 2 代函数。您可以继续阅读下一部分,了解第 1 代设备的说明。
现在,您已配置启用了 CMEK 的 Artifact Registry 代码库,并已授予 Cloud Functions 对您的密钥的访问权限,接下来可以部署使用您的 CMEK 密钥加密的函数了。
第 2 代函数的步骤:
创建函数的源代码
虽然此 Codelab 使用 Node.js,但您可以使用任何受支持的运行时。
首先,创建一个目录,然后通过 cd 命令进入该目录。
mkdir ~/cmek-function-2ndgen && cd $_
然后,创建 package.json 文件。
touch package.json
echo '{
"dependencies": {
"@google-cloud/functions-framework": "^2.1.0"
}
}
' > package.json
接下来,创建 index.js 源文件。
touch index.js
echo 'const functions = require("@google-cloud/functions-framework");
functions.http("helloWorld", (req, res) => {
res.send(`Hello ${req.query.name || req.body.name || "World"}!`);
});' > index.js
使用 CMEK 加密部署第 2 代 Cloud Functions 函数
注意:以下示例展示了如何使用当前目录中的来源部署函数。确保您位于与函数源代码相同的目录中。
FUNCTION_NAME=protect-me-cmek-2ndgen ENTRY_POINT=helloWorld REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME gcloud beta functions deploy $FUNCTION_NAME \ --gen2 \ --region $REGION \ --kms-key $KEY_FULLPATH \ --docker-repository $REPO_FULLPATH \ --source . \ --trigger-http \ --allow-unauthenticated \ --runtime nodejs16 \ --entry-point $ENTRY_POINT
您可以通过运行以下命令,从生成的输出中查看 CMEK 密钥
gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName
测试第 2 代函数
您可以通过 curl 命令测试函数:
FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(serviceConfig.uri)')" curl $FUNCTION_URL
这会产生以下结果:
Hello World!
只要加密密钥处于启用状态,该函数就会向调用方返回成功。不过,一旦加密密钥被停用,调用者就会收到错误。
在下一部分中,您将看到在停用密钥后调用函数时会发生什么情况。
8. 创建 CMEK 加密的函数(第 1 代)
本部分介绍了如何创建第 1 代函数。如果您之前创建过第 2 代函数,请继续学习下一部分。
现在,您已配置启用了 CMEK 的 Artifact Registry 代码库,并已授予 Cloud Functions 对您的密钥的访问权限,接下来可以部署使用您的 CMEK 密钥加密的函数了。
第 1 代函数的步骤:
为第 1 代函数创建源代码
虽然此 Codelab 使用 Node.js,但您可以使用任何受支持的运行时。
首先,创建一个目录,然后通过 cd 命令进入该目录。
mkdir ~/cmek-function-1stgen && cd $_
接下来,创建 package.json 文件。
touch package.json
echo '{
"name": "function-cmek-codelab",
"version": "0.0.1"
}' > package.json
然后,创建 index.js 源文件。
touch index.js
echo "exports.helloWorld = (req, res) => {
let message = req.query.message || req.body.message || 'Hello World!';
res.status(200).send(message);
};" > index.js
使用 CMEK 加密部署第 1 代 Cloud Functions 函数
注意:以下示例展示了如何使用当前目录中的来源部署函数。确保您位于与函数源代码相同的目录中。
FUNCTION_NAME=protect-me-cmek-1stgen ENTRY_POINT=helloWorld REPO_FULLPATH=projects/"$PROJECT_ID"/locations/"$REGION"/repositories/$REPO_NAME gcloud functions deploy $FUNCTION_NAME \ --region $REGION \ --kms-key $KEY_FULLPATH \ --docker-repository $REPO_FULLPATH \ --source . \ --trigger-http \ --allow-unauthenticated \ --runtime nodejs16 \ --entry-point $ENTRY_POINT
您可以通过运行以下命令,从生成的输出中查看 CMEK 密钥
gcloud functions describe $FUNCTION_NAME –region $REGION | grep kmsKeyName
测试第 1 代函数
您可以通过 curl 命令测试函数:
FUNCTION_URL="$(gcloud functions describe $FUNCTION_NAME --region $REGION --format='get(httpsTrigger.url)')" curl $FUNCTION_URL
这会产生以下结果:
Hello World!
只要加密密钥处于启用状态,该函数就会向调用方返回成功。不过,一旦加密密钥被停用,调用者就会收到错误。
在下一部分中,您将看到在停用密钥后调用函数时会发生什么情况。
9. 调用加密密钥已停用的 CMEK 加密函数
在本部分中,您将使密钥失效,然后再次调用该函数,以查看生成的错误。
停用加密密钥
您可以运行此命令来停用密钥。由于此 Codelab 仅创建一个版本的密钥,因此您将停用版本 1。
gcloud kms keys versions disable 1 \
--key=$KEY_NAME \
--keyring=$KEYRING_NAME \
--location=$REGION
您应该会看到相应信息:
algorithm: GOOGLE_SYMMETRIC_ENCRYPTION createTime: '2023-04-11T03:30:49.111832653Z' generateTime: '2023-04-11T03:30:49.111832653Z' name: projects/dogfood-gcf-saraford/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function/cryptoKeyVersions/1 protectionLevel: SOFTWARE state: DISABLED
使用已停用的密钥调用函数
现在,再次 curl 该函数。
curl $FUNCTION_URL
并且您这次不会收到 Hello World 响应。
在 Cloud Functions 函数的日志中,您会看到
User's CMEK key has been disabled. CMEK key: projects/<PROJECT-NAME>/locations/us-central1/keyRings/myKeyRing/cryptoKeys/encrypted-function
尝试在 CMEK 密钥停用时查看资源
在本部分中,您将看到在停用 CMEK 密钥后,以下资源会变得不可用:
- 函数源代码
- 根据源代码构建的容器映像
例如,访问 Cloud Functions 的“来源”标签页时,系统会显示提取归档文件时出错。如果您尝试直接在 Cloud Storage 中查看包含源代码的 .zip 文件,也会收到类似的错误。

此外,您将无法访问 Artifact Registry 中的函数容器映像。例如,如果您尝试将该容器映像部署到 Cloud Run,系统会显示一条错误消息,指出找不到该映像。
10. 恭喜
恭喜,您已完成此 Codelab!
所学内容
- 如何在现有对称密钥环中创建 CMEK 密钥
- 如何创建 Artifact Registry 代码库
- 如何在 Cloud Functions 上配置 CMEK
如需了解详情
如需详细了解 Cloud Functions 和 CMEK,请参阅以下链接: