Kubernetes v1.37 将 Pod Certificates 与 Cluster Trust Bundles 的基础能力带入 GA,为工作负载提供了一条内置的 X.509 身份路径。过去,Service Account JWT 一直是 Kubernetes 工作负载身份的主力;现在,应用可以在 Pod 中请求证书、获得信任锚,并使用 TLS 或 mTLS 与其他服务通信。
这不是简单地把 JWT 换成另一种文件格式。JWT 属于 bearer token:拿到令牌的一方通常就能代表该身份发起请求。X.509 证书则可以与只保留在工作负载内的私钥配合,通信时证明“我拥有对应私钥”,从而降低凭据被复制后的风险。
为什么工作负载需要 X.509 身份
Service Account JWT 的优点非常明显:它由控制面签发,Kubelet 自动写入容器文件系统并负责更新,还可以绑定时间、对象和 audience。云厂商的工作负载身份联邦,以及大量支持 JWT 的软件,都建立在这套机制之上。
但 JWT 的核心问题是 bearer 属性。应用为了调用对端,往往需要把 JWT 交给对端或中间组件;一旦令牌副本泄露,攻击者可能在有效期内直接冒充该工作负载。时间限制和 audience 限制能够缩小影响范围,却不能彻底改变“持有令牌即可使用身份”的模型。
X.509 采用了不同的凭据拆分方式:
- 私钥由工作负载侧生成,理想情况下不离开工作负载,甚至可以由硬件安全模块生成。
- 证书包含身份和公钥,并由 CA 签名。
- TLS 或 mTLS 握手使用私钥完成签名,通信对端不需要拿到私钥。
因此,Pod Certificates 更适合需要双向身份验证、服务间 mTLS 或现有 PKI 集成的场景。它不会让 JWT 失去价值:云身份联邦和大量外部系统仍然需要 JWT,实际集群很可能会长期同时使用两种身份机制。
一次证书投影是怎样完成的
Pod Certificates 的设计思路与 Service Account Token 投影相似,但签发机制更加可插拔。一次典型流程包含三个角色:
- 应用在 Pod spec 中声明
podCertificate和clusterTrustBundle投影卷。 - Pod 被调度后,Kubelet 为每个证书投影生成私钥,并创建
PodCertificateRequest。 - 指定的 signer controller 校验请求并填写证书链。
- Kubelet 将私钥与证书链写入容器文件系统。
- Kubelet 根据 signer 名称和标签选择匹配的
ClusterTrustBundle,合并其中的信任锚并写入文件。 - 应用读取这些文件,配置 TLS 或 mTLS。
- 证书接近刷新时间时,Kubelet 自动重新申请并替换文件。
这里有一个关键边界:Kubelet 负责密钥生成、请求转发、文件投影和刷新,但它本身不是签发者。signer controller 决定是否签发、证书包含什么身份以及信任包如何发布。一个集群可以同时部署多种 signer,例如面向 Kubernetes Service DNS 名称的服务端证书 signer,以及面向 SPIFFE 身份的客户端证书 signer。
一个可改造的 Pod 示例
Kubernetes 核心目前不提供完整的内置 Pod Certificate signer,因此下面的 YAML 假设集群中已经安装了一个实验性 signer,并且它使用 ahmedtd.github.io/tinycert-spiffe 这个 signer 名称。运行前,请将 signerName 改成你实际部署的 signer 名称,并确认该 signer 会发布对应的 ClusterTrustBundle。
apiVersion: v1
kind: Pod
metadata:
name: mtls-demo
namespace: default
spec:
serviceAccountName: default
containers:
- name: app
image: busybox:1.36
command: ["sh", "-c"]
args:
- |
echo "waiting for projected credentials"
while true; do
echo "--- $(date) ---"
ls -l /var/run/pod-identity
test -s /var/run/pod-identity/credential.pem && \
sed -n '1p' /var/run/pod-identity/credential.pem || true
test -s /var/run/pod-identity/ca-bundle.pem && \
sed -n '1p' /var/run/pod-identity/ca-bundle.pem || true
sleep 30
done
volumeMounts:
- name: pod-identity
mountPath: /var/run/pod-identity
readOnly: true
volumes:
- name: pod-identity
projected:
sources:
- podCertificate:
signerName: ahmedtd.github.io/tinycert-spiffe
keyType: ECDSA
credentialBundlePath: credential.pem
- clusterTrustBundle:
signerName: ahmedtd.github.io/tinycert-spiffe
path: ca-bundle.pem
可以这样应用和观察:
kubectl apply -f pod-cert-demo.yaml
kubectl get pod mtls-demo -w
kubectl exec mtls-demo -- sh -c \
'ls -l /var/run/pod-identity && head -n 3 /var/run/pod-identity/credential.pem'
credentialBundlePath 的目的,是让 Kubelet 把私钥和证书链放在一个可整体替换的文件中。应用只需要监听这一个文件,就能减少轮换期间分别读取私钥和证书时的竞态风险。若选择把私钥和证书链写入不同文件,应用必须处理“刚读完私钥、证书已经被替换”之类的不一致情况。
上面的 busybox 只用于验证文件投影,不能执行 TLS。生产应用需要使用语言运行时加载 PEM 文件,并在文件发生变化时重新构造 TLS 配置。例如,Go 服务通常可以通过轮询文件修改时间或监听 inotify 事件,在证书更新后替换 tls.Config 中的证书;Java、Python 和其他运行时也需要采用各自的热加载方式。
轮换不是可选功能
Pod Certificate 的自动轮换由 Kubelet 触发,但应用是否真正使用新证书,取决于应用能否重新加载文件。典型做法有两种:
- 监听文件系统事件,在收到替换事件后重新读取凭据。
- 按固定间隔轮询文件的修改时间或内容。
不要在进程启动时只读取一次证书,然后永久复用内存中的 TLS 配置。根据摘要中的设计,核心 Kubernetes 未来提供的 signer 证书最长有效期会控制在 24 小时以内;其他 signer 允许的最长有效期为 91 天。短有效期有助于缩短泄露后的可用窗口,但也要求应用和监控系统正确处理轮换失败。
建议至少监控以下情况:
- 凭据文件是否在预期时间内首次出现。
- 证书剩余有效期是否持续下降却没有更新。
- signer 是否持续返回拒绝或错误。
- 应用重新加载证书后,mTLS 握手是否恢复成功。
Cluster Trust Bundles 解决什么问题
仅有客户端证书还不够。应用还必须知道应该信任哪些 CA,才能验证对端证书。Cluster Trust Bundles 提供了由 Kubernetes 对象承载的信任锚集合,Kubelet 会根据 signer 名称和标签选择器收集匹配对象,合并证书后投影到 Pod 文件系统。
Kubelet 会稳定地重新排序合并后的证书,避免应用依赖某个对象或某种返回顺序。信任包内容变化时,文件也会更新,因此应用同样必须具备动态重新加载能力。
这带来一个实用的解耦关系:证书 signer 可以发布新的 CA 或轮换信任锚,而应用只消费投影文件,不必直接查询 Kubernetes API,也不必把 CA 内容硬编码到镜像中。
安全边界与落地建议
Pod Certificates 的安全性不只依赖 signer。尽可能多的校验由 kube-apiserver 的通用机制完成,例如内置的节点限制准入插件可以确保节点只能为当前实际运行的 Pod 请求证书,降低被攻陷节点横向获取其他 Pod 身份的风险。
部署时可以按下面的清单检查:
- 确认 Kubernetes 版本和目标发行版已启用 Pod Certificate、Cluster Trust Bundle 相关能力。
- 为每类用途选择明确的 signer 名称,不要让一个宽权限 signer 给所有命名空间签发任意身份。
- 让 signer 校验命名空间、ServiceAccount、Pod 所属关系和请求者权限。
- 私钥使用 Kubelet 生成的密钥,不要把私钥写入 ConfigMap、镜像或 Git 仓库。
- 优先使用单文件 credential bundle,降低证书轮换时的读取竞态。
- 在应用中实现证书和信任包热加载,并为加载失败设置明确的告警。
- 在测试环境验证 CA 轮换、Pod 重启、节点迁移以及 signer 不可用时的行为。
Pod Certificates 不会自动完成整个 PKI 体系。你仍然需要决定 signer 的身份模型、CA 生命周期、授权策略、审计方式和应用侧的 TLS 配置。但 Kubernetes v1.37 已经把最繁琐的工作负载接入部分——密钥生成、请求传递、文件投影和自动刷新——纳入了统一机制。对于正在推进服务间 mTLS、SPIFFE 或零信任接入的团队,这是值得在测试集群中尽早验证的一项基础能力。