1. 概览
Confidential Space 提供了一个安全的环境,供多方开展协作。此 Codelab 演示了如何使用 Confidential Space 保护敏感知识产权,例如机器学习模型。
在此 Codelab 中,您将使用 Confidential Space 使一家公司能够安全地与另一家想要使用该模型的公司共享其专有的机器学习模型。具体而言,Primus 公司有一个机器学习模型,该模型仅会发布给在 Confidential Space 中运行的工作负载,这使 Primus 能够完全控制其知识产权。Secundus 公司将成为工作负载操作员,并在 Confidential Space 中运行机器学习工作负载。Secundus 将加载此模型,并使用 Secundus 拥有的示例数据运行推理。
在这里,Primus 是工作负载作者,负责编写工作负载代码,也是一位希望保护其知识产权免受不受信任的工作负载操作员 Secundus 侵害的协作者。Secundus 是机器学习工作负载的工作负载操作员。

学习内容
- 如何配置一个环境,使一方可以与另一方共享其专有的机器学习模型,而不会失去对其知识产权的控制权。
所需条件
- 一个 Google Cloud Platform 项目
- 具备 Google Compute Engine(Codelab)、机密虚拟机、容器和远程仓库的基础知识
- 具备 服务账号、 工作负载身份联合和 条件的基础知识。
Confidential Space 设置中涉及的角色
在此 Codelab 中,Primus 公司将成为资源所有者和工作负载作者,负责以下事项:
- 使用机器学习模型设置所需 Cloud 资源
- 编写工作负载代码
- 发布工作负载映像
- 配置工作负载身份池政策,以保护机器学习模型免受不受信任的操作员侵害
Secundus 公司将成为操作员,负责以下事项:
- 设置所需 Cloud 资源,以存储工作负载使用的示例图片和结果
- 使用 Primus 提供的模型在 Confidential Space 中运行机器学习工作负载
Confidential Space 的运作方式
在 Confidential Space 中运行工作负载时,系统会使用配置的资源执行以下流程:
- 工作负载从 工作负载身份池 请求
$PRIMUS_SERVICEACCOUNT的通用 Google 访问令牌。它提供了一个包含工作负载和环境声明的证明验证器服务令牌。 - 如果 证明验证器服务 令牌中的工作负载衡量声明与 WIP 中的属性条件匹配,则它会返回
$PRIMUS_SERVICEACCOUNT.的访问令牌。 - 工作负载使用与
$PRIMUS_SERVICEACCOUNT关联的服务账号访问令牌,以访问存储在$PRIMUS_INPUT_STORAGE_BUCKET存储分区中的机器学习模型。 - 工作负载对 Secundus 拥有的数据执行操作,并且该工作负载由 Secundus 在其项目中运行。
- 工作负载使用
$WORKLOAD_SERVICEACCOUNT服务账号将该操作的结果写入$SECUNDUS_RESULT_STORAGE_BUCKET存储分区。
2. 设置 Cloud 资源
准备工作
- 使用以下命令克隆 此代码库,以获取此 Codelab 中使用的必要脚本。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
- 更改此 Codelab 的目录。
cd confidential-space/codelabs/ml_model_protection/scripts
export PRIMUS_PROJECT_ID=<GCP project id of Primus>
export SECUNDUS_PROJECT_ID=<GCP project id of Secundus>
- 为您的项目启用结算功能。
- 为这两个项目启用 Confidential Computing API 和以下 API。
gcloud services enable \
cloudapis.googleapis.com \
cloudresourcemanager.googleapis.com \
cloudshell.googleapis.com \
container.googleapis.com \
containerregistry.googleapis.com \
iam.googleapis.com \
confidentialcomputing.googleapis.com
- 使用以下命令为上述指定的资源名称的变量分配值。借助这些变量,您可以根据需要自定义资源名称,还可以使用已创建的现有资源。(例如
export PRIMUS_INPUT_STORAGE_BUCKET='my-input-bucket')
- 您可以使用 Primus 项目中的现有 Cloud 资源名称设置以下变量。如果设置了变量,则会使用 Primus 项目中相应的现有 Cloud 资源。如果未设置变量,则会根据项目名称生成 Cloud 资源名称,并使用该名称创建新的 Cloud 资源。以下是资源名称支持的变量:
| 存储 Primus 的机器学习模型的存储分区。 |
| Primus 的工作负载身份池 (WIP),用于验证声明。 |
| Primus 的工作负载身份池提供方,其中包含用于证明验证器服务签名的令牌的授权条件。 |
| Primus 服务账号, |
| 制品库,工作负载 Docker 映像将推送到该制品库。 |
- 您可以使用 Secundus 项目中的现有 Cloud 资源名称设置以下变量。如果设置了变量,则会使用 Secundus 项目中相应的现有 Cloud 资源。如果未设置变量,则会根据项目名称生成 Cloud 资源名称,并使用该名称创建新的 Cloud 资源。以下是资源名称支持的变量:
| 存储 Secundus 想要使用 Primus 提供的模型进行分类的示例图片的存储分区。 |
| 存储工作负载结果的存储分区。 |
| 工作负载容器映像的名称。 |
| 工作负载容器映像的标记。 |
| 有权访问运行工作负载的机密虚拟机的服务账号。 |
- 您需要这两个项目的某些权限,您可以参阅 此指南,了解如何使用 GCP 控制台授予 IAM 角色:
- 对于
$PRIMUS_PROJECT_ID,您需要 Storage Admin、Artifact Registry Administrator、Service Account Admin、IAM 工作负载身份池 Admin。 - 对于
$SECUNDUS_PROJECT_ID,您需要 Compute Admin、Storage Admin、服务账号 Admin、IAM 工作负载身份池 Admin、Security Admin(可选)。 - 运行以下 脚本,根据您的项目 ID 为其余变量名称设置资源名称的值。
source config_env.sh
设置 Primus 公司资源
在此步骤中,您将为 Primus 设置所需的 Cloud 资源。运行以下 脚本,为 Primus 设置资源。在脚本执行过程中,系统将创建以下资源:
- Cloud Storage 存储分区 (
$PRIMUS_INPUT_STORAGE_BUCKET),用于存储 Primus 的机器学习模型。 - 工作负载身份池 (
$PRIMUS_WORKLOAD_IDENTITY_POOL),用于根据其提供方下配置的 属性条件 验证声明。 - 服务账号 (
$PRIMUS_SERVICEACCOUNT),附加到上述工作负载身份池 ($PRIMUS_WORKLOAD_IDENTITY_POOL),具有 IAM 访问权限,可从 Cloud Storage 存储分区读取数据(使用objectViewer角色),并将此服务账号连接到工作负载身份池(使用roles/iam.workloadIdentityUser角色)。
在此 Cloud 资源设置过程中,我们将使用 TensorFlow 模型。我们可以将包含模型架构、权重和训练配置的整个模型保存到 ZIP 归档中。在此 Codelab 中,我们将使用在此处找到的在 ImageNet 数据集上训练的 MobileNet V1 模型。
./setup_primus_company_resources.sh
上述脚本将设置 Cloud 资源,我们现在将模型下载并发布到脚本创建的 Cloud Storage 存储分区。
- 从 此处 下载预训练模型。
- 下载完成后,将下载的 tar 文件重命名为 model.tar.gz 。
- 使用包含 model.tar.gz 文件的目录中的以下命令,将 model.tar.gz 文件发布到 Cloud Storage 存储分区。
gsutil cp model.tar.gz gs://${PRIMUS_INPUT_STORAGE_BUCKET}/
设置 Secundus 公司资源
在此步骤中,您将为 Secundus 设置所需的 Cloud 资源。运行以下 脚本,为 Secundus 设置资源。在这些步骤中,系统将创建以下资源:
- Cloud Storage 存储分区 (
$SECUNDUS_INPUT_STORAGE_BUCKET),用于存储 Secundus 运行推理的示例图片。 - Cloud Storage 存储分区 (
$SECUNDUS_RESULT_STORAGE_BUCKET),用于存储 Secundus 执行机器学习工作负载的结果。
在此 Codelab 中,我们提供了一些示例图片 here。
./setup_secundus_company_resources.sh
3. 创建工作负载
创建工作负载服务账号
现在,您将为工作负载创建一个具有所需角色和权限的服务账号。运行以下 脚本,在 Secundus 项目中创建工作负载服务账号。此服务账号将由运行机器学习工作负载的虚拟机使用。
此工作负载服务账号 ($WORKLOAD_SERVICEACCOUNT) 将具有以下角色:
confidentialcomputing.workloadUser,用于获取证明令牌logging.logWriter,用于将日志写入 Cloud Logging。objectViewer,用于从$SECUNDUS_INPUT_STORAGE_BUCKETCloud Storage 存储分区读取数据。objectUser,用于将工作负载结果写入$SECUNDUS_RESULT_STORAGE_BUCKETCloud Storage 存储分区。
./create_workload_service_account.sh
创建工作负载
在此步骤中,您将创建工作负载 Docker 映像。工作负载将由 Primus 编写。此 Codelab 中使用的工作负载是机器学习 Python 代码,该代码访问存储在 Primus 存储分区中的机器学习模型,并使用存储在存储分区中的示例图片运行推理。
只有满足所需属性条件的工作负载才能访问存储在 Primus 存储分区中的机器学习模型。下一部分将详细介绍这些属性条件,内容是关于为工作负载授权。
以下是将在本 Codelab 中创建和使用的工作负载的 run_inference() 方法。您可以在此处找到完整的工作负载代码 here。
def run_inference(image_path, model):
try:
# Read and preprocess the image
image = tf.image.decode_image(tf.io.read_file(image_path), channels=3)
image = tf.image.resize(image, (128, 128))
image = tf.image.convert_image_dtype(image, tf.float32)
image = tf.expand_dims(image, axis=0)
# Get predictions from the model
predictions = model(image)
predicted_class = np.argmax(predictions)
top_k = 5
top_indices = np.argsort(predictions[0])[-top_k:][::-1]
# Convert top_indices to a TensorFlow tensor
top_indices_tensor = tf.convert_to_tensor(top_indices, dtype=tf.int32)
# Use TensorFlow tensor for indexing
top_scores = tf.gather(predictions[0], top_indices_tensor)
return {
"predicted_class": int(predicted_class),
"top_k_predictions": [
{"class_index": int(idx), "score": float(score)}
for idx, score in zip(top_indices, top_scores)
],
}
except Exception as e:
return {"error": str(e)}
运行以下 脚本 以创建工作负载,其中执行以下步骤:
- 创建由 Primus 拥有的 Artifact Registry(
$PRIMUS_ARTIFACT_REGISTRY)。 - 使用所需的资源名称更新工作负载代码。
- 构建机器学习工作负载,并创建 Dockerfile 以构建工作负载代码的 Docker 映像。 以下是此 Codelab 中使用的 Dockerfile。
- 构建 Docker 映像并将其发布到由 Primus 拥有的 Artifact Registry (
$PRIMUS_ARTIFACT_REGISTRY)。 - 为
$PRIMUS_ARTIFACT_REGISTRY授予$WORKLOAD_SERVICEACCOUNT读取权限。这是工作负载容器从 Artifact Registry 中拉取工作负载 Docker 映像所必需的。
./create_workload.sh
此外,工作负载还可以通过编码来确保在机器学习模型使用之前检查其哈希或签名,从而加载预期版本的机器学习模型。这种额外检查的优势在于,它可以确保机器学习模型的完整性。这样,当工作负载需要使用不同版本的机器学习模型时,工作负载操作员还需要更新工作负载映像或其参数。
4. 为工作负载授权并运行工作负载
为工作负载授权
Primus 希望根据以下资源的特性为工作负载授权,以访问其机器学习模型:
- 内容:经过验证的代码
- 位置:安全的环境
- 人员:受信任的操作员
Primus 使用 工作负载身份联合 来根据这些要求强制执行访问政策。借助工作负载身份联合,您可以指定 属性条件。这些条件限制了哪些身份可以使用 工作负载身份池 (WIP) 进行身份验证。您可以将证明验证器服务作为 工作负载身份池提供方 添加到 WIP,以呈现度量并强制执行政策。
Workload Identity 池已在之前的 Cloud 资源设置步骤中创建。现在,Primus 将创建一个新的 OIDC 工作负载身份池提供方。指定的 --attribute-condition 授权访问工作负载容器。它需要:
- 内容:上传到
$PRIMUS_ARTIFACT_REPOSITORY仓库的最新$WORKLOAD_IMAGE_NAME。 - 位置:Confidential Space 可信执行环境在完全受支持的 Confidential Space 虚拟机映像上运行。
- 人员:Secundus
$WORKLOAD_SERVICE_ACCOUNT服务账号。
export WORKLOAD_IMAGE_DIGEST=$(gcloud artifacts docker images describe ${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG --format="value(image_summary.digest)" --project ${PRIMUS_PROJECT_ID})
gcloud config set project $PRIMUS_PROJECT_ID
gcloud iam workload-identity-pools providers create-oidc $PRIMUS_WIP_PROVIDER \
--location="global" \
--workload-identity-pool="$PRIMUS_WORKLOAD_IDENTITY_POOL" \
--issuer-uri="https://confidentialcomputing.googleapis.com/" \
--allowed-audiences="https://sts.googleapis.com" \
--attribute-mapping="google.subject='assertion.sub'" \
--attribute-condition="assertion.swname == 'CONFIDENTIAL_SPACE' &&
'STABLE' in assertion.submods.confidential_space.support_attributes &&
assertion.submods.container.image_digest == '${WORKLOAD_IMAGE_DIGEST}' &&
assertion.submods.container.image_reference == '${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG' &&
'$WORKLOAD_SERVICEACCOUNT@$SECUNDUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"
运行工作负载
在此步骤中,我们将在 Confidential Space 虚拟机中运行工作负载。所需的 TEE 实参通过 元数据标志 传递。工作负载容器的实参通过标志的“tee-cmd”部分传递。工作负载执行的结果将发布到 $SECUNDUS_RESULT_STORAGE_BUCKET。
gcloud compute instances create ${WORKLOAD_VM} \
--confidential-compute-type=SEV \
--shielded-secure-boot \
--project=${SECUNDUS_PROJECT_ID} \
--maintenance-policy=MIGRATE \
--scopes=cloud-platform --zone=${SECUNDUS_PROJECT_ZONE} \
--image-project=confidential-space-images \
--image-family=confidential-space \
--service-account=${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com \
--metadata ^~^tee-image-reference=${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/${PRIMUS_PROJECT_ID}/${PRIMUS_ARTIFACT_REPOSITORY}/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}
查看结果
工作负载成功完成后,机器学习工作负载的结果将发布到 $SECUNDUS_RESULT_STORAGE_BUCKET。
gsutil cat gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result
以下是一些示例,展示了示例图片的推理结果可能是什么样子:
Image: sample_image_1.jpeg, Response: {'predicted_class': 531, 'top_k_predictions': [{'class_index': 531, 'score': 12.08437442779541}, {'class_index': 812, 'score': 10.269512176513672}, {'class_index': 557, 'score': 9.202644348144531}, {'class_index': 782, 'score': 9.08737564086914}, {'class_index': 828, 'score': 8.912498474121094}]}
Image: sample_image_2.jpeg, Response: {'predicted_class': 905, 'top_k_predictions': [{'class_index': 905, 'score': 9.53619384765625}, {'class_index': 557, 'score': 7.928380966186523}, {'class_index': 783, 'score': 7.70129919052124}, {'class_index': 531, 'score': 7.611623287200928}, {'class_index': 906, 'score': 7.021416187286377}]}
Image: sample_image_3.jpeg, Response: {'predicted_class': 905, 'top_k_predictions': [{'class_index': 905, 'score': 6.09878396987915}, {'class_index': 447, 'score': 5.992854118347168}, {'class_index': 444, 'score': 5.9582319259643555}, {'class_index': 816, 'score': 5.502010345458984}, {'class_index': 796, 'score': 5.450454235076904}]}
对于 Secundus 存储分区中的每个示例图片,您都会在结果中看到一个条目。此条目将包含两个关键信息:
- predicted_class 的索引 :这是一个数值索引,表示模型预测图片所属的类别。
- Top_k_predictions: :这为图片提供了最多 k 个预测,从最有可能到最不可能进行排名。在此 Codelab 中,k 的值设置为 5,但您可以在工作负载代码中调整它以获取更多或更少的预测。
如需将类别索引转换为人类可读的类别名称,请参阅此处提供的标签列表 here。例如,如果您看到类别索引为 2,则它对应于标签列表中的类别标签“tench”。
在此 Codelab 中,我们演示了 Primus 拥有的模型仅发布给在 TEE 中运行的工作负载。Secundus 在 TEE 中运行机器学习工作负载,并且此工作负载能够使用 Primus 拥有的模型,而 Primus 保留对模型的完全控制权。
运行未经授权的工作负载
Secundus 通过从自己的制品库中拉取不同的工作负载映像来更改工作负载映像,该映像未经 Primus 授权。Primus 的工作负载身份池仅授权了 ${PRIMUS_PROJECT_REPOSITORY_REGION}-docker.pkg.dev/$PRIMUS_PROJECT_ID/$PRIMUS_ARTIFACT_REPOSITORY/$WORKLOAD_IMAGE_NAME:$WORKLOAD_IMAGE_TAG 工作负载映像。
重新运行工作负载
当 Secundus 尝试使用此新工作负载映像运行原始工作负载时,它将失败。如需查看错误,请删除原始结果文件和虚拟机实例,然后尝试再次运行工作负载。
请确保 Secundus 的 Artifact Registry 下发布了新的 Docker 映像(如 us-docker.pkg.dev/${SECUNDUS_PROJECT_ID}/custom-image/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}),并且工作负载服务账号 ($WORKLOAD_SERVICEACCOUNT) 已授予 Artifact Registry 读取器权限以读取此新工作负载映像。这是为了确保工作负载不会在 Primus 的 WIP 政策拒绝工作负载提供的令牌之前退出。
删除现有结果文件和虚拟机实例
- 将项目设置为
$SECUNDUS_PROJECT_ID项目。
gcloud config set project $SECUNDUS_PROJECT_ID
- 删除结果文件。
gsutil rm gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result
- 删除机密虚拟机实例。
gcloud compute instances delete ${WORKLOAD_VM} --zone=${SECUNDUS_PROJECT_ZONE}
运行未经授权的工作负载:
gcloud compute instances create ${WORKLOAD_VM} \
--confidential-compute-type=SEV \
--shielded-secure-boot \
--maintenance-policy=MIGRATE \
--scopes=cloud-platform --zone=${SECUNDUS_PROJECT_ZONE} \
--image-project=confidential-space-images \
--image-family=confidential-space \
--service-account=${WORKLOAD_SERVICEACCOUNT}@${SECUNDUS_PROJECT_ID}.iam.gserviceaccount.com \
--metadata ^~^tee-image-reference=us-docker.pkg.dev/${SECUNDUS_PROJECT_ID}/custom-image/${WORKLOAD_IMAGE_NAME}:${WORKLOAD_IMAGE_TAG}
查看错误
您看到的不是工作负载的结果,而是错误 (The given credential is rejected by the attribute condition)。
gsutil cat gs://$SECUNDUS_RESULT_STORAGE_BUCKET/result
5. 清理
以下脚本可用于清理我们在本 Codelab 中创建的资源。在此清理过程中,系统将删除以下资源:
- Primus 的输入存储分区 (
$PRIMUS_INPUT_STORAGE_BUCKET)。 - Primus 服务账号 (
$PRIMUS_SERVICEACCOUNT)。 - Primus 的制品库 (
$PRIMUS_ARTIFACT_REPOSITORY)。 - Primus 工作负载身份池 (
$PRIMUS_WORKLOAD_IDENTITY_POOL)。 - Secundus 的工作负载服务账号 (
$WORKLOAD_SERVICEACCOUNT)。 - Secundus 的输入存储分区 (
$SECUNDUS_INPUT_STORAGE_BUCKET)。 - 工作负载计算实例。
- Secundus 的结果存储分区 (
$SECUNDUS_RESULT_STORAGE_BUCKET)。
$ ./cleanup.sh
如果您已完成探索,请考虑删除您的项目。
- 前往 Cloud Platform 控制台
- 选择要关停的项目,然后点击顶部的“删除”:这会将项目安排为删除
后续操作
查看下列类似 Codelab…