在 Google Confidential Space 上部署

从项目与 IAM 到私有网络、预构建镜像、中转站接入和客户验收策略,按步骤完成部署。

适用于:项目 main 分支当前实现核对日期:2026-08-27预计:45–90 分钟

部署前必读

TrustedAIProxy 运行在中转站出口,代理端口只允许内部调用方访问。最终用户不连接代理、不安装内部 MITM CA;他们通过业务响应 headers 和客户可访问的证明端点建立信任。

你需要

  • 一个启用结算的 Google Cloud 项目和已登录的 gcloud CLI;
  • 可以创建 Compute Engine、VPC、防火墙、服务账号和 Secret Manager 资源的权限;
  • 能够从 GHCR 拉取本文指定的 TrustedAIProxy 不可变镜像;
  • New API / One API 等中转服务与 TAP 的内部网络连通性;
  • 客户批准的项目、实例、镜像 digest、上游和证明策略。

Google 官方参考:部署 Confidential Space workload镜像类型与生命周期硬件与区域支持

1

设置部署变量

示例使用 AMD SEV 与 n2d-standard-2。先确认所选 zone 支持对应 CPU;若改用 TDX,机型、zone 和客户允许的 hwmodel 必须一起更新。

export PROJECT_ID="your-project"
export REGION="us-central1"
export ZONE="us-central1-a"
export INSTANCE_NAME="tap-01"
export MACHINE_TYPE="n2d-standard-2"
export SERVICE_ACCOUNT_NAME="tap-workload"
export SERVICE_ACCOUNT="${SERVICE_ACCOUNT_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
export NETWORK="tap-vpc"
export SUBNET="tap-subnet"
export SUBNET_CIDR="10.40.0.0/24"
export INTERNAL_CALLER_CIDR="10.40.1.0/24"
export IMAGE="ghcr.io/tokenevol/trustedaiproxy@sha256:8271352838ac4db3647b4b028f6f6ddd67266d4a0114ada49db3980e5ed331ea"

gcloud config set project "${PROJECT_ID}"
gcloud compute zones describe "${ZONE}" \
  --format="value(availableCpuPlatforms)"
i
替换环境占位符

需要替换 PROJECT_ID、zone 和调用方 CIDR;IMAGE 已固定为可直接拉取的版本。部署后这些值还要作为客户带外策略的一部分交付。

2

启用所需 API

gcloud services enable \
  compute.googleapis.com \
  confidentialcomputing.googleapis.com \
  iam.googleapis.com \
  logging.googleapis.com \
  secretmanager.googleapis.com

本文直接使用公开 GHCR 镜像,不需要启用 Artifact Registry,也不需要为拉取镜像配置额外的 Registry IAM 权限。

3

创建 workload 身份

VM 附加的服务账号需要请求 Confidential Space attestation token。日志权限只用于测试诊断;生产镜像默认不应重定向业务日志。

gcloud iam service-accounts create "${SERVICE_ACCOUNT_NAME}" \
  --display-name="TrustedAIProxy Confidential Space workload"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/confidentialcomputing.workloadUser"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/logging.logWriter"

gcloud iam service-accounts add-iam-policy-binding "${SERVICE_ACCOUNT}" \
  --member="user:$(gcloud config get-value account)" \
  --role="roles/iam.serviceAccountUser"

生产中遵循最小权限:若不写 Cloud Logging,可移除 logging.logWriter;Secret Manager 的读取权限应绑定到单个 secret,而不是整个项目。

4

使用已发布的不可变镜像

无需自行构建或发布镜像。直接使用 GitHub 仓库已经发布到 GHCR 的固定 digest:

export IMAGE="ghcr.io/tokenevol/trustedaiproxy@sha256:8271352838ac4db3647b4b028f6f6ddd67266d4a0114ada49db3980e5ed331ea"

固定 digest 可以避免 tag 更新后静默切换代码。客户验证策略中的 image digest 必须与这里的值完全一致。

5

配置私有网络与受限入口

以下示例创建自定义 VPC、私有子网和 Cloud NAT。VM 没有公网 IP,但可以拉取公开镜像并访问模型厂商。仅允许中转站所在 CIDR 访问 TAP 的 8080/tcp

gcloud compute networks create "${NETWORK}" --subnet-mode=custom

