部署前必读
TrustedAIProxy 运行在中转站出口,代理端口只允许内部调用方访问。最终用户不连接代理、不安装内部 MITM CA;他们通过业务响应 headers 和客户可访问的证明端点建立信任。
你需要
- 一个启用结算的 Google Cloud 项目和已登录的
gcloudCLI; - 可以创建 Compute Engine、VPC、防火墙、服务账号和 Secret Manager 资源的权限;
- 能够从 GHCR 拉取本文指定的 TrustedAIProxy 不可变镜像;
- New API / One API 等中转服务与 TAP 的内部网络连通性;
- 客户批准的项目、实例、镜像 digest、上游和证明策略。
Google 官方参考:部署 Confidential Space workload、镜像类型与生命周期、硬件与区域支持。
设置部署变量
示例使用 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)"需要替换 PROJECT_ID、zone 和调用方 CIDR;IMAGE 已固定为可直接拉取的版本。部署后这些值还要作为客户带外策略的一部分交付。
启用所需 API
gcloud services enable \
compute.googleapis.com \
confidentialcomputing.googleapis.com \
iam.googleapis.com \
logging.googleapis.com \
secretmanager.googleapis.com本文直接使用公开 GHCR 镜像,不需要启用 Artifact Registry,也不需要为拉取镜像配置额外的 Registry IAM 权限。
创建 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,而不是整个项目。
使用已发布的不可变镜像
无需自行构建或发布镜像。直接使用 GitHub 仓库已经发布到 GHCR 的固定 digest:
export IMAGE="ghcr.io/tokenevol/trustedaiproxy@sha256:8271352838ac4db3647b4b028f6f6ddd67266d4a0114ada49db3980e5ed331ea"固定 digest 可以避免 tag 更新后静默切换代码。客户验证策略中的 image digest 必须与这里的值完全一致。
配置私有网络与受限入口
以下示例创建自定义 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 规则。
准备固定版本的 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。
创建 debug 测试实例
只使用假数据和演示 CA。Debug 镜像允许 SSH/root 访问,dbgstat 为 enabled,不能被生产客户策略接受。
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}"创建生产实例
生产环境仍需使用稳定、受控配置的 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}"从 metadata 中删除 tee-env-TAP_PG_DSN_SECRET_VERSION=…。客户验证器要使用 --without-postgres,并理解无法跨副本路由新 challenge。
生产 Confidential Space 镜像禁用 SSH。通过最小化的启动日志、内部健康探测和客户 proof 验证进行运维,不要为了调试把生产实例改回 debug 镜像。
让中转站使用 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,只有本地成功证明后才添加新值。
生产验收清单
| 检查项 | 通过标准 |
|---|---|
| 镜像 | 部署使用 @sha256:…,且 digest 与客户批准值完全一致。 |
| 运行环境 | Google token 中 swname=CONFIDENTIAL_SPACE、dbgstat=disabled-since-boot、secboot=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/503 | 404=未知引用;410=owner 不在线;503=跨副本签发超时或临时失败。检查 PostgreSQL 与 owner 心跳。 |
| 客户验签失败 | 中转层是否修改了模型、路径、角色、顺序、消息边界或文本;是否丢失/合并了 headers;nonce 是否已消费。 |