Kubernetes v1.37:用 Pod Certificates 和 Cluster Trust Bundles 构建原生工作负载身份

2026-08-29 33 预计阅读时间: 1 分钟
来源: kubernetes.io AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:11 分钟

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 投影相似,但签发机制更加可插拔。一次典型流程包含三个角色:

  1. 应用在 Pod spec 中声明 podCertificateclusterTrustBundle 投影卷。
  2. Pod 被调度后,Kubelet 为每个证书投影生成私钥,并创建 PodCertificateRequest
  3. 指定的 signer controller 校验请求并填写证书链。
  4. Kubelet 将私钥与证书链写入容器文件系统。
  5. Kubelet 根据 signer 名称和标签选择匹配的 ClusterTrustBundle,合并其中的信任锚并写入文件。
  6. 应用读取这些文件,配置 TLS 或 mTLS。
  7. 证书接近刷新时间时,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 或零信任接入的团队,这是值得在测试集群中尽早验证的一项基础能力。


相关推荐