gcloud compute networks subnets create "${SUBNET}" \
  --network="${NETWORK}" \
  --region="${REGION}" \
  --range="${SUBNET_CIDR}" \
  --enable-private-ip-google-access

gcloud compute routers create tap-router \
  --network="${NETWORK}" \
  --region="${REGION}"

gcloud compute routers nats create tap-nat \
  --router=tap-router \
  --region="${REGION}" \
  --auto-allocate-nat-external-ips \
  --nat-all-subnet-ip-ranges

gcloud compute firewall-rules create tap-from-internal \
  --network="${NETWORK}" \
  --direction=INGRESS \
  --action=ALLOW \
  --rules=tcp:8080 \
  --source-ranges="${INTERNAL_CALLER_CIDR}" \
  --target-tags=tap

如果中转站位于另一个 VPC,需要先配置 VPC Peering、VPN 或其他私网连接,再把 INTERNAL_CALLER_CIDR 缩小到真实调用方范围。不要创建 0.0.0.0/0 → tcp:8080 规则。

6

准备固定版本的 Secret

单副本测试可以不配置 PostgreSQL。多副本生产环境把完整 PostgreSQL DSN 放入 Secret Manager,并只传固定编号的资源名。程序会自动创建或迁移 proof 相关表。

gcloud secrets create tap-pg-dsn --replication-policy=automatic

printf '%s' 'postgres://tap:PASSWORD@postgres.internal:5432/tap?sslmode=verify-full' \
  | gcloud secrets versions add tap-pg-dsn --data-file=-

gcloud secrets add-iam-policy-binding tap-pg-dsn \
  --member="serviceAccount:${SERVICE_ACCOUNT}" \
  --role="roles/secretmanager.secretAccessor"

export PG_SECRET_VERSION="projects/${PROJECT_ID}/secrets/tap-pg-dsn/versions/1"
  • 禁止使用 versions/latest
  • 不要把 DSN、密码、CA 私钥放进 Git、镜像、命令行参数或实例 metadata;
  • 数据库应启用 TLS 校验并限制网络来源;
  • 当前程序只直接从 Secret Manager 读取 PostgreSQL DSN;生产 MITM CA 仍需要先实现独立的受控 bootstrap。
7

创建 debug 测试实例

只使用假数据和演示 CA。Debug 镜像允许 SSH/root 访问,dbgstatenabled,不能被生产客户策略接受。

gcloud compute instances create "${INSTANCE_NAME}-debug" \
  --project="${PROJECT_ID}" \
  --zone="${ZONE}" \
  --machine-type="${MACHINE_TYPE}" \
  --network="${NETWORK}" \
  --subnet="${SUBNET}" \
  --no-address \
  --confidential-compute-type=SEV \
  --maintenance-policy=MIGRATE \
  --shielded-secure-boot \
  --image-project=confidential-space-images \
  --image-family=confidential-space-debug \
  --service-account="${SERVICE_ACCOUNT}" \
  --scopes=cloud-platform \
  --tags=tap \
  --metadata="^~^tee-image-reference=${IMAGE}~tee-restart-policy=OnFailure~tee-container-log-redirect=true"

检查启动日志与内部 IP:

gcloud compute instances get-serial-port-output "${INSTANCE_NAME}-debug" \
  --zone="${ZONE}" --port=1

export TAP_INTERNAL_IP="$(gcloud compute instances describe "${INSTANCE_NAME}-debug" \
  --zone="${ZONE}" --format='get(networkInterfaces[0].networkIP)')"

echo "TAP internal address: http://${TAP_INTERNAL_IP}:8080"

从允许的内部调用主机检查元数据端点:

curl --fail --silent --show-error \
  "http://${TAP_INTERNAL_IP}:8080/.well-known/http-attestation-key"

NONCE="$(openssl rand -hex 16)"
curl --fail --silent --show-error \
  "http://${TAP_INTERNAL_IP}:8080/.well-known/confidential-attestation?nonce=${NONCE}"
8

创建生产实例

生产环境仍需使用稳定、受控配置的 MITM CA 和签名密钥,并确保容器不会记录消息正文、query、凭据、token 或 DSN;若生产密钥方案改变镜像内容,应同步更新固定 digest 和客户策略。

