可信空间 Codelab

1. 概览

准备好提升 GPU 加速型工作负载的安全性和隐私性了吗?此 Codelab 将引导您全面了解可信空间的功能。该产品可为敏感的 AI/ML 工作负载提供强大的运维员隔离和加速器支持。

保护有价值的数据、模型和密钥变得比以往更加重要。Trusted Space 可确保您的工作负载在安全可信的环境中运行,即使工作负载操作员也无权访问。

可信空间提供以下功能

  • 增强型隐私保护和安全性:Trusted Space 可提供可信执行环境,在该环境中,您的敏感资产(例如模型、重要数据和密钥)将得到保护,并由加密证明提供支持。
  • 运营商隔离:消除对运营商干扰的担忧。借助可信空间,即使您的工作负载运维人员也无法访问,从而阻止他们使用 SSH 连接、访问数据、安装软件或篡改代码。
  • 加速器支持:可信空间旨在与各种硬件加速器(包括 H100、A100、T4 和 L4 等 GPU)无缝协作。这可确保性能关键型 AI/ML 应用顺畅运行。

学习内容

  • 了解可信空间的主要产品和服务。
  • 了解如何部署和配置可信空间环境,以保护 AI/机器学习工作负载的重要资产。

所需条件

使用 Primus Company 保护敏感的代码生成提示

在本 Codelab 中,我们将扮演 Primus 公司的角色,该公司非常重视员工数据的隐私和安全。Primus 希望部署代码生成模型,以协助其开发者完成编码任务。不过,他们担心无法保护员工提交的问题的机密性,因为这些问题通常包含敏感的代码段、内部项目详细信息或专有算法。

为什么 Primus 公司不信任运营商?

Primus Corp 在竞争激烈的市场中运营。其代码库包含宝贵的知识产权,包括可提供竞争优势的专有算法和敏感代码段。他们担心工作负载运营商可能会进行企业间谍活动。此外,员工提示可能包含 Primus Corp 想要保护的代码的“需要知道”部分。

为了解决此问题,Primus Corp 将利用可信空间来隔离运行模型以生成代码的推理服务器。其工作原理如下:

  • 提示加密:在向推理服务器发送提示之前,每位员工都会使用 Primus Corp 在 Google Cloud 中管理的 KMS 密钥对其进行加密。这样可以确保只有包含相应解密密钥的可信空间环境才能对其进行解密并访问明文提示。在实际场景中,可用库(例如 tink)可以处理客户端加密。在本 Codelab 中,我们将使用此示例客户端应用搭配封信加密功能。
  • 运算符隔离:只有在 Trusted Space 环境中运行的推理服务器才能访问用于加密的密钥,并且能够在可信环境中解密提示。对加密密钥的访问将受到 Workload Identity 池的保护。由于 Trusted Space 的隔离保证,即使工作负载运维人员也无法访问用于加密的密钥和解密内容。
  • 使用加速器进行安全推理:推理服务器将在安全强化型虚拟机上启动(作为可信空间设置的一部分),这将确保工作负载实例未因启动级或内核级恶意软件rootkit 而遭到破坏。该服务器会在可信空间环境中解密提示,使用代码生成模型执行推理,并将生成的代码返回给员工。

2. 设置 Cloud 资源

准备工作

  • 使用以下命令克隆 此代码库,以获取此 Codelab 中所需的脚本。
git clone https://github.com/GoogleCloudPlatform/confidential-space.git
  • 更改此 Codelab 的目录。
cd confidential-space/codelabs/trusted_space_codelab/scripts
  • 确保您已设置所需的项目环境变量,如下所示。如需详细了解如何设置 GCP 项目,请参阅 此 Codelab。您可以参阅此处,详细了解如何检索项目 ID,以及项目 ID 与项目名称和项目编号的区别。
export PRIMUS_PROJECT_ID=<GCP project id of Primus>
  • 为您的项目启用结算功能
  • 为这两个项目启用 Confidential Computing API 和以下 API。
