Confidential Containers 是一个开源项目,将机密计算引入云原生环境,利用硬件技术保护复杂工作负载。 Confidential Containers 是 CNCF Incubating 项目。
1 - 概览
什么是 Confidential Containers(CoCo)项目?
Confidential Containers(CoCo)通过将 Pod 运行在机密虚拟机(Confidential Virtual Machine)中, 让云原生工作负载在几乎无需修改的情况下利用机密计算硬件提供的安全能力。
Confidential Containers 将机密计算保护能力扩展到复杂工作负载场景。 借助 Confidential Containers,敏感工作负载即便运行在不受信任的主机环境(untrusted hosts)上, 也能够抵御来自已遭入侵或恶意的用户、软件和管理员的攻击。
Confidential Containers 提供一个 工作负载部署、远程证明(Remote Attestation) 以及 密钥/机密信息(Keys/Secrets)分发 的端到端框架。
Confidential Containers 支持哪些硬件?
在裸金属环境下,Confidential Containers 支持以下平台:
| 平台 | 支持远程证明(Remote Attestation) |
|---|---|
| Intel TDX | 是 |
| AMD SEV-SNP | 是 |
| IBM Secure Execution | 是 |
硬件加速器(Accelerators)
| 硬件加速器 | 单设备透传 | 多设备透传 |
|---|---|---|
| Hygon DCU | 是 | 否 |
| NVIDIA Hopper | 是 | Protected PCIe |
| NVIDIA RTX Pro 6000 BSE | 是 | 否 |
| NVIDIA Blackwell | 是 | 是 |
NVIDIA 多设备透传要求将主机上的全部 GPU 分配给同一个 Pod。 NVIDIA Protected PCIe 还要求在 Pod 中列出 NVIDIA NVLink 交换机。
云平台
还可以借助cloud-api-adaptor在云环境中部署Confidential Containers。
目前支持以下平台。
| 平台 | 云 | 备注 |
|---|---|---|
| SNP | Azure | |
| TDX | Azure | |
| TDX | 阿里云 | |
| Secure Execution | IBM | |
| None | AWS | 开发中 |
| SNP | GCP | |
| TDX | GCP | 开发中 |
| None | LibVirt | 用于本地测试 |
远程证明(Attestation)
Confidential Containers 提供了一个名为 Trustee 的远程证明与密钥管理引擎,可为以下平台提供远程证明:
| 平台 |
|---|
| AMD SEV-SNP |
| Intel TDX |
| Intel SGX |
| AMD SEV-SNP with Azure vTPM |
| Intel TDX with Azure vTPM |
| IBM Secure Execution |
| ARM CCA |
| Hygon CSV |
| Hygon DCU |
| NVIDIA GPU |
Trustee 既可以与 Confidential Containers 配合使用,也可以用于对独立运行的机密虚拟机(即非 CoCo 场景)进行远程证明。 更多信息请参见“远程证明(Attestation)”章节。
2 - 快速开始
本节将介绍部署 Confidential Containers 所需的软硬件前提条件、 如何使用 Helm Chart 完成安装、如何验证安装结果, 以及如何运行使用 Confidential Containers 的 Pod。
2.1 - 前提条件
本节将介绍使用 Helm Chart 安装 Confidential Containers 所需的软硬件前提条件。
2.2 - 安装
安装 Confidential Containers 之前,请先完成前提条件章节中的准备工作。
使用 Helm 安装 CoCo
通过 Confidential Containers Charts 仓库提供的 Helm Chart 安装 CoCo 运行时。
安装最新版本:
helm install coco oci://ghcr.io/confidential-containers/charts/confidential-containers \
--namespace coco-system \
--create-namespace
将 <VERSION> 替换为所需的发布版本:
helm install coco oci://ghcr.io/confidential-containers/charts/confidential-containers \
--version <VERSION> \
--namespace coco-system \
--create-namespace
例如,安装 v0.18.0 版本:
helm install coco oci://ghcr.io/confidential-containers/charts/confidential-containers \
--version 0.18.0 \
--namespace coco-system \
--create-namespace
等待所有 Pod 的 STATUS 变为 Running。
kubectl get pods -n coco-system --watch
如果需要了解特定场景的安装选项(例如 s390x、peer-pods)或高级配置,请参见
Charts 仓库文档。
验证安装
检查预期的 RuntimeClass 是否已创建。
kubectl get runtimeclass
可用的 RuntimeClass 取决于具体架构:
| runtimeclass | 说明 |
|---|---|
kata-qemu-coco-dev |
开发/测试运行时 |
kata-qemu-coco-dev-runtime-rs |
开发/测试运行时(基于 Rust) |
kata-qemu-snp |
AMD SEV-SNP |
kata-qemu-tdx |
Intel TDX |
kata-qemu-nvidia-gpu-snp |
NVIDIA GPU 加 AMD SNP 组合 |
kata-qemu-nvidia-gpu-tdx |
NVIDIA GPU 加 Intel TDX 组合 |
| runtimeclass | 说明 |
|---|---|
kata-qemu-coco-dev |
开发/测试运行时 |
kata-qemu-coco-dev-runtime-rs |
开发/测试运行时(基于 Rust) |
kata-qemu-se |
IBM Secure Execution |
kata-qemu-se-runtime-rs |
IBM Secure Execution(基于 Rust) |
| runtimeclass | 说明 |
|---|---|
kata-remote |
Peer-pods |
卸载
如需卸载 Confidential Containers 并删除 coco-system 命名空间,请执行:
helm uninstall coco --namespace coco-system
kubectl delete namespace coco-system
2.3 - 示例工作负载
创建示例 Confidential Containers 工作负载
使用 Helm Chart 安装 Confidential Containers 后,只需为 Pod 添加一个 RuntimeClass,
即可运行 CoCo 工作负载。
我们使用 kata-qemu-coco-dev RuntimeClass,它会在不依赖机密计算硬件支持的情况下运行 CoCo。
首先,使用一个未加密的容器镜像进行演示。
本示例使用如下 YAML 所示的 nginx 镜像:
apiVersion: v1
kind: Pod
metadata:
labels:
run: nginx
name: nginx
annotations:
io.containerd.cri.runtime-handler: kata-qemu-coco-dev
spec:
containers:
- name: nginx
image: nginx:1.29.4
dnsPolicy: ClusterFirst
runtimeClassName: kata-qemu-coco-dev
对于大多数基础的工作负载来说,通常只需在 Pod YAML 中设置 runtimeClassName
和 runtime-handler 注解即可。
按照上面的内容创建一个 Pod YAML 文件(本示例命名为 nginx.yaml)。
创建工作负载:
kubectl apply -f nginx.yaml
输出示例:
pod/nginx created
确认 Pod 已成功创建并处于运行状态:
kubectl get pods
输出示例:
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 3m50s
2.4 - 加固工作负载
现在你已经部署了一个简单的 Confidential Containers 工作负载, 接下来可以进一步了解如何将其加固到适用于生产环境的水平。 本页重点介绍你需要做出的几个关键决策:
- 为你的硬件选择合适的 RuntimeClass
- 理解并配置用于保护工作负载的各类策略
- 利用额外的安全特性进一步提升防护能力
选择合适的 RuntimeClass
在前面的示例中,我们使用的是 kata-qemu-coco-dev,
它主要用于测试场景,不依赖机密计算硬件支持。
如果是在生产环境中部署,则必须选择与实际 TEE 硬件相匹配的 RuntimeClass。
RuntimeClass 选择指南
用于开发与测试:
kata-qemu-coco-dev- 不依赖 TEE 硬件的测试运行时(⚠️ 不提供安全保证)
用于 x86_64 裸金属生产环境:
kata-qemu-tdx- Intel TDX(Trust Domain Extensions)kata-qemu-snp- AMD SEV-SNP(Secure Encrypted Virtualization)kata-qemu-sev- AMD SEV(较早一代)kata-qemu-nvidia-gpu-tdx- NVIDIA GPU 加 Intel TDX 组合kata-qemu-nvidia-gpu-snp- NVIDIA GPU 加 AMD SNP 组合
用于 s390x 生产环境:
kata-qemu-se- IBM Secure Execution
用于云上部署(Peer Pods):
kata-remote- 面向 AWS、Azure、GCP 等平台的 Cloud API Adaptor
示例:迁移到生产环境配置
下面展示如何将 Pod 更新为使用真实的 TEE 硬件。
以 Intel TDX 为例:
apiVersion: v1
kind: Pod
metadata:
name: nginx-production
spec:
runtimeClassName: kata-qemu-tdx
containers:
- image: bitnami/nginx:1.22.0
name: nginx
设置 runtimeClassName 字段通常已经足够。
有些示例为了兼容较旧配置,还会保留 io.containerd.cri.runtime-handler 注解(annotation),
但在使用 RuntimeClass 时,这个注解通常是冗余的。
使用Intel TDX 加 NVIDIA Hopper GPU:
apiVersion: v1
kind: Pod
metadata:
name: cuda-vectoradd-kata
namespace: default
spec:
runtimeClassName: kata-qemu-nvidia-gpu-tdx
restartPolicy: Never
containers:
- name: cuda-vectoradd
image: "nvcr.io/nvidia/k8s/cuda-sample:vectoradd-cuda12.5.0-ubuntu22.04"
resources:
limits:
nvidia.com/pgpu: "1"
memory: 16Gi
关于 Hopper、Blackwell 多 GPU 示例,以及 Hopper PPCIE 标签配置,请参见 NVIDIA GPU 示例。
所选 RuntimeClass 必须与你的硬件能力匹配。
如果 RuntimeClass 与实际硬件不一致(例如在 AMD 硬件上使用 kata-qemu-tdx),
Pod 创建将会失败。
理解 CoCo 策略体系
Confidential Containers 使用三类策略(policy),分别在不同层面保护工作负载。 若要加固生产环境部署,理解这三类策略至关重要。
三类策略
| 策略类型 | 执行位置 | 控制内容 | 配置方式 |
|---|---|---|---|
| Kata Agent 策略 (Kata Agent Policy) | TEE 内部,由 Kata Agent 执行 | 控制 Agent 可执行的操作(如创建容器、对 Pod 执行 exec 等) |
通过包含 init-data 的 Pod 注解配置 |
| KBS 资源策略 (KBS Resource Policy) | 由 Trustee KBS 执行 | 控制哪些机密信息可以释放给哪些工作负载 | 通过 KBS Client 或 Trustee Operator 配置 |
| 远程证明策略 | 由 Trustee AS 执行 | 控制如何评估硬件证据(例如接受哪些 TCB 状态) | 通过 KBS Client 或 Trustee Operator 配置 |
图中展示的 Rego 文件名仅为示例。
这些名称本身没有特殊含义。
实际配置时,策略始终是通过命令行参数(例如 kbs-client ... set-resource-policy --policy-file <path>)
或配置项按路径传入,服务实际使用的是文件内容,而不是文件名。
1. Kata Agent 策略(TEE 内)
Kata Agent 策略决定了 Kata Agent 在 TEE 内允许执行哪些操作。 这是防御恶意或已被入侵的 Kubernetes 控制平面的第一道防线。
典型用途包括:
- 禁止对生产 Pod 执行
kubectl exec - 限制允许启动的容器镜像
- 控制允许执行的命令
下面是一个较为严格的 Kata Agent 策略示例:
package agent_policy
import rego.v1
default CreateContainerRequest := false
default ExecProcessRequest := false
# Only allow specific image digests
CreateContainerRequest if {
input.storages[0].source == "docker.io/library/nginx@sha256:abc123..."
}
Kata Agent 策略会嵌入到 Init-Data 配置文件中。 该文件还可提供其他配置,例如 Trustee 的地址信息。
2. KBS 资源策略(KBS 侧)
KBS 资源策略用于控制在何种条件下释放哪些机密信息。 它会检查工作负载提交的证明令牌,并据此做出决策。
典型用途包括:
- 验证工作负载是否使用了特定的 Kata Agent 策略(通过 Init-Data 哈希)
- 仅向通过 TDX 远程证明的 TDVM 实例释放数据库凭据
- 要求特定的信任级别(例如
affirming或contraindicated) - 为不同平台(TDX 或 SNP)下发不同的机密信息
示例:校验 Init-Data 哈希
当你在 Pod 中提供 Init-Data(其中包含 Kata Agent 策略)时, 证明服务(Attestation Service)会对其进行校验,并将相应哈希写入令牌。 你的 KBS 资源策略可以进一步验证这个特定的 Init-Data 哈希, 从而确保实际使用的是期望的 Kata Agent 策略与配置。
package policy
import rego.v1
default allow = false
# Only release secrets to workloads with the expected Init-Data hash
allow if {
input["submods"]["cpu0"]["ear.status"] == "affirming"
# Verify the specific Init-Data hash (includes kata agent policy + config)
input["submods"]["cpu0"]["ear.veraison.annotated-evidence"]["init_data"] == "expected-hash-here"
}
请使用你在 initdata.toml 中指定的哈希算法计算期望值。
例如,对 TDX 场景,通常会使用 sha384,此时可在命令行中执行:
sha384sum initdata.toml
延伸阅读:KBS 资源策略
3. 远程证明策略(Attestation Service 侧)
远程证明策略定义了如何评估硬件证据,包括: 接受哪些测量值、与哪些参考值进行比对,以及如何计算信任向量。
典型用途包括:
- 定义可接受的固件版本
- 为不同工作负载指定所需的安全级别
- 将硬件测量值映射为可信声明(trust claims)
延伸阅读:Attestation Service Policies
CoCo 已为 TDX、SNP 实例以及 NVIDIA 机密计算 GPU 提供了合理的默认证明策略。 对大多数用户而言,只需补充参考值即可,策略本身通常已具备合适配置。
额外的安全特性
完成基础配置后,可以进一步了解以下功能以增强整体安全性: 功能概览
生产环境快速检查清单
在部署到生产环境之前,请确认已完成以下事项:
- 已根据实际硬件选择正确的 RuntimeClass
- 已生成并嵌入适合当前工作负载的 Kata Agent 策略
- 已在 KBS 中配置 KBS 资源策略
- 已向证明服务预置参考值
后续步骤
- 部署 Trustee: 参见Trustee 安装,以启用远程证明
- 深入策略体系: 参见各类策略说明
- 云上部署: 参见AWS、Azure、GCP 云平台示例
3 - 术语对照表
本文根据当前 CoCo 英文文档整理出常见的专业名称、关键术语与专有名词,便于中文文档翻译时保持用词一致。
说明:
- 组件名、项目名、协议名、工具名以及
RuntimeClass名称通常保留英文。 - 中文列给出建议译法;对于不宜直译的项目名,采用“保留英文 + 中文解释”的方式。
- 该表会随着英文文档演进持续补充和调整。
核心项目与组件
| English | 中文建议 | 说明 |
|---|---|---|
| Confidential Containers | 机密容器 | 项目正式名称 |
| CoCo | CoCo / 机密容器 | Confidential Containers 的简称 |
| Kata Containers | Kata Containers | CoCo 依赖的容器运行时项目 |
| Kata Agent | Kata Agent / Kata 代理 | 运行在客户机内的代理组件 |
| Kata Shim | Kata Shim | 宿主机侧连接容器运行时与客户机的组件 |
| PodVM | PodVM / Pod 虚拟机 | 承载机密工作负载的虚拟机 |
| Peer Pods | Peer Pods | 通过云 API 启动 PodVM 的部署模式 |
| guest-components | 客户机内组件 | 客户机内组件的集合 |
| image-rs | 镜像处理组件 | 客户机内镜像拉取与解包组件 |
| ocicrypt-rs | OCI 镜像解密组件 | 客户机内镜像解密组件 |
| confidential-data-hub | 机密数据中心 | 客户机内数据与机密访问组件 |
| CDH | 机密数据中心枢纽 | confidential-data-hub 的简称 |
| attestation-agent | 远程证明代理 | 客户机内远程证明客户端 |
| AA | 证明代理 | attestation-agent 的简称 |
| api-server-rest | API 服务代理 | Pod / 客户机内 API 访问代理 |
| cloud-api-adaptor | 云 API 适配器 | 通过云平台接口创建 PodVM 的组件 |
| CAA | 云 API 适配器 | cloud-api-adaptor 的简称 |
| Trustee | Trustee | CoCo 的证明与机密管理服务栈 |
| Key Broker Service | 密钥代理服务 | Trustee 中用于资源发放的服务 |
| KBS | 密钥代理服务 | Key Broker Service 的简称 |
| Attestation Service | 远程证明服务 | Trustee 中负责验证证据的服务 |
| AS | 证明服务 | Attestation Service 的简称 |
| Reference Value Provider Service | 参考值提供服务 | 提供参考测量值的服务 |
| RVPS | 参考值提供服务 | Reference Value Provider Service 的简称 |
| CoCo operator | CoCo Operator | 部署和管理 CoCo 的 Kubernetes Operator |
| nydus-snapshotter | Nydus 快照器 | 配合镜像拉取与快照管理的组件 |
安全、TEE 与证明术语
| English | 中文建议 | 说明 |
|---|---|---|
| confidential computing | 机密计算 | 总体技术范畴 |
| Trusted Execution Environment | 可信执行环境 | 机密计算的核心执行环境 |
| TEE | 可信执行环境 | Trusted Execution Environment 的简称 |
| enclave | 安全飞地 / 隔离执行区 | 受保护的隔离执行环境 |
| Trusted Computing Base | 可信计算基 | 信任边界内的软硬件集合 |
| TCB | 可信计算基 | Trusted Computing Base 的简称 |
| Remote Attestation | 远程证明 | 验证平台或客户机可信性的过程 |
| attestation token | 远程证明令牌 | 远程证明结果的令牌化表示 |
| hardware evidence | 硬件证据 | 由 TEE 平台提供的证据 |
| reference values | 参考值 | 与实际度量结果比对的基准值 |
| verifier | 验证器 / 验证者 | 用于校验证据的组件 / 角色 |
| root of trust | 信任根 | 构建信任链的基础 |
| attestation policy | 远程证明策略 | 判定环境是否可信的策略 |
| resource policy | 资源策略 | 控制 KBS 是否发放资源的策略 |
| TCB claims | TCB 声明 | 从证据中提取的可信属性 |
| trust vector | 信任向量 | 结构化的证明结果表达 |
| EAR | 远程证明结果令牌 | Trustee 文档中使用的证明结果格式术语 |
| AR4SI | 远程证明结果互操作模型 | Trustee 使用的信任结果表达模型 |
| Init-Data | 初始化数据 | 注入客户机内的配置、策略和输入数据 |
| sealed secrets | 密封机密 | 保护机密数据的功能 |
| encrypted images | 加密镜像 | 经过加密保护的容器镜像 |
| signed images | 签名镜像 | 带有签名与完整性校验的镜像 |
| memory encryption | 内存加密 | 保护运行中数据的硬件能力 |
| GetResource | 获取资源请求 | 通过证明后向 KBS 获取机密资源的动作 |
Kubernetes 与容器术语
| English | 中文建议 | 说明 |
|---|---|---|
| CRI | 容器运行时接口 | Container Runtime Interface |
| CRD | 自定义资源定义 | Custom Resource Definition |
| OLM | Operator 生命周期管理器 | Operator Lifecycle Manager |
| Helm | Helm | Kubernetes 包管理工具 |
| Helm Chart | Helm Chart | Helm 安装包 |
| kubectl | kubectl | Kubernetes 命令行工具 |
| KServe | KServe | Kubernetes 上的模型推理平台 |
| ConfigMap | 配置映射 | Kubernetes 配置对象 |
平台、硬件与云环境
| English | 中文建议 | 说明 |
|---|---|---|
| Intel TDX | Intel TDX | Intel Trusted Domain Extension TEE 技术 |
| Intel SGX | Intel SGX | Intel 安全飞地技术 |
| AMD SEV | AMD SEV | AMD 安全加密虚拟化技术 |
| AMD SEV-ES | AMD SEV-ES | 带寄存器状态保护的 SEV 扩展 |
| AMD SEV-SNP | AMD SEV-SNP | 带更强完整性保护的 AMD TEE 技术 |
| IBM Secure Execution | IBM-SE | IBM Z 平台的机密计算能力 |
| IBM Z | IBM Z | IBM 大型机平台 |
| LinuxONE | LinuxONE | IBM 企业级 Linux 平台 |
| s390x | s390x | IBM Z 使用的体系结构 |
| ARM CCA | ARM CCA | ARM 机密计算架构 |
| Hygon CSV | 海光 CSV | 海光平台机密计算技术 |
| Hygon DCU | 海光 DCU | 海光硬件加速器平台 |
| NVIDIA GPU | NVIDIA GPU | 英伟达GPU 机密计算相关平台 |
| Hopper | Hopper | NVIDIA GPU 架构代号 |
| Blackwell | Blackwell | NVIDIA GPU 架构代号 |
| Protected PCIe | 受保护的 PCIe | 英伟达 Hopper 一代多GPU互联总线保护技术 |
| vTPM | 虚拟 TPM | 虚拟化可信平台模块 |
| AWS | 亚马逊云 | 云平台 |
| Azure | 微软云 | 云平台 |
| GCP | Google Cloud | 云平台 |
| Alibaba Cloud | 阿里云 | 云平台 |
| OpenShift | OpenShift | 企业级 Kubernetes 发行版 |
| LibVirt | LibVirt | 本地虚拟化测试场景中使用的平台 |
标准、协议与工具
| English | 中文建议 | 说明 |
|---|---|---|
| OCI | OCI 开放容器规范 | 容器镜像与运行时相关规范 |
| OCI Registry | OCI 镜像仓库 | 存储 OCI 镜像与工件的仓库 |
| SBOM | 软件物料清单 | Software Bill of Materials |
| SLSA | 供应链安全等级框架 | Supply-chain Levels for Software Artifacts |
| in-toto | in-toto 供应链证明框架 | 供应链证明格式与框架 |
| OPA | 开放策略代理 | Open Policy Agent |
| Rego | Rego 策略语言 | OPA 使用的策略语言 |
| ORAS | OCI 工件工具 | 用于操作 OCI Artifact 的 CLI |
| JWK | JSON Web Key | JSON Web 密钥格式 |
| JWT | JSON Web Token | 常见令牌格式 |
| PluginResponse | 插件响应 | KBS 外部插件文档中的接口名 |
| KBC | 密钥代理客户端 | Key Broker Client 的简称 |
扩展项目名与场景术语
| English | 中文建议 | 说明 |
|---|---|---|
| BYOM | 自带机器模型 | Bring Your Own Machine |
| External Secrets Operator | 外部机密 Operator | 常简称 ESO |
| ESO | 外部机密 Operator | External Secrets Operator 的简称 |
| NIM | NVIDIA 推理微服务 | NVIDIA Inference Microservices |
| Switchboard | Switchboard | 相关博客中出现的项目名 |
| IRSA | 服务账户 IAM 角色机制 | AWS 场景常见术语 |
| EKS | Amazon Elastic Kubernetes Service | AWS Kubernetes 托管服务 |
| AKS | Azure Kubernetes Service | Azure Kubernetes 托管服务 |
| GKE | Google Kubernetes Engine | GCP Kubernetes 托管服务 |
| NGC API | NGC API | NVIDIA NGC 访问接口 |
RuntimeClass 与字面标识符
以下名称通常不翻译,中文仅作解释。
| English | 中文建议 | 说明 |
|---|---|---|
kata-qemu-coco-dev |
CoCo 开发运行时 | 非 TEE 开发与测试运行时 |
kata-qemu-coco-dev-runtime-rs |
CoCo Rust 开发运行时 | 基于 Rust 的开发运行时 |
kata-qemu-tdx |
TDX 运行时 | Intel TDX RuntimeClass |
kata-qemu-snp |
SNP 运行时 | AMD SEV-SNP RuntimeClass |
kata-qemu-sev |
SEV 运行时 | AMD SEV RuntimeClass |
kata-qemu-se |
Secure Execution 运行时 | IBM Secure Execution RuntimeClass |
kata-qemu-nvidia-gpu-tdx |
TDX + NVIDIA GPU 运行时 | GPU 机密计算场景 |
kata-qemu-nvidia-gpu-snp |
SNP + NVIDIA GPU 运行时 | GPU 机密计算场景 |
kata-remote |
远程虚拟机运行时 | Peer Pods 或 CAA 场景 |
kata-clh |
Cloud Hypervisor 运行时 | 发行说明中出现的运行时名称 |
kata-clh-tdx |
Cloud Hypervisor TDX 运行时 | 发行说明中出现的运行时名称 |
kata-cc |
CoCo 运行时 | 部分策略示例中出现 |
io.containerd.cri.runtime-handler |
containerd 运行时处理器注解 | 用于选择运行时的注解 |
4 - 示例
4.1 - AWS
说明: 本文为英文文档的中文译版,英文原版请参见 AWS 示例(英文版)。
本文将介绍如何在 AWS Elastic Kubernetes Service (EKS) 上配置 CAA(即 Peer Pods),具体包括:
- 一个基于 Elastic Kubernetes Service (EKS) 的单工作节点 Kubernetes 集群
- 运行在该 Kubernetes 集群上的 CAA
- 一个由 CAA PodVM 支撑的 Nginx Pod
前提条件
安装所需工具:
AWS 准备工作
- 为 AWS CLI 访问设置
AWS_ACCESS_KEY_ID、AWS_SECRET_ACCESS_KEY(或AWS_PROFILE)以及AWS_REGION
说明: 除了静态凭证外,也可以在 EKS 上使用 IRSA(IAM Roles for Service Accounts)。使用 IRSA 时,CAA Pod 通过 OIDC 完成认证,无需在 Kubernetes Secret 中保存静态 AWS 密钥。集群初始化步骤中仍然需要
AWS_REGION和临时凭证。
- 设置区域:
export AWS_REGION="us-east-2"
说明: 选择
us-east-2区域,是因为这里既提供 AMD SEV-SNP 实例,也提供可直接使用的预构建 PodVM 镜像。
export AWS_REGION="us-east-2"
说明: 选择
us-east-2区域,是因为这里提供可直接使用的预构建 PodVM 镜像。
使用 EKS 部署 Kubernetes
按需修改以下环境变量:
export CLUSTER_NAME="caa-$(date '+%Y%m%b%d%H%M%S')"
export CLUSTER_NODE_TYPE="m5.xlarge"
export CLUSTER_NODE_FAMILY_TYPE="Ubuntu2204"
export SSH_KEY=~/.ssh/id_rsa.pub
以下示例使用默认的 AWS VPC-CNI 创建 EKS 集群:
eksctl create cluster --name "$CLUSTER_NAME" \
--node-type "$CLUSTER_NODE_TYPE" \
--node-ami-family "$CLUSTER_NODE_FAMILY_TYPE" \
--nodes 1 \
--nodes-min 0 \
--nodes-max 2 \
--node-private-networking \
--kubeconfig "$CLUSTER_NAME"-kubeconfig
等待集群创建完成。
为集群节点添加 node.kubernetes.io/worker= 标签:
for NODE_NAME in $(kubectl get nodes -o jsonpath='{.items[*].metadata.name}'); do
kubectl label node $NODE_NAME node.kubernetes.io/worker=
done
放通所需网络端口
EKS_VPC_ID=$(aws eks describe-cluster --name "$CLUSTER_NAME" \
--query "cluster.resourcesVpcConfig.vpcId" \
--output text)
echo $EKS_VPC_ID
EKS_CLUSTER_SG=$(aws eks describe-cluster --name "$CLUSTER_NAME" \
--query "cluster.resourcesVpcConfig.clusterSecurityGroupId" \
--output text)
echo $EKS_CLUSTER_SG
EKS_VPC_CIDR=$(aws ec2 describe-vpcs --vpc-ids "$EKS_VPC_ID" \
--query 'Vpcs[0].CidrBlock' --output text)
echo $EKS_VPC_CIDR
# agent-protocol-forwarder 端口
aws ec2 authorize-security-group-ingress --group-id "$EKS_CLUSTER_SG" --protocol tcp --port 15150 --cidr "$EKS_VPC_CIDR"
# vxlan 端口
aws ec2 authorize-security-group-ingress --group-id "$EKS_CLUSTER_SG" --protocol tcp --port 9000 --cidr "$EKS_VPC_CIDR"
aws ec2 authorize-security-group-ingress --group-id "$EKS_CLUSTER_SG" --protocol udp --port 9000 --cidr "$EKS_VPC_CIDR"
说明:
- 端口
15150是 CAA 连接 PodVM 内agent-protocol-forwarder时使用的默认端口。- 端口
9000是 CAA 使用的 VXLAN 端口。请确保它与 Kubernetes CNI 使用的 VXLAN 端口不冲突。
配置认证
选择 CAA 与 AWS 交互时的认证方式。静态凭证方式通过 Kubernetes Secret 保存访问密钥;IRSA 则通过 OIDC 联邦让 Pod 直接承担 IAM 角色,无需静态密钥。
确保环境中已设置 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY(或 AWS_PROFILE)。这些值会存入 Kubernetes Secret,供 CAA Pod 使用。
此处无需额外操作,Secret 将在后续的 在 Kubernetes 集群中部署 Helm Chart 步骤中创建。
IRSA 不再需要把长期 AWS 访问密钥保存在 Kubernetes Secret 中,是 EKS 上推荐使用的认证方式。
启用 OIDC Provider
检查 IAM OIDC provider 是否已经注册:
OIDC_ID=$(aws eks describe-cluster \
--name ${CLUSTER_NAME} \
--region ${AWS_REGION} \
--query "cluster.identity.oidc.issuer" \
--output text | awk -F'/' '{print $NF}')
aws iam list-open-id-connect-providers | grep ${OIDC_ID}
如果命令没有返回结果,则创建 OIDC provider:
eksctl utils associate-iam-oidc-provider \
--cluster ${CLUSTER_NAME} \
--region ${AWS_REGION} \
--approve
导出账户 ID 和 OIDC provider,供后续步骤使用:
export ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
export OIDC_PROVIDER=$(aws eks describe-cluster \
--name ${CLUSTER_NAME} \
--region ${AWS_REGION} \
--query "cluster.identity.oidc.issuer" \
--output text | sed 's|https://||')
为 cloud-api-adaptor 创建 IAM Role
export NAMESPACE="confidential-containers-system"
export CAA_SERVICE_ACCOUNT="cloud-api-adaptor"
export CAA_ROLE_NAME="CAA-IRSA-Role"
创建信任策略:
cat > /tmp/caa-trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${NAMESPACE}:${CAA_SERVICE_ACCOUNT}",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
创建 IAM 角色,并附加 AmazonEC2FullAccess 托管策略:
aws iam create-role \
--role-name ${CAA_ROLE_NAME} \
--assume-role-policy-document file:///tmp/caa-trust-policy.json \
--description "IRSA role for Cloud API Adaptor on EKS"
aws iam attach-role-policy \
--role-name ${CAA_ROLE_NAME} \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
说明:
AmazonEC2FullAccess会授予较宽泛的 EC2 权限。用于生产环境时,强烈建议改用更小权限范围的自定义策略,仅授予 CAA 所需的 EC2 操作权限。更多配置方式请参考 AWS IRSA 文档。
导出 role ARN,供后续使用:
export CAA_ROLE_ARN=$(aws iam get-role \
--role-name ${CAA_ROLE_NAME} \
--query 'Role.Arn' \
--output text)
echo "CAA Role ARN: ${CAA_ROLE_ARN}"
为 Peerpod-ctrl 创建 IAM Role(可选)
只有在部署 Peerpod-ctrl 时才需要这一步。
export CTRL_SERVICE_ACCOUNT="peerpodctrl-controller-manager"
export CTRL_ROLE_NAME="PeerpodCtrl-IRSA-Role"
创建信任策略:
cat > /tmp/peerpod-ctrl-trust-policy.json <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Federated": "arn:aws:iam::${ACCOUNT_ID}:oidc-provider/${OIDC_PROVIDER}"
},
"Action": "sts:AssumeRoleWithWebIdentity",
"Condition": {
"StringEquals": {
"${OIDC_PROVIDER}:sub": "system:serviceaccount:${NAMESPACE}:${CTRL_SERVICE_ACCOUNT}",
"${OIDC_PROVIDER}:aud": "sts.amazonaws.com"
}
}
}
]
}
EOF
创建角色并附加权限:
aws iam create-role \
--role-name ${CTRL_ROLE_NAME} \
--assume-role-policy-document file:///tmp/peerpod-ctrl-trust-policy.json \
--description "IRSA role for PeerPod Controller on EKS"
aws iam attach-role-policy \
--role-name ${CTRL_ROLE_NAME} \
--policy-arn arn:aws:iam::aws:policy/AmazonEC2FullAccess
说明:
AmazonEC2FullAccess会授予较宽泛的 EC2 权限。用于生产环境时,强烈建议改用更小权限范围的自定义策略,仅授予 CAA 所需的 EC2 操作权限。更多配置方式请参考 AWS IRSA 文档。
导出 role ARN:
export CTRL_ROLE_ARN=$(aws iam get-role \
--role-name ${CTRL_ROLE_NAME} \
--query 'Role.Arn' \
--output text)
echo "Controller Role ARN: ${CTRL_ROLE_ARN}"
部署 CAA Helm Chart
下载 CAA Helm 部署资源
export CAA_VERSION="0.22.0"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/tags/v${CAA_VERSION}.tar.gz"
tar -xvzf "v${CAA_VERSION}.tar.gz"
cd "cloud-api-adaptor-${CAA_VERSION}/src/cloud-api-adaptor/install/charts/peerpods"
export CAA_BRANCH="main"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/heads/${CAA_BRANCH}.tar.gz"
tar -xvzf "${CAA_BRANCH}.tar.gz"
cd "cloud-api-adaptor-${CAA_BRANCH}/src/cloud-api-adaptor/install/charts/peerpods"
假如你已在本地准备好代码,请在终端中切换到 Cloud API Adaptor 的代码目录。
导出 PodVM 镜像版本
导出 peer pods 所用的 PodVM 镜像 ID。该变量告诉部署工具在 AWS 中创建 peer pod 虚拟机时应使用哪个 PodVM 镜像版本。
镜像来自 CoCo 社区镜像库(或由你手动构建),并且必须与当前 CAA 发布版本匹配。
在 us-east-2 区域中,我们提供了一个可用于 PoC 的预构建调试版 PodVM 镜像。可通过以下命令查询对应发布版本的 AMI ID:
export PODVM_AMI_ID=$(aws ec2 describe-images \
--filters Name=name,Values="podvm-ubuntu-amd64-${CAA_VERSION//./-}" \
--query 'Images[*].[ImageId]' --output text)
echo $PODVM_AMI_ID
最新构建没有预构建的 PodVM AMI。你需要自行构建 PodVM 镜像,然后按照这里的说明创建 AMI。
为 AWS 构建 PodVM 镜像前,请记得设置 TEE_PLATFORM=amd。
镜像构建完成后,将镜像 ID 导出到环境变量 PODVM_AMI_ID。
你可以按照这里的说明构建自定义 PodVM 镜像。
为 AWS 构建 PodVM 镜像前,请记得设置 TEE_PLATFORM=amd。
镜像构建完成后,将镜像 ID 导出到环境变量 PODVM_AMI_ID。
导出 CAA 容器镜像路径
定义要部署的 Cloud API Adaptor(CAA)容器镜像。 这些变量指定了部署工具所要拉取和运行的 CAA 镜像及其架构专属 tag。 tag 与 CAA 发布版本对应,以确保与所选 PodVM 镜像和配置兼容。
导出以下环境变量以使用 CAA 最新发布镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
export CAA_TAG="v${CAA_VERSION}-amd64"
导出以下环境变量,以使用每次合并到 main 后由 CAA CI 构建的镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
你可以在这里找到适合需求的预构建镜像 tag。
export CAA_TAG=""
注意: 你也可以使用
latesttag,但不推荐这样做,因为它缺少版本控制,可能引入不可预期的更新,影响部署稳定性和可复现性。
如果你修改了 CAA 代码并希望部署这些改动,请按这些说明构建容器镜像。镜像构建完成后,导出环境变量 CAA_IMAGE 和 CAA_TAG。
选择 peer-pods 机型
export PODVM_INSTANCE_TYPE="m6a.large"
export DISABLECVM="false"
更多 AMD SEV-SNP 机型可参考这份 AWS 文档。
export PODVM_INSTANCE_TYPE="t3.large"
export DISABLECVM="true"
填充 providers/aws.yaml 文件
全部可用配置项可在以下两个位置找到:
运行以下命令更新 providers/aws.yaml 文件:
cat <<EOF > providers/aws.yaml
provider: aws
image:
name: "${CAA_IMAGE}"
tag: "${CAA_TAG}"
providerConfigs:
aws:
DISABLECVM: ${DISABLECVM}
PODVM_AMI_ID: "${PODVM_AMI_ID}"
PODVM_INSTANCE_TYPE: "${PODVM_INSTANCE_TYPE}"
VXLAN_PORT: 9000
EOF
安装 cert-manager
CAA 依赖 cert-manager。除非环境中已经安装,否则请使用以下方式部署:
helm repo add jetstack https://charts.jetstack.io
helm install cert-manager jetstack/cert-manager \
--namespace cert-manager \
--create-namespace \
--set crds.enabled=true \
--wait \
--timeout 5m
在 Kubernetes 集群中部署 Helm Chart
-
创建由 Helm 管理的命名空间:
kubectl apply -f - << EOF apiVersion: v1 kind: Namespace metadata: name: confidential-containers-system labels: app.kubernetes.io/managed-by: Helm annotations: meta.helm.sh/release-name: peerpods meta.helm.sh/release-namespace: confidential-containers-system EOF -
创建凭证并安装 Helm Chart:
下面命令使用了
-f和--set这两个自定义选项,其含义可参考这里。
使用 kubectl 创建 Secret。所需 key 请参见 providers/aws-secrets.yaml.template。
kubectl create secret generic my-provider-creds \
-n confidential-containers-system \
--from-literal=AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \
--from-literal=AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
--from-file=id_rsa.pub=${SSH_KEY}
说明:
--from-file=id_rsa.pub=${SSH_KEY}是可选项。它允许用户为排障目的通过 SSH 登录 PodVM。 该选项只对启用了调试功能的自定义 PodVM 镜像有效。预构建的 PodVM 镜像默认不启用 SSH 连接。
安装 Helm Chart:
helm install peerpods . \
-f providers/aws.yaml \
--set secrets.mode=reference \
--set secrets.existingSecretName=my-provider-creds \
--dependency-update \
-n confidential-containers-system
使用 IRSA 时,无需创建 AWS 凭证 Secret。CAA Pod 会通过配置认证章节中配置的 IAM 角色完成认证。
使用 IRSA 注解安装 Helm Chart:
helm install peerpods . \
-f providers/aws.yaml \
--set "daemonset.serviceAccount.annotations.eks\.amazonaws\.com/role-arn=${CAA_ROLE_ARN}" \
--set "resourceCtrl.serviceAccount.annotations.eks\.amazonaws\.com/role-arn=${CTRL_ROLE_ARN}" \
--dependency-update \
-n confidential-containers-system
说明:
resourceCtrl.serviceAccount.annotations这一行只有在部署 Peerpod-ctrl 时才需要。 如果不部署它,可以省略这个--set参数,并跳过前文中的 为 Peerpod-ctrl 创建 IAM Role(可选) 步骤。
验证 IRSA 是否生效,可检查服务账号注解和 Pod 环境变量:
kubectl get serviceaccount cloud-api-adaptor \
-n confidential-containers-system \
-o jsonpath='{.metadata.annotations.eks\.amazonaws\.com/role-arn}'
CAA_POD=$(kubectl get pods -n confidential-containers-system \
-l app=cloud-api-adaptor \
-o jsonpath='{.items[0].metadata.name}')
kubectl exec -n confidential-containers-system ${CAA_POD} -- env | grep AWS
输出中应包含 AWS_WEB_IDENTITY_TOKEN_FILE 和 AWS_ROLE_ARN 变量。
通用的 Peer Pods Helm Chart 部署说明也可参考这里。
运行示例应用
确认 RuntimeClass 已创建
部署 CAA 后,请确认已创建 RuntimeClass:
kubectl get runtimeclass
当你看到名为 kata-remote 的 RuntimeClass 时,就说明部署成功。成功输出类似如下:
$ kubectl get runtimeclass
NAME HANDLER AGE
kata-remote kata-remote 7m18s
部署工作负载
创建一个 nginx deployment:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
runtimeClassName: kata-remote
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
imagePullPolicy: Always
EOF
确认 pod 已成功启动:
kubectl get pods -n default
你可以通过运行以下命令确认 peer pod VM 是否已经创建:
aws ec2 describe-instances --filters "Name=tag:Name,Values=podvm*" \
--query 'Reservations[*].Instances[*].[InstanceId, Tags[?Key==`Name`].Value | [0]]' --output table
此时你应该能看到与 pod nginx 对应的虚拟机。
说明: 如果遇到问题,请查看故障排查指南。
清理
删除所有使用 kata-remote runtimeclass 运行的 Pod。可以使用以下命令:
kubectl get pods -A -o custom-columns='NAME:.metadata.name,NAMESPACE:.metadata.namespace,RUNTIMECLASS:.spec.runtimeClassName' | grep kata-remote | awk '{print $1, $2}'
确认所有 peer-pod VM 都已删除。你可以使用以下命令列出所有 peer-pod VM(名称前缀为 podvm)及其状态:
aws ec2 describe-instances --filters "Name=tag:Name,Values=podvm*" \
--query 'Reservations[*].Instances[*].[InstanceId, Tags[?Key==`Name`].Value | [0], State.Name]' --output table
运行以下命令删除 EKS 集群:
eksctl delete cluster --name=$CLUSTER_NAME
4.2 - Azure
说明: 本文为英文文档的中文译版,英文原版请参见 Azure 示例(英文版)。
本文将介绍如何在 Azure Kubernetes Service (AKS) 上配置 CAA(即 Peer Pods),具体包括:
- 一个基于 Azure Kubernetes Service (AKS) 的单工作节点 Kubernetes 集群
- 运行在该 Kubernetes 集群上的 CAA
- 一个由 CAA PodVM 支撑的 Nginx Pod
Confidential Containers 也支持将 Azure Key Vault 用作 Trustee 的资源后端。 更多信息
前提条件
安装所需工具:
Azure 准备工作
登录 Azure
以下许多步骤均需先登录 Azure 账号:
az login
获取你的订阅 ID:
export AZURE_SUBSCRIPTION_ID=$(az account show --query id --output tsv)
设置区域:
export AZURE_REGION="eastus"
说明: 选择
eastus区域,是因为这里既提供 AMD SEV-SNP 实例,也提供可直接使用的预构建 PodVM 镜像。
export AZURE_REGION="eastus2"
说明: 选择
eastus2区域,是因为这里既提供 Intel TDX 实例,也提供可直接使用的预构建 PodVM 镜像。
export AZURE_REGION="eastus"
说明: 选择
eastus区域,是因为这里提供可直接使用的预构建 PodVM 镜像。
资源组
说明: 如果你已经有可用的资源组,可以跳过这一步。请将资源组名称导出到环境变量
AZURE_RESOURCE_GROUP。
运行以下命令创建 Azure 资源组:
export AZURE_RESOURCE_GROUP="caa-rg-$(date '+%Y%m%b%d%H%M%S')"
az group create \
--name "${AZURE_RESOURCE_GROUP}" \
--location "${AZURE_REGION}"
使用 AKS 部署 Kubernetes
按需修改以下环境变量:
export CLUSTER_NAME="caa-$(date '+%Y%m%b%d%H%M%S')"
export AKS_WORKER_USER_NAME="azuser"
export AKS_RG="${AZURE_RESOURCE_GROUP}-aks"
export SSH_KEY=~/.ssh/id_rsa.pub
说明: 你也可以通过增加参数
--vnet-subnet-id $MY_SUBNET_ID,将工作节点部署到现有的 Azure Virtual Network (VNet) 和子网中。
将一个单工作节点的 AKS 集群部署到你刚刚创建的资源组中:
az aks create \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--node-resource-group "${AKS_RG}" \
--name "${CLUSTER_NAME}" \
--enable-oidc-issuer \
--enable-workload-identity \
--location "${AZURE_REGION}" \
--node-count 1 \
--node-vm-size Standard_F4s_v2 \
--nodepool-labels node.kubernetes.io/worker= \
--ssh-access disabled \
--admin-username "${AKS_WORKER_USER_NAME}" \
--os-sku Ubuntu
将 kubeconfig 下载到本地,以便用 kubectl 访问集群:
az aks get-credentials \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--name "${CLUSTER_NAME}"
用户分配身份与联合凭证
CAA 需要具备访问 Azure API 的权限。做法是将工作负载身份(workload identity)关联到 CAA 的服务账号上。该工作负载身份(即用户分配身份)将在下一步被授予创建虚拟机、获取镜像和访问网络的权限。
说明: 如果你使用的是现有 AKS 集群,可能需要先配置工作负载身份(workload identity)和 OpenID Connect (OIDC)。可参考指南。
先为 CAA 创建一个身份:
export AZURE_WORKLOAD_IDENTITY_NAME="${CLUSTER_NAME}-identity"
az identity create \
--name "${AZURE_WORKLOAD_IDENTITY_NAME}" \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--location "${AZURE_REGION}"
export USER_ASSIGNED_CLIENT_ID="$(az identity show \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--name "${AZURE_WORKLOAD_IDENTITY_NAME}" \
--query 'clientId' \
-otsv)"
网络
承载 Pod 的虚拟机通常需要访问互联网服务,例如从公共 OCI 镜像仓库拉取镜像。你可以在 AKS 集群所在 VNet 中,为 AKS 子网旁边新建一个独立子网,再为该子网绑定带公网 IP 的 NAT 网关:
export AZURE_VNET_NAME="$(az network vnet list -g ${AKS_RG} --query '[].name' -o tsv)"
export AKS_CIDR="$(az network vnet show -n $AZURE_VNET_NAME -g $AKS_RG --query "subnets[?name == 'aks-subnet'].addressPrefix" -o tsv)"
# 10.224.0.0/16
export MASK="${AKS_CIDR#*/}"
# 16
PEERPOD_CIDR="$(sipcalc $AKS_CIDR -n 2 | grep ^Network | grep -v current | cut -d' ' -f2)/${MASK}"
# 10.225.0.0/16
az network public-ip create -g "$AKS_RG" -n peerpod
az network nat gateway create -g "$AKS_RG" -l "$AZURE_REGION" --public-ip-addresses peerpod -n peerpod
az network vnet subnet create -g "$AKS_RG" --vnet-name "$AZURE_VNET_NAME" --nat-gateway peerpod --address-prefixes "$PEERPOD_CIDR" -n peerpod
export AZURE_SUBNET_ID="$(az network vnet subnet show -g "$AKS_RG" --vnet-name "$AZURE_VNET_NAME" -n peerpod --query id -o tsv)"
AKS 资源组权限
为了让 CAA 能管理虚拟机,需为该身份授予虚拟机和网络相关权限,使其能够在 $AZURE_RESOURCE_GROUP 中创建虚拟机,并连接 $AKS_RG 中的 VNet。
az role assignment create \
--role "Virtual Machine Contributor" \
--assignee "$USER_ASSIGNED_CLIENT_ID" \
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourcegroups/${AZURE_RESOURCE_GROUP}"
az role assignment create \
--role "Reader" \
--assignee "$USER_ASSIGNED_CLIENT_ID" \
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourcegroups/${AZURE_RESOURCE_GROUP}"
az role assignment create \
--role "Network Contributor" \
--assignee "$USER_ASSIGNED_CLIENT_ID" \
--scope "/subscriptions/${AZURE_SUBSCRIPTION_ID}/resourcegroups/${AKS_RG}"
使用 AKS 集群的 OIDC endpoint 为 CAA ServiceAccount 创建联合凭证:
export AKS_OIDC_ISSUER="$(az aks show \
--name "${CLUSTER_NAME}" \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--query "oidcIssuerProfile.issuerUrl" \
-otsv)"
az identity federated-credential create \
--name "${CLUSTER_NAME}-federated" \
--identity-name "${AZURE_WORKLOAD_IDENTITY_NAME}" \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--issuer "${AKS_OIDC_ISSUER}" \
--subject system:serviceaccount:confidential-containers-system:cloud-api-adaptor \
--audience api://AzureADTokenExchange
部署 CAA Helm Chart
说明: 如果你的 Kubernetes 集群使用 Calico Container Network Interface (CNI),请先按说明为所有工作负载间流量配置 Virtual Extensible LAN (VXLAN) 封装。
下载 CAA Helm 部署资源
export CAA_VERSION="0.17.0"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/tags/v${CAA_VERSION}.tar.gz"
tar -xvzf "v${CAA_VERSION}.tar.gz"
cd "cloud-api-adaptor-${CAA_VERSION}/src/cloud-api-adaptor/install/charts/peerpods"
export CAA_BRANCH="main"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/heads/${CAA_BRANCH}.tar.gz"
tar -xvzf "${CAA_BRANCH}.tar.gz"
cd "cloud-api-adaptor-${CAA_BRANCH}/src/cloud-api-adaptor/install/charts/peerpods"
假如你已在本地准备好代码,请在终端中切换到 Cloud API Adaptor 的代码目录。
导出 PodVM 镜像版本
导出 peer pods 所用的 PodVM 镜像 ID。该变量告诉部署工具在 Azure 中创建 peer pod 虚拟机时应使用哪个 PodVM 镜像版本。
镜像来自 CoCo 社区镜像库(或由你手动构建),并且必须与当前 CAA 发布版本匹配。
导出以下环境变量,作为 peer pod VM 使用的镜像:
export AZURE_IMAGE_ID="/CommunityGalleries/cococommunity-42d8482d-92cd-415b-b332-7648bd978eff/Images/peerpod-podvm-fedora/Versions/${CAA_VERSION}"
自动化任务会在每天 00:00 UTC 构建一次 PodVM 镜像。你可以导出以下环境变量来使用该镜像:
SUCCESS_TIME=$(curl -s \
-H "Accept: application/vnd.github+json" \
"https://api.github.com/repos/confidential-containers/cloud-api-adaptor/actions/workflows/azure-nightly-build.yml/runs?status=success" \
| jq -r '.workflow_runs[0].updated_at')
export AZURE_IMAGE_ID="/CommunityGalleries/cocopodvm-d0e4f35f-5530-4b9c-8596-112487cdea85/Images/podvm_image0/Versions/$(date -u -jf "%Y-%m-%dT%H:%M:%SZ" "$SUCCESS_TIME" "+%Y.%m.%d" 2>/dev/null || date -d "$SUCCESS_TIME" +%Y.%m.%d)"
版本号格式为 YYYY.MM.DD,最新镜像对应今天或前一天的日期。
如果你修改了会影响 PodVM 镜像的 CAA 代码,并希望部署这些改动,请按这些说明构建 PodVM 镜像。
镜像构建完成后,将镜像 ID 导出到环境变量 AZURE_IMAGE_ID。
导出 CAA 容器镜像路径
定义要部署的 Cloud API Adaptor(CAA)容器镜像。 这些变量指定了部署工具所要拉取和运行的 CAA 镜像及其架构专属 tag。 tag 与 CAA 发布版本对应,以确保与所选 PodVM 镜像和配置兼容。
导出以下环境变量以使用 CAA 最新发布镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
export CAA_TAG="v${CAA_VERSION}-amd64"
导出以下环境变量,以使用每次合并到 main 后由 CAA CI 构建的镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
你可以在这里找到适合需求的预构建镜像 tag。
export CAA_TAG=""
注意: 你也可以使用
latesttag,但不推荐这样做,因为它缺少版本控制,可能引入不可预期的更新,影响部署稳定性和可复现性。
如果你修改了 CAA 代码并希望部署这些改动,请按说明构建容器镜像。镜像构建完成后,导出环境变量 CAA_IMAGE 和 CAA_TAG。
选择 peer-pods 机型
export AZURE_INSTANCE_SIZE="Standard_DC2as_v5"
export DISABLECVM="false"
更多 AMD SEV-SNP 机型可参考Azure 文档 。
export AZURE_INSTANCE_SIZE="Standard_DC2es_v6"
export DISABLECVM="false"
更多 Intel TDX 机型可参考Azure 文档。
export AZURE_INSTANCE_SIZE="Standard_D2as_v5"
export DISABLECVM="true"
填充 providers/azure.yaml 文件
全部可用配置项可在以下两个位置找到:
运行以下命令更新 providers/azure.yaml 文件:
cat <<EOF > providers/azure.yaml
provider: azure
image:
name: "${CAA_IMAGE}"
tag: "${CAA_TAG}"
providerConfigs:
azure:
AZURE_IMAGE_ID: "${AZURE_IMAGE_ID}"
AZURE_REGION: "${AZURE_REGION}"
AZURE_RESOURCE_GROUP: "${AZURE_RESOURCE_GROUP}"
AZURE_SUBNET_ID: "${AZURE_SUBNET_ID}"
AZURE_SUBSCRIPTION_ID: "${AZURE_SUBSCRIPTION_ID}"
AZURE_INSTANCE_SIZE: "${AZURE_INSTANCE_SIZE}"
DISABLECVM: ${DISABLECVM}
EOF
在 Kubernetes 集群中部署 Helm Chart
-
创建由 Helm 管理的命名空间:
kubectl apply -f - << EOF apiVersion: v1 kind: Namespace metadata: name: confidential-containers-system labels: app.kubernetes.io/managed-by: Helm annotations: meta.helm.sh/release-name: peerpods meta.helm.sh/release-namespace: confidential-containers-system EOF -
使用
kubectl创建 Secret:所需 key 请参见 providers/azure-secrets.yaml.template。
说明: 以下示例假定你使用工作负载身份(workload identity)进行认证,因此不需要提供
AZURE_CLIENT_SECRET和AZURE_TENANT_ID。
kubectl create secret generic my-provider-creds \
-n confidential-containers-system \
--from-literal=AZURE_CLIENT_ID="${USER_ASSIGNED_CLIENT_ID}" \
--from-file=id_rsa.pub=${SSH_KEY}
说明:
--from-file=id_rsa.pub=${SSH_KEY}是可选项。它允许用户为排障目的通过 SSH 登录 PodVM。 该选项只对启用了调试功能的自定义 PodVM 镜像有效。预构建的 PodVM 镜像默认不启用 SSH 连接。
-
安装 Helm Chart:
下面命令使用了
-f和--set这两个自定义选项,其含义可参考这里。helm install peerpods . \ -f providers/azure.yaml \ --set secrets.mode=reference \ --set secrets.existingSecretName=my-provider-creds \ --set-json daemonset.podLabels='{"azure.workload.identity/use":"true"}' \ --dependency-update \ -n confidential-containers-system
说明: 上述示例假定你使用工作负载身份(workload identity)进行认证。
--set-json daemonset.podLabels='{{"azure.workload.identity/use":"true"}}'参数仅在使用工作负载身份时才需要。
通用的 Peer Pods Helm Chart 部署说明也可参考这里。
运行示例应用
确认 RuntimeClass 已创建
部署 Peer Pods Helm Chart 后,请确认已创建 runtimeclass:
kubectl get runtimeclass
当你看到名为 kata-remote 的 runtimeclass 时,就说明部署成功。
成功输出类似如下:
$ kubectl get runtimeclass
NAME HANDLER AGE
kata-remote kata-remote 7m18s
部署工作负载
创建一个 nginx deployment:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
runtimeClassName: kata-remote
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
imagePullPolicy: Always
EOF
确认 pod 已成功启动:
kubectl get pods -n default
你可以通过运行以下命令确认 peer pod VM 是否已经创建:
az vm list \
--resource-group "${AZURE_RESOURCE_GROUP}" \
--output table
此时你应该能看到与 pod nginx 对应的虚拟机。
说明: 如果遇到问题,请查看故障排查指南。
PodVM 参考值
PodVM 镜像在构建过程中,会把预期的 PCR 测量值发布到 OCI 镜像仓库中。
前提条件
安装 ORAS 工具,以便从 OCI 镜像仓库拉取参考值;安装 GitHub CLI,以便验证构建来源。
验证构建来源
确认这些测量值是由官方仓库中可信的构建流程生成的。指定 --format=json 可以看到更详细的构建信息。
CAA_REPO="confidential-containers/cloud-api-adaptor"
OCI_REGISTRY="ghcr.io/${CAA_REPO}/measurements/azure/podvm:${CAA_VERSION}"
gh attestation verify -R "$CAA_REPO" "oci://${OCI_REGISTRY}"
获取参考值
这些 PCR 值可用于远程证明策略中,以校验 PodVM 镜像的完整性。
oras pull "$OCI_REGISTRY"
jq -r .measurements.sha256.pcr11 < measurements.json
0x58e8afdf5b105fc6b202eb8e537a9f1512a4b33cd5921171b518645a86ca5a75
清理
如果你希望清理整个环境,可以运行以下命令删除资源组:
az group delete \
--name "${AZURE_RESOURCE_GROUP}" \
--yes --no-wait
4.3 - GCP
说明: 本文为英文文档的中文译版,英文原版请参见 GCP 示例(英文版)。
本文将介绍如何在 Google Kubernetes Engine (GKE) 上配置 CAA(即 Peer Pods),具体包括:
- 一个基于 GKE 的单工作节点 Kubernetes 集群
- 运行在该 Kubernetes 集群上的 CAA
- 一个由 CAA PodVM 支持的示例应用
前提条件
安装所需工具:
Google Cloud 项目:
- 确保你已经创建了一个 Google Cloud 项目
- 记录项目 ID(导出为
GCP_PROJECT_ID)
GCP 准备工作
先完成 Google 认证,并选择要使用的项目:
export GCP_PROJECT_ID="YOUR_PROJECT_ID"
gcloud auth login
gcloud config set project ${GCP_PROJECT_ID}
启用所需 API:
gcloud services enable container.googleapis.com --project=${GCP_PROJECT_ID}
创建一个具备所需权限的服务账号:
gcloud iam service-accounts create peerpods \
--description="Peerpods Service Account" \
--display-name="Peerpods Service Account"
gcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \
--member="serviceAccount:peerpods@${GCP_PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/compute.instanceAdmin.v1"
gcloud projects add-iam-policy-binding ${GCP_PROJECT_ID} \
--member="serviceAccount:peerpods@${GCP_PROJECT_ID}.iam.gserviceaccount.com" \
--role="roles/iam.serviceAccountUser"
生成并保存凭证文件:
gcloud iam service-accounts keys create \
~/.config/gcloud/peerpods_application_key.json \
--iam-account=peerpods@${GCP_PROJECT_ID}.iam.gserviceaccount.com
export GOOGLE_APPLICATION_CREDENTIALS=~/.config/gcloud/peerpods_application_key.json
配置后续要使用的其他环境变量。
设置区域:
export GCP_REGION="us-central1"
之所以选择 us-central1,是因为它支持机密虚拟机。支持区域的完整列表请访问:
https://cloud.google.com/confidential-computing/confidential-vm/docs/supported-configurations#supported-zones
设置 PodVM 实例类型:
export PODVM_INSTANCE_TYPE="n2d-standard-4"
export DISABLECVM=false
export GCP_CONFIDENTIAL_TYPE="SEV" # SEV or SEV_SNP
export GCP_DISK_TYPE="pd-standard"
export PODVM_INSTANCE_TYPE="c3-standard-4"
export DISABLECVM=false
export GCP_CONFIDENTIAL_TYPE="TDX"
export GCP_DISK_TYPE="pd-balanced"
export PODVM_INSTANCE_TYPE="e2-medium"
export DISABLECVM=true
export GCP_CONFIDENTIAL_TYPE=""
export GCP_DISK_TYPE="pd-standard"
使用 GKE 部署 Kubernetes
使用 GKE 部署一个单节点 Kubernetes 集群:
gcloud container clusters create my-cluster \
--zone ${GCP_REGION}-a \
--machine-type "e2-standard-4" \
--image-type UBUNTU_CONTAINERD \
--num-nodes 1
为工作节点添加标签:
kubectl get nodes --selector='!node-role.kubernetes.io/master' -o name | \
xargs -I{} kubectl label {} node.kubernetes.io/worker=
从 GKE 1.27 开始,GCP 会为 containerd 配置 discard_unpacked_layers=true,以节省磁盘空间(移除解包后的压缩镜像层)。但这可能会导致 PeerPods 出现问题,因为工作负载可能找不到所需镜像层。
为避免这个问题,请在 containerd 配置中禁用 discard_unpacked_layers。
如果遇到虚拟机未正常运行的问题,请查看本页的故障排查部分。
配置 VPC 网络
我们需要确保默认 VPC 网络中已经放通 15150 端口:
gcloud compute firewall-rules create allow-port-15150 \
--project=${GCP_PROJECT_ID} \
--network=default \
--allow=tcp:15150
在生产场景中,建议限制来源 IP 范围,以降低安全风险。例如,可以把来源范围限制为特定 IP 地址或 CIDR 段:
gcloud compute firewall-rules create allow-port-15150-restricted \
--project=${GCP_PROJECT_ID} \
--network=default \
--allow=tcp:15150 \
--source-ranges=[YOUR_EXTERNAL_IP]
部署 CAA Helm Chart
下载 CAA Helm 部署资源
export CAA_VERSION="0.17.0"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/tags/v${CAA_VERSION}.tar.gz"
tar -xvzf "v${CAA_VERSION}.tar.gz"
cd "cloud-api-adaptor-${CAA_VERSION}/src/cloud-api-adaptor/install/charts/peerpods"
export CAA_BRANCH="main"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/heads/${CAA_BRANCH}.tar.gz"
tar -xvzf "${CAA_BRANCH}.tar.gz"
cd "cloud-api-adaptor-${CAA_BRANCH}/src/cloud-api-adaptor/install/charts/peerpods"
此方式假定你已在本地准备好代码,请在终端中切换到 Cloud API Adaptor 的代码目录。
导出 PodVM 镜像版本
导出 peer pods 所用的 PodVM 镜像 ID。该变量告诉部署工具在 Google Cloud 中创建 peer pod 虚拟机时应使用哪个 PodVM 镜像版本。
镜像来自 CoCo 社区镜像库(或由你手动构建),并且必须与当前 CAA 发布版本匹配。
导出以下环境变量,作为 PodVM 使用的镜像:
export PODVM_IMAGE_ID="/projects/it-cloud-gcp-prod-osc-devel/global/images/fedora-mkosi-tee-amd-1-11-0"
最新构建没有预构建的 PodVM 镜像。你需要按说明构建 PodVM 镜像。镜像构建完成后,将镜像 ID 导出到环境变量 PODVM_IMAGE_ID。
如果你修改了会影响 PodVM 镜像的 CAA 代码,并希望部署这些改动,请按说明构建 PodVM 镜像。镜像构建完成后,将镜像 ID 导出到环境变量 PODVM_IMAGE_ID。
导出 CAA 容器镜像路径
定义要部署的 Cloud API Adaptor(CAA)容器镜像。 这些变量指定了部署工具所要拉取和运行的 CAA 镜像及其架构专属 tag。 tag 与 CAA 发布版本对应,以确保与所选 PodVM 镜像和配置兼容。
导出以下环境变量以使用 CAA 最新发布镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
export CAA_TAG="v${CAA_VERSION}-amd64"
导出以下环境变量,以使用每次合并到 main 后由 CAA CI 构建的镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
你可以在这里找到适合需求的预构建镜像 tag。
export CAA_TAG=""
注意: 你也可以使用
latesttag,但不推荐这样做,因为它缺少版本控制,可能引入不可预期的更新,影响部署稳定性和可复现性。
如果你修改了 CAA 代码并希望部署这些改动,请按这些说明构建容器镜像。镜像构建完成后,导出环境变量 CAA_IMAGE 和 CAA_TAG。
填充 providers/gcp.yaml 文件
全部可用配置项可在以下两个位置找到:
运行以下命令更新 providers/gcp.yaml 文件:
cat <<EOF > providers/gcp.yaml
provider: gcp
image:
name: "${CAA_IMAGE}"
tag: "${CAA_TAG}"
providerConfigs:
gcp:
GCP_NETWORK: "global/networks/default"
GCP_PROJECT_ID: "${GCP_PROJECT_ID}"
GCP_ZONE: "${GCP_REGION}-a"
GCP_MACHINE_TYPE: "${PODVM_INSTANCE_TYPE}"
GCP_DISK_TYPE: "${GCP_DISK_TYPE}"
PODVM_IMAGE_NAME: "${PODVM_IMAGE_ID}"
GCP_CONFIDENTIAL_TYPE: "${GCP_CONFIDENTIAL_TYPE}"
DISABLECVM: ${DISABLECVM}
EOF
在 Kubernetes 集群中部署 Helm Chart
-
创建由 Helm 管理的命名空间:
kubectl apply -f - << EOF apiVersion: v1 kind: Namespace metadata: name: confidential-containers-system labels: app.kubernetes.io/managed-by: Helm annotations: meta.helm.sh/release-name: peerpods meta.helm.sh/release-namespace: confidential-containers-system EOF -
使用
kubectl创建 Secret:所需 key 请参见 providers/gcp-secrets.yaml.template。
kubectl create secret generic my-provider-creds \ -n confidential-containers-system \ --from-file=GCP_CREDENTIALS="${GOOGLE_APPLICATION_CREDENTIALS}" -
安装 Helm Chart:
下面命令使用了
-f和--set这两个自定义选项,其含义可参考这里。helm install peerpods . \ -f providers/gcp.yaml \ --set secrets.mode=reference \ --set secrets.existingSecretName=my-provider-creds \ --dependency-update \ -n confidential-containers-system
通用的 Peer Pods Helm Chart 部署说明也可参考这里。
运行示例应用
确认 RuntimeClass 已创建
部署 Peer Pods Helm Chart 后,请确认已创建 runtimeclass:
kubectl get runtimeclass
当你看到名为 kata-remote 的 runtimeclass 时,就说明部署成功。
成功输出类似如下:
$ kubectl get runtimeclass
NAME HANDLER AGE
kata-remote kata-remote 7m18s
部署工作负载
本示例展示了一个更完整的部署方式:结合 TEE、机密虚拟机以及 kata-remote RuntimeClass,演示如何部署示例 Pod 并在机密计算环境中安全获取机密。
准备 init data 配置
Peer Pods 现已支持 init data。你可以通过注解 io.katacontainers.config.hypervisor.cc_init_data 传入所需配置文件(aa.toml、cdh.toml 和 policy.rego)。下面给出配置和使用示例。
# initdata.toml
algorithm = "sha384"
version = "0.1.0"
[data]
"aa.toml" = '''
[token_configs]
[token_configs.coco_as]
url = 'http://127.0.0.1:8080'
[token_configs.kbs]
url = 'http://127.0.0.1:8080'
cert = """
-----BEGIN CERTIFICATE-----
MIIDljCCAn6gAwIBAgIUR/UNh13GFam4emgludtype/S9BIwDQYJKoZIhvcNAQEL
BQAwdTELMAkGA1UEBhMCQ04xETAPBgNVBAgMCFpoZWppYW5nMREwDwYDVQQHDAhI
YW5nemhvdTERMA8GA1UECgwIQUFTLVRFU1QxFDASBgNVBAsMC0RldmVsb3BtZW50
MRcwFQYDVQQDDA5BQVMtVEVTVC1IVFRQUzAeFw0yNDAzMTgwNzAzNTNaFw0yNTAz
MTgwNzAzNTNaMHUxCzAJBgNVBAYTAkNOMREwDwYDVQQIDAhaaGVqaWFuZzERMA8G
A1UEBwwISGFuZ3pob3UxETAPBgNVBAoMCEFBUy1URVNUMRQwEgYDVQQLDAtEZXZl
bG9wbWVudDEXMBUGA1UEAwwOQUFTLVRFU1QtSFRUUFMwggEiMA0GCSqGSIb3DQEB
AQUAA4IBDwAwggEKAoIBAQDfp1aBr6LiNRBlJUcDGcAbcUCPG6UzywtVIc8+comS
ay//gwz2AkDmFVvqwI4bdp/NUCwSC6ShHzxsrCEiagRKtA3af/ckM7hOkb4S6u/5
ewHHFcL6YOUp+NOH5/dSLrFHLjet0dt4LkyNBPe7mKAyCJXfiX3wb25wIBB0Tfa0
p5VoKzwWeDQBx7aX8TKbG6/FZIiOXGZdl24DGARiqE3XifX7DH9iVZ2V2RL9+3WY
05GETNFPKtcrNwTy8St8/HsWVxjAzGFzf75Lbys9Ff3JMDsg9zQzgcJJzYWisxlY
g3CmnbENP0eoHS4WjQlTUyY0mtnOwodo4Vdf8ZOkU4wJAgMBAAGjHjAcMBoGA1Ud
EQQTMBGCCWxvY2FsaG9zdIcEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAKW32spii
t2JB7C1IvYpJw5mQ5bhIlldE0iB5rwWvNbuDgPrgfTI4xiX5sumdHw+P2+GU9KXF
nWkFRZ9W/26xFrVgGIS/a07aI7xrlp0Oj+1uO91UhCL3HhME/0tPC6z1iaFeZp8Y
T1tLnafqiGiThFUgvg6PKt86enX60vGaTY7sslRlgbDr9sAi/NDSS7U1PviuC6yo
yJi7BDiRSx7KrMGLscQ+AKKo2RF1MLzlJMa1kIZfvKDBXFzRd61K5IjDRQ4HQhwX
DYEbQvoZIkUTc1gBUWDcAUS5ztbJg9LCb9WVtvUTqTP2lGuNymOvdsuXq+sAZh9b
M9QaC1mzQ/OStg==
-----END CERTIFICATE-----
"""
'''
"cdh.toml" = '''
socket = 'unix:///run/confidential-containers/cdh.sock'
credentials = []
[kbc]
name = 'cc_kbc'
url = 'http://1.2.3.4:8080'
kbs_cert = """
-----BEGIN CERTIFICATE-----
MIIFTDCCAvugAwIBAgIBADBGBgkqhkiG9w0BAQowOaAPMA0GCWCGSAFlAwQCAgUA
oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAgUAogMCATCjAwIBATB7MRQwEgYD
VQQLDAtFbmdpbmVlcmluZzELMAkGA1UEBhMCVVMxFDASBgNVBAcMC1NhbnRhIENs
YXJhMQswCQYDVQQIDAJDQTEfMB0GA1UECgwWQWR2YW5jZWQgTWljcm8gRGV2aWNl
czESMBAGA1UEAwwJU0VWLU1pbGFuMB4XDTIzMDEyNDE3NTgyNloXDTMwMDEyNDE3
NTgyNlowejEUMBIGA1UECwwLRW5naW5lZXJpbmcxCzAJBgNVBAYTAlVTMRQwEgYD
VQQHDAtTYW50YSBDbGFyYTELMAkGA1UECAwCQ0ExHzAdBgNVBAoMFkFkdmFuY2Vk
IE1pY3JvIERldmljZXMxETAPBgNVBAMMCFNFVi1WQ0VLMHYwEAYHKoZIzj0CAQYF
K4EEACIDYgAExmG1ZbuoAQK93USRyZQcsyobfbaAEoKEELf/jK39cOVJt1t4s83W
XM3rqIbS7qHUHQw/FGyOvdaEUs5+wwxpCWfDnmJMAQ+ctgZqgDEKh1NqlOuuKcKq
2YAWE5cTH7sHo4IBFjCCARIwEAYJKwYBBAGceAEBBAMCAQAwFwYJKwYBBAGceAEC
BAoWCE1pbGFuLUIwMBEGCisGAQQBnHgBAwEEAwIBAzARBgorBgEEAZx4AQMCBAMC
AQAwEQYKKwYBBAGceAEDBAQDAgEAMBEGCisGAQQBnHgBAwUEAwIBADARBgorBgEE
AZx4AQMGBAMCAQAwEQYKKwYBBAGceAEDBwQDAgEAMBEGCisGAQQBnHgBAwMEAwIB
CDARBgorBgEEAZx4AQMIBAMCAXMwTQYJKwYBBAGceAEEBEDDhCejDUx6+dlvehW5
cmmCWmTLdqI1L/1dGBFdia1HP46MC82aXZKGYSutSq37RCYgWjueT+qCMBE1oXDk
d1JOMEYGCSqGSIb3DQEBCjA5oA8wDQYJYIZIAWUDBAICBQChHDAaBgkqhkiG9w0B
AQgwDQYJYIZIAWUDBAICBQCiAwIBMKMDAgEBA4ICAQACgCai9x8DAWzX/2IelNWm
ituEBSiq9C9eDnBEckQYikAhPasfagnoWFAtKu/ZWTKHi+BMbhKwswBS8W0G1ywi
cUWGlzigI4tdxxf1YBJyCoTSNssSbKmIh5jemBfrvIBo1yEd+e56ZJMdhN8e+xWU
bvovUC2/7Dl76fzAaACLSorZUv5XPJwKXwEOHo7FIcREjoZn+fKjJTnmdXce0LD6
9RHr+r+ceyE79gmK31bI9DYiJoL4LeGdXZ3gMOVDR1OnDos5lOBcV+quJ6JujpgH
d9g3Sa7Du7pusD9Fdap98ocZslRfFjFi//2YdVM4MKbq6IwpYNB+2PCEKNC7SfbO
NgZYJuPZnM/wViES/cP7MZNJ1KUKBI9yh6TmlSsZZOclGJvrOsBZimTXpATjdNMt
cluKwqAUUzYQmU7bf2TMdOXyA9iH5wIpj1kWGE1VuFADTKILkTc6LzLzOWCofLxf
onhTtSDtzIv/uel547GZqq+rVRvmIieEuEvDETwuookfV6qu3D/9KuSr9xiznmEg
xynud/f525jppJMcD/ofbQxUZuGKvb3f3zy+aLxqidoX7gca2Xd9jyUy5Y/83+ZN
bz4PZx81UJzXVI9ABEh8/xilATh1ZxOePTBJjN7lgr0lXtKYjV/43yyxgUYrXNZS
oLSG2dLCK9mjjraPjau34Q==
-----END CERTIFICATE-----
"""
'''
"policy.rego" = '''
package agent_policy
import future.keywords.in
import future.keywords.every
import input
# Default values, returned by OPA when rules cannot be evaluated to true.
default CopyFileRequest := true
default CreateContainerRequest := true
default CreateSandboxRequest := true
default DestroySandboxRequest := true
default ExecProcessRequest := false
default GetOOMEventRequest := true
default GuestDetailsRequest := true
default OnlineCPUMemRequest := true
default PullImageRequest := true
default ReadStreamRequest := false
default RemoveContainerRequest := true
default RemoveStaleVirtiofsShareMountsRequest := true
default SignalProcessRequest := true
default StartContainerRequest := true
default StatsContainerRequest := true
default TtyWinResizeRequest := true
default UpdateEphemeralMountsRequest := true
default UpdateInterfaceRequest := true
default UpdateRoutesRequest := true
default WaitProcessRequest := true
default WriteStreamRequest := false
'''
请确认策略正确,并且 KBC URL 已指向你的 Key Broker Service。
然后对 initdata.toml 进行编码并保存为变量:
INITDATA=$(cat initdata.toml | gzip | base64 -w0)
使用以下命令部署 Pod:
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: example-pod
annotations:
io.katacontainers.config.hypervisor.cc_init_data: "$INITDATA"
spec:
runtimeClassName: kata-remote
containers:
- name: example-container
image: alpine:latest
command:
- sleep
- "3600"
securityContext:
privileged: false
seccompProfile:
type: RuntimeDefault
EOF
从 Trustee 获取机密
Pod 成功携带 initdata 部署后,你可以在 Pod 内部从 Trustee 服务获取机密。使用以下命令获取指定机密:
kubectl exec -it example-pod -- curl http://127.0.0.1:8006/cdh/resource/default/kbsres1/key1
本示例是最基础的部署验证,用于确认 Helm Chart 是否已在云厂商侧成功启动 PodVM。
创建一个 nginx deployment:
cat <<EOF | kubectl apply -f -
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
selector:
matchLabels:
app: nginx
replicas: 1
template:
metadata:
labels:
app: nginx
spec:
runtimeClassName: kata-remote
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
imagePullPolicy: Always
EOF
确认 pod 已成功启动:
kubectl get pods -n default
你可以通过运行以下命令确认 PodVM 是否已经创建:
gcloud compute instances list
此时你应该能看到与上述示例 Pod 对应的虚拟机。
清理
删除所有使用 kata-remote RuntimeClass 运行的 Pod。可以使用以下命令:
kubectl get pods -A -o custom-columns='NAME:.metadata.name,NAMESPACE:.metadata.namespace,RUNTIMECLASS:.spec.runtimeClassName' | grep kata-remote | awk '{print $1, $2}'
确认所有 peer-pod VM 都已删除。你可以使用以下命令列出所有 peer-pod VM(名称前缀为 podvm)及其状态:
gcloud compute instances list \
--filter="name~'podvm.*'" \
--format="table(name,zone,status)"
运行以下命令删除 GKE 集群:
gcloud container clusters delete my-cluster --zone ${GCP_REGION}-a
故障排查
说明: 如果你的问题不在下面的范围内,请查看这里的故障排查指南。
虚拟机未启动
从 GKE 1.27 开始,GCP 会为 containerd 配置 discard_unpacked_layers=true,以节省磁盘空间(移除解包后的压缩镜像层)。但这可能会导致 PeerPods 出现问题,因为工作负载可能找不到所需镜像层。
为避免这个问题,请在 containerd 配置中禁用 discard_unpacked_layers。
大多数情况下,你会看到类似下面的通用报错:
Error: failed to create containerd container: error unpacking image: failed to extract layer sha256:<SHA>: failed to get reader from content store: content digest sha256:<SHA>: not found
要在 Google Kubernetes Engine (GKE) 1.27 及以上版本中禁用 containerd 配置里的 discard_unpacked_layers,请按以下步骤操作:
- 在 Google Console 中 SSH 登录工作节点
- 运行命令
sudo sed -i 's/discard_unpacked_layers = true/discard_unpacked_layers = false/' /etc/containerd/config.toml - 运行
sudo cat /etc/containerd/config.toml | grep discard_unpacked_layers验证修改结果 - 重启 containerd:
sudo systemctl restart containerd
4.4 - 阿里云
说明: 本文为英文文档的中文译版,英文原版请参见阿里云示例(英文版)。
本文将介绍如何在阿里云容器服务 Kubernetes 版(ACK)和阿里云弹性计算服务(ECS)上部署 CAA(即 Peer Pods),具体包括:
- ACK 托管集群中的一个工作节点
- 运行在该 Kubernetes 集群上的 CAA
- 一个由运行在 ECS 上 CAA PodVM 支撑的 Nginx Pod
说明: 请在目录
src/cloud-api-adaptor下运行以下命令。
说明: 当前机密计算实例已在部分地域提供。
说明: 阿里云官方文档可参考这里。
前提条件
安装所需工具:
创建 PodVM 镜像
说明: 在
cn-hongkong地域中,版本0.22.0已提供一个预构建的社区镜像(id:m-j6c3kfz2vhu6ze04wacb),可直接用于测试。 也可以使用下方导出 PodVM 镜像版本中列出的各地域镜像 ID。
如果你希望自行构建 PodVM 镜像,请按以下步骤操作。当前 PodVM 构建使用 mkosi,目标系统为 Ubuntu 26.04(resolute)。前提条件和自定义选项请参见 PodVM README。
-
构建 Ubuntu 26.04 PodVM 镜像。
cd podvm make此命令将构建 PodVM 二进制文件和操作系统镜像,生成的 qcow2 文件路径为:
podvm/build/podvm-ubuntu-amd64.qcow2若二进制文件已存在,仅重新构建操作系统镜像:
cd podvm make image -
上传到 OSS,并创建 ECS 镜像。
在
src/cloud-api-adaptor目录下,将 qcow2 文件上传到 OSS(对象存储服务):cd .. export REGION_ID=<region-id> export IMAGE_FILE=podvm/build/podvm-ubuntu-amd64.qcow2 export BUCKET=<OSS-bucket-name> export OBJECT=<object-name> aliyun oss cp ${IMAGE_FILE} oss://${BUCKET}/${OBJECT}然后将该镜像文件导入为 ECS 镜像:
export IMAGE_NAME=$(basename ${IMAGE_FILE%.*}) aliyun ecs ImportImage --ImageName ${IMAGE_NAME} \ --region ${REGION_ID} --RegionId ${REGION_ID} \ --BootMode UEFI \ --DiskDeviceMapping.1.OSSBucket ${BUCKET} --DiskDeviceMapping.1.OSSObject ${OBJECT} \ --Features.NvmeSupport supported \ --method POST --force export POD_IMAGE_ID=<ImageId>
构建 CAA 开发镜像
如果你希望自行构建 CAA DaemonSet 镜像:
export registry=<registry-address>
export RELEASE_BUILD=true
export CLOUD_PROVIDER=alibabacloud
make image
请记录该镜像使用的 tag,后续会用到。
使用 ACK 托管集群部署 Kubernetes
-
创建 ACK 托管集群。
export CONTAINER_CIDR=172.18.0.0/16 export REGION_ID=cn-beijing export ZONES='["cn-beijing-i"]' aliyun cs CreateCluster --header "Content-Type=application/json" --body " { \"cluster_type\":\"ManagedKubernetes\", \"name\":\"caa\", \"region_id\":\"${REGION_ID}\", \"zone_ids\":${ZONES}, \"enable_rrsa\":true, \"container_cidr\":\"${CONTAINER_CIDR}\", \"addons\":[ { \"name\":\"flannel\" } ] }" export CLUSTER_ID=<cluster-id> export SECURITY_GROUP_ID=$(aliyun cs DescribeClusterDetail --ClusterId ${CLUSTER_ID} | jq -r ".security_group_id")等待集群创建完成。获取该集群的 vSwitch ID,然后为集群添加一个工作节点。
-
为集群所在 VPC 添加公网访问能力。
export VPC_ID=$(aliyun cs DescribeClusterDetail --ClusterId ${CLUSTER_ID} | jq -r ".vpc_id") export VSWITCH_ID=$(echo ${VSWITCH_IDS} | sed 's/[][]//g' | sed 's/"//g') aliyun vpc CreateNatGateway \ --region ${REGION_ID} \ --RegionId ${REGION_ID} \ --VpcId ${VPC_ID} \ --NatType Enhanced \ --VSwitchId ${VSWITCH_ID} \ --NetworkType internet export GATEWAY_ID="<NatGatewayId>" export SNAT_TABLE_ID="<SnatTableId>" # 公网 IP 带宽(Mbps) export BAND_WIDTH=5 aliyun vpc AllocateEipAddress \ --region ${REGION_ID} \ --RegionId ${REGION_ID} \ --Bandwidth ${BAND_WIDTH} export EIP_ID="<AllocationId>" export EIP_ADDRESS="<EipAddress>" aliyun vpc AssociateEipAddress \ --region ${REGION_ID} \ --RegionId ${REGION_ID} \ --AllocationId ${EIP_ID} \ --InstanceId ${GATEWAY_ID} \ --InstanceType Nat aliyun vpc CreateSnatEntry \ --region ${REGION_ID} \ --RegionId ${REGION_ID} \ --SnatTableId ${SNAT_TABLE_ID} \ --SourceVSwitchId ${VSWITCH_ID} \ --SnatIp ${EIP_ADDRESS} -
授予角色权限。
为集群工作节点授予相应角色权限,使其能够创建 ECS 实例。
部署 CAA Helm Chart
下载 CAA Helm 部署资源
export CAA_VERSION="0.22.0"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/tags/v${CAA_VERSION}.tar.gz"
tar -xvzf "v${CAA_VERSION}.tar.gz"
cd "cloud-api-adaptor-${CAA_VERSION}/src/cloud-api-adaptor/install/charts/peerpods"
export CAA_BRANCH="main"
curl -LO "https://github.com/confidential-containers/cloud-api-adaptor/archive/refs/heads/${CAA_BRANCH}.tar.gz"
tar -xvzf "${CAA_BRANCH}.tar.gz"
cd "cloud-api-adaptor-${CAA_BRANCH}/src/cloud-api-adaptor/install/charts/peerpods"
假如你已在本地准备好代码,请在终端中切换到 Cloud API Adaptor 的代码目录。
导出 PodVM 镜像版本
导出 peer pods 所用的 PodVM 镜像 ID。该变量告诉部署工具在阿里云中创建 peer pod 虚拟机时应使用哪个 PodVM 镜像版本。
export IMAGEID="m-j6c3kfz2vhu6ze04wacb"
说明: 阿里云会预先构建这些镜像,不同地域使用不同的镜像 ID。
region IMAGEID cn-beijing m-2ze2vxvrxsbue3sf8b02 cn-hongkong m-j6c3kfz2vhu6ze04wacb cn-hangzhou m-bp146ws6x3iyuwjvbdw2 ap-southeast-1 m-t4ng1w8ipua3c0o57hor
导出 CAA 容器镜像路径
定义要部署的 Cloud API Adaptor(CAA)容器镜像。 这些变量指定了部署工具所要拉取和运行的 CAA 镜像及其架构专属 tag。 tag 与 CAA 发布版本对应,以确保与所选 PodVM 镜像和配置兼容。
导出以下环境变量以使用 CAA 最新发布镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
export CAA_TAG="v${CAA_VERSION}-amd64"
导出以下环境变量,以使用每次合并到 main 后由 CAA CI 构建的镜像:
export CAA_IMAGE="quay.io/confidential-containers/cloud-api-adaptor"
你可以在这里找到适合需求的预构建镜像 tag。
export CAA_TAG=""
注意: 你也可以使用
latesttag,但不推荐这样做,因为它缺少版本控制,可能引入不可预期的更新,影响部署稳定性和可复现性。
如果你修改了 CAA 代码并希望部署这些改动,请按说明构建容器镜像。镜像构建完成后,导出环境变量 CAA_IMAGE 和 CAA_TAG。
选择 peer-pods 机型
export PODVM_INSTANCE_TYPE="ecs.g8i.xlarge"
export DISABLECVM="false"
说明: 更多支持机密计算的实例规格,请参考官方文档。
填充 providers/alibabacloud.yaml 文件
全部可用配置项可在以下两个位置找到:
运行以下命令更新 providers/alibabacloud.yaml 文件:
cat <<EOF > providers/alibabacloud.yaml
provider: alibabacloud
image:
name: "${CAA_IMAGE}"
tag: "${CAA_TAG}"
providerConfigs:
alibabacloud:
IMAGEID: "${IMAGEID}"
REGION: "${REGION_ID}"
SECURITY_GROUP_IDS: "${SECURITY_GROUP_ID}"
VSWITCH_ID: "${VSWITCH_ID}"
DISABLECVM: ${DISABLECVM}
alibabacloud:
rrsa:
enable: true
EOF
说明: 如果你不使用 RRSA 进行认证,请将 yaml 中的
alibabacloud.rrsa.enable改为false。
在 Kubernetes 集群中部署 Helm Chart
-
创建由 Helm 管理的命名空间:
kubectl apply -f - << EOF apiVersion: v1 kind: Namespace metadata: name: confidential-containers-system labels: app.kubernetes.io/managed-by: Helm annotations: meta.helm.sh/release-name: peerpods meta.helm.sh/release-namespace: confidential-containers-system EOF -
使用
kubectl创建 Secret:所需 key 请参见 providers/alibabacloud-secrets.yaml.template。
说明: 以下示例假定你使用 RRSA 进行认证,因此不需要提供
ALIBABACLOUD_ACCESS_KEY_ID和ALIBABACLOUD_ACCESS_KEY_SECRET,而是提供ALIBABA_CLOUD_ROLE_ARN和ALIBABA_CLOUD_OIDC_PROVIDER_ARN。kubectl create secret generic my-provider-creds \ -n confidential-containers-system \ --from-literal=ALIBABA_CLOUD_ROLE_ARN=${ALIBABA_CLOUD_ROLE_ARN} \ --from-literal=ALIBABA_CLOUD_OIDC_PROVIDER_ARN=${ALIBABA_CLOUD_OIDC_PROVIDER_ARN} \ --from-literal=ALIBABA_CLOUD_OIDC_TOKEN_FILE=/var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token -
安装 Helm Chart:
下面命令使用了
-f和--set这两个自定义选项,其含义可参考这里。helm install peerpods . \ -f providers/alibabacloud.yaml \ --set secrets.mode=reference \ --set secrets.existingSecretName=my-provider-creds \ --dependency-update \ -n confidential-containers-system
通用的 Peer Pods Helm Chart 部署说明也可参考这里。
运行示例应用
确认 runtimeclass 已创建
部署 CAA 后,请确认 runtimeclass 已创建:
kubectl get runtimeclass
当你看到名为 kata-remote 的 RuntimeClass 时,就说明部署成功。成功输出类似如下:
$ kubectl get runtimeclass
NAME HANDLER AGE
kata-remote kata-remote 7m18s
部署工作负载
创建一个 nginx deployment:
echo '
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
runtimeClassName: kata-remote
containers:
- name: nginx
image: registry.openanolis.cn/openanolis/nginx:1.14.1-8.6
' | kubectl apply -f -
确认 pod 已成功启动:
kubectl get pods -n default
你可以通过运行以下命令确认 peer-pod VM 是否已经创建:
aliyun ecs DescribeInstances --RegionId ${REGION_ID} --InstanceName 'podvm-*'
此时你应该能看到与 pod nginx 对应的虚拟机。
如果遇到问题,请查看故障排查指南。
远程证明
TODO
清理
删除所有使用 runtimeClass kata-remote 运行的 Pod。
确认所有 peer-pod VM 都已删除。你可以使用以下命令列出所有 peer-pod VM(名称前缀为 podvm)及其状态:
aliyun ecs DescribeInstances --RegionId ${REGION_ID} --InstanceName 'podvm-*'
运行以下命令删除 ACK 集群:
aliyun cs DELETE /clusters/${CLUSTER_ID} --region ${REGION_ID} --keep_slb false --retain_all_resources false --header "Content-Type=application/json;" --body "{}"