Files
qinglong/docs/adr/ADR-0248-worker-management-pki-rotation-evidence.md
T

5.4 KiB
Raw Blame History

ADR-0248Worker 管理 PKI 吊销与滚动替换证据

  • 状态:Accepted(证据协议、runner、离线审计与部署注解已实现;生产报告待采集)
  • 日期:2026-08-01
  • 关联 RFCQL-RFC-0001 D-229、D-230、D-231、D-232
  • 关联 ADRADR-0245、ADR-0246、ADR-0247
  • 后续修正:客户端证书 issuer 与服务端 TLS trust 的分离由 ADR-0251/v2 取代本 ADR 中“同 endpoint/CA”的表述;v1 不再是兼容发布证据。

背景

ADR-0247 已要求 Worker credential management 在业务路由同时验证客户端证书与 Worker-purpose OIDC 并以更新 CRL 后滚动双副本的方式完成吊销。但“某一旧证书曾成功、随后返回 401”不足以证明生产集群确实 加载了新 CRL:请求可能落到不同环境,Deployment 可能没有换代,旧 Pod 也可能仍存活。另一方面,让证据 采集器读取 TLS Secret 或自行 patch Deployment,会把观察者升级为 PKI/部署变更者,失去独立证明价值。

决策

  1. 使用 caller-driven、两阶段、只读观察协议。before 证明旧证书与替代证书在同一 endpoint、CA、命令和 Worker-purpose User assertion 下均返回 200after 证明旧证书统一返回 401 client_certificate_required、替代证书仍返回 200。
  2. 两阶段之间只能由协议外的生产 PKI/Deployment operator 更新 CRL、计算原始 CRL 文件 SHA-256、把该摘要 写入 Pod template 注解 qinglong.io/worker-credential-management-client-crl-sha256,再完成 maxUnavailable=0 rollout。证据 collector 不提供 mutate 子命令。
  3. Kubernetes collector 身份只允许 get 指定 Deployment 与 list 带固定 selector 的 Pod;必须明确证明 Secret get/list、ConfigMap get、Deployment list、Deployment/Secret/Pod create/update/patch/delete、 Pod exec/port-forward 与 ServiceAccount TokenRequest 均被拒绝。
  4. 每个阶段要求 Deployment observed generation 收敛、两副本 Ready、无 ServiceAccount token、位于两个不同 Node。after 还要求同一 Deployment UID、generation 增加、resourceVersion 改变、CRL 注解改变且等于当前 CRL 摘要,以及两个旧 Pod UID 全部消失。
  5. CRL 必须由 OpenSSL 验证并提取 issuer、number、lastUpdate、nextUpdateafter 必须保持同一 issuer CRL number 与 lastUpdate 单调增加,且 CRL 当前有效。
  6. 最终报告必须摘要绑定 before-state、ADR-0245 external ceremony report 与 ADR-0246 durable audit report 当前操作者必须是 ceremony 的 requester 或 reviewer,并在 durable report 中存在相同摘要身份。
  7. 报告只保存域分离 SHA-256、generation、HTTP 状态和布尔 gate。禁止证书、私钥、JWT、Kubernetes token、 Pod/Node/Deployment 原始标识、Secret 内容和 DSN。before-state 与报告均以 no-replace 0600 文件写入并由 独立 exact-shape auditor 验证。
  8. 该协议只增加短生命周期脚本、测试、文档和 Pod template 注解;不增加 workspace package、第三方依赖、 migration、controller、watcher、timer、sidecar、listener、Pool 或连接。Edge/Standalone/Worker 零稳态成本。

失败与恢复

  • before 写出后若 operator 尚未完成吊销,保留该 state,修正变更后再执行一次新的 after 输出路径;
  • CRL 未递增、注解与文件摘要不一致、rollout 未收敛、任一旧 Pod 仍存在或 collector 权限变宽均失败关闭, 且不会写最终报告;
  • after 的旧证书请求若超时、返回 200 或返回其他业务错误,不能解释为已吊销;替代证书非 200 也不能通过;
  • runner 不执行回滚。生产 operator 必须按自身 PKI 记录判断修复或回滚,并重新从新的 before-state 开始;
  • 报告只证明观察窗口内的联合事实,不替代 CA 私钥 custody、CRL 发布 SLO、证书库存或 ingress 日志。

被拒绝的替代方案

让 collector 读取或更新 Secret

拒绝。Secret read 会把证书/私钥/CRL custody 扩大给证据身份;Secret/Deployment write 又使同一主体既变更又 证明,无法形成独立控制。

只记录 rollout status 或 Pod 名称

拒绝。rollout status 不能证明旧 Pod UID 全部退役,也不能绑定当前 CRL 字节;Pod 名称既可能复用又会泄漏 基础设施标识。协议使用 UID 的域分离摘要与 CRL 原始字节摘要。

在 manager 中加入 CRL watcher 和证据端点

拒绝。watcher 会引入混合 TLS context、常驻资源和低配 Profile 供应链成本;自证端点由被测进程声明自身状态, 也弱于外部 read-only Kubernetes 观察和真实请求结果。

验证

  • runner/auditor 定向测试覆盖两阶段成功、CRL number 不递增、generation 未改变、旧 Pod 未完全替换、Secret 读取权限被放宽、false gate、widened shape、敏感字段和 CLI exact arguments
  • deployment audit 锁定提交态的全零注解占位符,要求生产私有 overlay 显式替换;
  • D-232 不新增 package 或依赖,复用既有 Cluster Admin production client、D-229 ceremony validator 与 D-230 durable audit validator
  • PostgreSQL 18.4 arm64 HA 重跑完成 remote_apply、timeline 1→2、旧主 fencing、pg_rewind 只读重入、 双 fresh control replicas、Worker management quota/keyset ledger 与总 gateql3-ha- Docker 资源零残留;
  • 真实生产 PKI、external IdP、ingress 与多节点集群联合报告仍是发布门。