gcloud services enable \
    cloudapis.googleapis.com \
    cloudresourcemanager.googleapis.com \
    cloudkms.googleapis.com \
    cloudshell.googleapis.com \
    container.googleapis.com \
    containerregistry.googleapis.com \
    iam.googleapis.com \
    confidentialcomputing.googleapis.com
  • 使用以下命令为上述资源名称的变量分配值。借助这些变量,您可以根据需要自定义资源名称,还可以使用已创建的现有资源。(例如 export PRIMUS_SERVICE_ACCOUNT='my-service-account'
  1. 您可以在 Primus 项目中使用现有云资源名称设置以下变量。如果设置了该变量,则系统会使用 Primus 项目中的相应现有云资源。如果未设置该变量,系统会根据 project-name 生成云资源名称,并使用该名称创建新的云资源。以下是资源名称支持的变量:

$PRIMUS_PROJECT_REGION

为 Primus 公司创建地区性资源时所属的地区。

$PRIMUS_SERVICE_LOCATION

为 Primus 公司创建资源的位置。

$PRIMUS_PROJECT_ZONE

为 Primus 公司创建可用区级资源时所属的可用区。

$PRIMUS_WORKLOAD_IDENTITY_POOL

Primus 公司的工作负载身份池,用于保护云资源。

$PRIMUS_WIP_PROVIDER

Primus 公司的工作负载身份池提供方,其中包含要用于由 Attestation Verifier Service 签名的令牌的授权条件。

$PRIMUS_SERVICEACCOUNT

Primus 公司的服务账号,$PRIMUS_WORKLOAD_IDENTITY_POOL 使用该账号访问受保护的资源。在此步骤中,该角色有权查看存储在 $PRIMUS_INPUT_STORAGE_BUCKET 存储分区中的客户数据。

$PRIMUS_ENC_KEY

KMS 密钥用于加密 Primus 公司员工提供的提示。

$PRIMUS_ENC_KEYRING

用于为 Primus 公司创建加密密钥 $PRIMUS_ENC_KEY 的 KMS 密钥环。

$PRIMUS_ENC_KEYVERSION

加密密钥 $PRIMUS_ENC_KEY 的 KMS 密钥版本。默认值为 1。如果您使用的是过去轮替过且版本已更新的现有密钥,请更新此字段。

$PRIMUS_ARTIFACT_REPOSITORY

将推送工作负载 Docker 映像的工件仓库。

$PRIMUS_PROJECT_REPOSITORY_REGION

包含已发布工作负载 Docker 映像的工件库所在的区域。

$WORKLOAD_VM

工作负载虚拟机的名称。

$WORKLOAD_IMAGE_NAME

工作负载 Docker 映像的名称。

$WORKLOAD_IMAGE_TAG

工作负载容器映像的标记。

$WORKLOAD_SERVICEACCOUNT

有权访问运行工作负载的 Confidential 虚拟机的服务账号。

$CLIENT_VM

用于运行推理服务器的客户端应用的客户端虚拟机的名称。

$CLIENT_SERVICEACCOUNT

$CLIENT_VM 使用的服务账号

  • 您需要拥有项目 $PRIMUS_PROJECT_ID 的 Storage Admin、Artifact Registry Administrator、Cloud KMS Admin、Service Account Admin、IAM Workload Identity Pool Admin 角色。如需了解如何使用 GCP 控制台授予 IAM 角色,请参阅此指南
  • 对于 $PRIMUS_PROJECT_ID,请运行以下脚本,根据资源名称的项目 ID 将其余变量名称设置为值。
source config_env.sh

设置 Primus 公司资源

在此步骤中,您将为 Primus 设置所需的云资源。运行以下脚本,为 Primus 设置资源。脚本执行过程中将创建以下资源:

  • KMS 中的加密密钥 ($PRIMUS_ENC_KEY) 和密钥环 ($PRIMUS_ENC_KEYRING),用于加密 Primus 公司客户数据文件。
  • Workload Identity 池 ($PRIMUS_WORKLOAD_IDENTITY_POOL),用于根据其提供方下配置的属性条件验证声明。
  • 附加到上述工作负载身份池 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 的服务账号 ($PRIMUS_SERVICE_ACCOUNT) 有权使用 KMS 密钥解密数据(使用 roles/cloudkms.cryptoKeyDecrypter 角色),使用 KMS 密钥加密数据(使用 roles/cloudkms.cryptoKeyEncrypter 角色),从云端存储分区读取数据(使用 objectViewer 角色),以及将服务账号连接到工作负载身份池(使用 roles/iam.workloadIdentityUser)。
./setup_primus_resources.sh

3. 创建工作负载

创建工作负载服务账号

现在,您将为工作负载创建一个具有所需角色和权限的服务账号。运行以下脚本,在 Primus 项目中创建工作负载服务账号。运行推理服务器的虚拟机将使用此服务账号。

此工作负载服务账号 ($WORKLOAD_SERVICEACCOUNT) 将具有以下角色:

  • confidentialcomputing.workloadUser 以获取认证令牌
  • logging.logWriter 将日志写入 Cloud Logging。
./create_workload_service_account.sh

创建工作负载

在此步骤中,您将创建一个工作负载 Docker 映像。工作负载将由 Primus 公司编写。此 Codelab 中使用的工作负载是 Python 代码,该代码使用 公开提供的 GCS 存储分区(Vertex Model Garden 中的)中的 codegemma 模型。工作负载将加载 Codegemma 模型并启动推理服务器,该服务器将处理来自 Primus 开发者的代码生成请求。

在收到代码生成请求后,Workload 会获取封装的 DEK 以及加密的提示。然后,工作负载将发出 KMS API 调用以解密 DEK,然后使用此 DEK 解密提示。加密密钥(适用于 DEK)将通过工作负载身份池进行保护,并向符合属性条件的工作负载授予访问权限。下一部分将详细介绍这些属性条件。推理服务器获得解密后的提示后,便会使用已加载的模型生成代码,并返回响应。

运行以下脚本,创建一个执行以下步骤的工作负载:

  • 创建 Primus 拥有的 Artifact Registry($PRIMUS_ARTIFACT_REGISTRY)。
  • 使用所需的资源名称更新工作负载代码。
  • 构建推理服务器工作负载,并创建 Dockerfile 以构建工作负载代码的 Docker 映像。此处提供了此 Codelab 使用的 Dockerfile。
  • 构建 Docker 映像并将其发布到 Primus 拥有的 Artifact Registry ($PRIMUS_ARTIFACT_REGISTRY)。
  • $WORKLOAD_SERVICEACCOUNT 授予对 $PRIMUS_ARTIFACT_REGISTRY 的读取权限。工作负载容器需要从 Artifact Registry 中拉取工作负载 Docker 映像,因此需要此权限。
./create_workload.sh

下面是此 Codelab 中创建并使用的作业的 generate() 方法(您可以在此处找到完整的作业代码)。

def generate():
  try:
    data = request.get_json()
    ciphertext = base64.b64decode(data["ciphertext"])
    wrapped_dek = base64.b64decode(data["wrapped_dek"])
    unwrapped_dek_response = kms_client.decrypt(
        request={"name": key_name, "ciphertext": wrapped_dek}
    )
    unwrapped_dek = unwrapped_dek_response.plaintext
    f = Fernet(unwrapped_dek)
    plaintext = f.decrypt(ciphertext)
    prompt = plaintext.decode("utf-8")
    tokens = tokenizer(prompt, return_tensors="pt")
    outputs = model.generate(**tokens, max_new_tokens=128)
    generated_code = tokenizer.decode(outputs[0])
    generated_code_bytes = generated_code.encode("utf-8")

    response = f.encrypt(generated_code_bytes)
    ciphertext_base64 = base64.b64encode(response).decode("utf-8")
    response = {"generated_code_ciphertext": ciphertext_base64}
    return jsonify(response)

  except (ValueError, TypeError, KeyError) as e:
    return jsonify({"error": str(e)}), 500

4. 授权和运行工作负载

为工作负载授权

Primus 希望根据以下资源的属性,授权工作负载访问用于快速加密的 KMS 密钥:

  • 什么:已通过验证的代码
  • 位置:安全的环境
  • Who:受信任的运营商

Primus 使用工作负载身份联合根据这些要求强制执行访问权限政策。借助工作负载身份联合,您可以指定属性条件。这些条件会限制哪些身份可以使用工作负载身份池 (WIP) 进行身份验证。您可以将 Attestation Verifier Service 作为工作负载身份池提供方添加到 WIP,以显示测量结果并强制执行政策。

工作负载身份池已在之前的云资源设置步骤中创建。现在,Primus 将创建新的 OIDC 工作负载身份池提供方。指定的 --attribute-condition 会授权访问工作负载容器。它需要:

  • 内容:上传到 $PRIMUS_ARTIFACT_REPOSITORY 代码库的最新 $WORKLOAD_IMAGE_NAME
  • 条件:Confidential Space 可信执行环境在完全受支持的 Confidential Space VM 映像上运行。
  • :Primus $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 iam workload-identity-pools providers create-oidc $PRIMUS_WIP_PROVIDER \
  --location="global" \
  --project="$PRIMUS_PROJECT_ID" \
  --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 == 'HARDENED_SHIELDED' && assertion.hwmodel == 'GCP_SHIELDED_VM' && 
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@$PRIMUS_PROJECT_ID.iam.gserviceaccount.com' in assertion.google_service_accounts"

上述命令会检查 hwmodel 是否设置为“GCP_SHIELDED_VM”以及 swname 是否设置为“HARDENED_SHIELDED”,以验证工作负载是否在可信空间环境中运行。此外,它还包含特定于工作负载的断言(例如 image_digestimage_reference),以增强安全性并确保正在运行的工作负载的完整性。

运行工作负载

在此步骤中,我们将在已连接加速器的可信空间虚拟机中运行工作负载。使用元数据标志传递所需的 TEE 参数。工作负载容器的参数使用标志的“tee-cmd”部分传递。如需为工作负载虚拟机配备 Nvidia Tesla T4 GPU,我们将使用 --accelerator=type=nvidia-tesla-t4,count=1 标志。这会将一个 GPU 挂接到虚拟机。我们还需要在元数据标志中添加 tee-install-gpu-driver=true,以触发相应 GPU 驱动程序的安装。

gcloud compute instances create ${WORKLOAD_VM} \
  --accelerator=type=nvidia-tesla-t4,count=1 \
  --machine-type=n1-standard-16 \
  --shielded-secure-boot \
  --image-project=conf-space-images-preview \
  --image=confidential-space-0-gpupreview-796705b \
  --zone=${PRIMUS_PROJECT_ZONE} \
  --maintenance-policy=TERMINATE \
  --boot-disk-size=40 \
  --scopes=cloud-platform \
  --service-account=${WORKLOAD_SERVICEACCOUNT}@${PRIMUS_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}~tee-install-gpu-driver=true~tee-restart-policy=Never"

运行推理查询

在成功启动工作负载推理服务器后,Primus 公司员工现在可以向推理服务器发送代码生成请求。

在此 Codelab 中,我们将使用以下脚本设置与推理服务器交互的客户端应用。运行此脚本以设置客户端虚拟机。

./setup_client.sh

以下步骤演示了如何通过 SSH 登录客户端虚拟机,并在 Python 虚拟环境中执行示例客户端应用。此示例应用结合使用了信封加密和 Fernet 库,但请注意,您可以根据不同的用例调整特定加密库。

gcloud compute ssh ${CLIENT_VM} --zone=${PRIMUS_PROJECT_ZONE}

运行以下命令以在客户端虚拟机中激活 Python 虚拟环境并执行客户端应用。

source venv/bin/activate
python3 inference_client.py

此示例客户端应用的输出将显示加密和明文提示请求及其对应的加密和解密响应。

5. 清理

此处提供了一个脚本,可用于清理我们在此 Codelab 中创建的资源。在此清理过程中,系统将删除以下资源:

  • Primus 服务账号 ($PRIMUS_SERVICEACCOUNT)。
  • Primus 加密密钥 ($PRIMUS_ENC_KEY)。
  • Primus ($PRIMUS_ARTIFACT_REPOSITORY) 的制品库。
  • Primus 工作负载身份池 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 及其提供方。
  • Primus 的工作负载服务账号 ($WORKLOAD_SERVICEACCOUNT)。
  • 工作负载虚拟机 ($WORKLOAD_VM) 和客户端虚拟机 ($CLIENT_VM)。
./cleanup.sh

如果您已完成探索,请考虑删除您的项目。

  • 前往 Cloud Platform 控制台
  • 选择要关停的项目,然后点击顶部的“删除”:这会安排删除该项目