gcloud compute instances create "${INSTANCE_NAME}" \
  --project="${PROJECT_ID}" \
  --zone="${ZONE}" \
  --machine-type="${MACHINE_TYPE}" \
  --network="${NETWORK}" \
  --subnet="${SUBNET}" \
  --no-address \
  --confidential-compute-type=SEV \
  --maintenance-policy=MIGRATE \
  --shielded-secure-boot \
  --image-project=confidential-space-images \
  --image-family=confidential-space \
  --service-account="${SERVICE_ACCOUNT}" \
  --scopes=cloud-platform \
  --tags=tap \
  --metadata="^~^tee-image-reference=${IMAGE}~tee-restart-policy=OnFailure~tee-env-TAP_PG_DSN_SECRET_VERSION=${PG_SECRET_VERSION}"
i
单副本且不使用 PostgreSQL

从 metadata 中删除 tee-env-TAP_PG_DSN_SECRET_VERSION=…。客户验证器要使用 --without-postgres,并理解无法跨副本路由新 challenge。

生产 Confidential Space 镜像禁用 SSH。通过最小化的启动日志、内部健康探测和客户 proof 验证进行运维,不要为了调试把生产实例改回 debug 镜像。

9

让中转站使用 TAP

在 New API / One API 等中转服务进程中配置代理,并将生产 Intermediate CA 证书加入该进程的系统或应用 trust store。CA 只给内部中转服务信任,绝不能交给最终用户安装。

export HTTP_PROXY="http://${TAP_INTERNAL_IP}:8080"
export HTTPS_PROXY="http://${TAP_INTERNAL_IP}:8080"
export NO_PROXY="127.0.0.1,localhost,metadata.google.internal"

# 按中转服务运行时的要求导入生产 Intermediate CA。
# 不要关闭 TLS 校验,也不要使用 InsecureSkipVerify。

确认中转站原样返回所有 X-Attestation-* headers。代理会主动清除上游伪造或陈旧的同名 headers,只有本地成功证明后才添加新值。

10

生产验收清单

检查项通过标准
镜像部署使用 @sha256:…,且 digest 与客户批准值完全一致。
运行环境Google token 中 swname=CONFIDENTIAL_SPACEdbgstat=disabled-since-bootsecboot=true,并满足硬件与 STABLE/LATEST 策略。
密钥材料镜像、Git、metadata 和日志中没有生产 CA 私钥、签名私钥、DSN 或凭据。
网络实例无公网入口;8080 只允许中转站私网 CIDR;出站 TLS 正常校验。
非流式签名受支持的纯文本请求返回 llm-conversation-text-v1,参考客户端可验签。
失败关闭超限、歧义、多模态或不支持内容正常透传但不带本地证明 headers。
流式边界带合法 challenge 的 SSE 只返回 llm-request-upstream-v1;产品 UI 明确标记 body 未证明。
多副本proof_ref 能路由到 owner;owner 下线、未知引用和超时分别返回预期状态。

最后,把 issuer、audience、镜像 digest、project ID/number、zone、实例允许列表、服务账号、硬件类型、允许域名/path/model 与 Secret 固定版本通过可信带外渠道交付客户。不要让客户从待验证响应中学习这些期望值。

故障排查

现象优先检查
容器未启动GHCR package 是否公开、digest 是否存在、Cloud NAT/DNS 是否可用、镜像架构是否为 linux/amd64。
证明端点 503服务账号是否有 roles/confidentialcomputing.workloadUser,launcher socket 是否可访问,audience/nonce 是否合规。
没有证明 headers请求 path、Content-Type、body 大小、文本提取器、上游 TLS、stream/challenge 是否满足 profile。
中转请求 TLS 失败中转进程是否信任正确的内部 CA,是否误用旧 CA;不要禁用证书校验。
proof_ref 查询 404/410/503404=未知引用;410=owner 不在线;503=跨副本签发超时或临时失败。检查 PostgreSQL 与 owner 心跳。
客户验签失败中转层是否修改了模型、路径、角色、顺序、消息边界或文本;是否丢失/合并了 headers;nonce 是否已消费。
下一步:把验证能力交付给最终用户用户不需要代理地址和内部 CA,只需要带外策略、证明包与业务响应。
用户使用指南