可信空间 Codelab

1. 概览

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

保护有价值的数据、模型和密钥比以往任何时候都更加重要。Trusted Space 提供了一种解决方案,可确保您的工作负载在安全可信的环境中运行,即使是工作负载操作员也无法访问。

可信空间提供以下功能

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

学习内容

  • 了解可信空间的主要功能。
  • 了解如何部署和配置可信空间环境,以保护 AI/ML 工作负载的宝贵资产。

所需条件

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

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

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

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

为解决此问题,Primus Corp 将利用可信空间来隔离运行代码生成模型的推理服务器。具体操作过程如下:

  • 提示加密:在将提示发送到推理服务器之前,每位员工都会使用 Google Cloud 中由 Primus Corp 管理的 KMS 密钥对其进行加密。这样可确保只有可信空间环境(其中提供相应的解密密钥)才能解密该提示并访问明文提示。在实际应用场景中,客户端加密可以由可用的库(例如 tink)处理。在此 Codelab 中,我们将使用此示例客户端应用进行信封加密。
  • 运营商隔离:只有在可信空间环境中运行的推理服务器才能访问用于加密的密钥,并且能够在可信环境中解密提示。加密密钥的访问权限将受到工作负载身份池的保护。由于可信空间具有隔离保证,即使是工作负载操作员也无法访问用于加密的密钥和解密后的内容。
  • 使用加速器的安全推理:推理服务器将在安全强化型虚拟机上启动(作为可信空间设置的一部分),这将确保工作负载实例不会受到启动级或内核级恶意软件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 项目中相应的现有云资源。如果未设置该变量,系统会根据项目名称生成云资源名称,并使用该名称创建新的云资源。以下是资源名称支持的变量:

$PRIMUS_PROJECT_REGION

Primus 公司的区域资源将在哪个区域下创建。

$PRIMUS_SERVICE_LOCATION

Primus 公司的资源将创建在哪个位置。

$PRIMUS_PROJECT_ZONE

Primus 公司的可用区级资源将在哪个可用区下创建。

$PRIMUS_WORKLOAD_IDENTITY_POOL

Primus 公司的 Workload Identity 池,用于保护云资源。

$PRIMUS_WIP_PROVIDER

Primus 公司的 Workload Identity Pool 提供商,其中包含用于由证明验证器服务签名的令牌的授权条件。

$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

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

$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 Company 资源

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

  • KMS 中的加密密钥 ($PRIMUS_ENC_KEY) 和密钥环 ($PRIMUS_ENC_KEYRING),用于加密 Primus 公司的客户数据文件。
  • 工作负载身份池 ($PRIMUS_WORKLOAD_IDENTITY_POOL),用于根据其提供方下配置的属性条件验证声明。
  • 附加到上述工作负载身份池 ($PRIMUS_WORKLOAD_IDENTITY_POOL) 的服务账号 ($PRIMUS_SERVICE_ACCOUNT) 具有以下权限:使用 KMS 密钥解密数据(使用 roles/cloudkms.cryptoKeyDecrypter 角色)、使用 KMS 密钥加密数据(使用 roles/cloudkms.cryptoKeyEncrypter 角色)、从 Cloud Storage 存储分区读取数据(使用 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 模型园)中的 codegemma 模型。工作负载将加载 codegemma 模型并启动推理服务器,该服务器将处理来自 Primus 开发者的代码生成请求。

在代码生成请求中,工作负载将获取封装的 DEK 以及加密的提示。然后,工作负载将调用 KMS API 来解密 DEK,并使用此 DEK 解密提示。加密密钥(针对 DEK)将通过工作负载身份池受到保护,并且只有满足属性条件的工作负载才能获得访问权限。下一部分将更详细地介绍这些属性条件,其中涉及工作负载授权。推理服务器获得解密的提示后,会使用已加载的模型生成代码,然后返回响应。

运行以下脚本以创建工作负载,其中执行以下步骤:

  • 创建由 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

为供您参考,以下是此 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 密钥:

  • 内容:已验证的代码
  • 地点:安全的环境
  • :受信任的运营商

Primus 使用工作负载身份联合来根据这些要求强制执行访问政策。借助工作负载身份联合,您可以指定特性条件。这些条件用于限制哪些身份可以使用工作负载身份池 (WIP) 进行身份验证。您可以将证明验证器服务作为工作负载身份池提供方添加到 WIP,以提供测量结果并强制执行政策。

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

  • 内容:最新 $WORKLOAD_IMAGE_NAME 已上传到 $PRIMUS_ARTIFACT_REPOSITORY 代码库。
  • 其中:Confidential Space 可信执行环境在完全受支持的 Confidential Space 虚拟机映像上运行。
  • :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 控制台
  • 选择要关停的项目,然后点击顶部的“删除”:系统会安排删除该项目