Files
qinglong/docs/adr/ADR-0244-purpose-bound-management-identity-assertions.md

6.3 KiB
Raw Permalink Blame History

ADR-0244:按管理能力绑定身份断言用途

  • 状态:Accepted
  • 日期:2026-08-01
  • 关联 RFCQL-RFC-0001 D-58、D-85、D-175、D-226、D-228
  • 关联 ADRADR-0148、ADR-0242、ADR-0243
  • 修正:Worker Credential 管理身份曾复用 Plugin Package 的 JWT typql3_purpose

背景

Plugin Package 管理与 Worker Credential 管理已经拥有不同的 HTTPS 路径、PostgreSQL 角色、durable quota/identity ledger authority 和 JWT audience。Worker manager 进程却仍通过 Plugin Package keyset factory 的默认值校验:

  • typ=ql3-plugin-package-management+jwt
  • ql3_purpose=plugin-package-management

不同 audience 已阻止两条 token 直接互换,因此这不是一个已证明可利用的跨能力授权漏洞;但它使 断言自描述用途与实际 authority 不一致,要求外部 IdP 为 Worker 操作签发带 Plugin 语义的 token, 也让未来配置或审计错误更难被发现。仅靠 audience 区分两条高风险管理链不是 QingLong 3.0 应保留 的边界。

决策

  1. 管理身份验证器接受一个严格、启动时审查的 assertion profile。profile 只含 typepurpose,对象必须 exact-shapetype 只接受 ql3-<capability>+jwtpurpose 只接受规范化 kebab-case,禁止任意 JWT 类型、控制字符、空白或大小写漂移。
  2. Plugin Package profile 保持: ql3-plugin-package-management+jwt / plugin-package-management。省略 profile 时仍使用该值, 使既有 Plugin caller 的语义不变。
  3. Worker Credential profile 固定为: ql3-worker-credential-management+jwt / worker-credential-management。Worker 进程只通过 createClusterWorkerCredentialIdentityKeysetFile 装配该 profile,调用方不能覆盖它。
  4. 一条管理断言必须同时匹配 issuer、audience、JWT typql3_purpose、签名、生命周期与 assurance mapping。三类能力标识中的任一项不一致都返回同一低敏认证失败,不提供探测细节。
  5. keyset generation、digest、撤销集合与 PostgreSQL durable ledger 协议不变。此决策不新增 package、第三方依赖、migration、数据库角色、listener、Pool、timer、watcher、controller 或 sidecarEdge/Standalone 不装配该能力,路由设备的安装闭包与常驻资源保持不变。
  6. Kubernetes Worker management live fixture 必须生成 Worker 专属 typ/purpose。外部 IdP ceremony 在正式接受前还必须证明两名不同强 User 的 Worker-purpose token、申请者自批拒绝、reviewer 批准与撤销后的失败关闭;仓库内自签 fixture 不冒充该证据。

被拒绝的替代方案

只依赖 audience

拒绝。audience 是必要条件,但不能让 token 自描述它正在请求哪一种管理 authority;多入口共享 issuer/keyset 时,显式 typ 与 purpose 能把错误配置在认证边界失败关闭。

继续复用 Plugin purpose,并只在文档中解释

拒绝。它要求 IdP 签发语义错误的 token,日志、策略和撤销规则都无法准确表达 Worker 能力;文档 不能修复运行时 contract。

为 Worker 身份再建 workspace package 或独立常驻身份服务

拒绝。两条链共享相同的有界 keyset、签名、lifetime、assurance 和 durable rotation 协议,差异是 编译时 profile 与部署 authority。包内显式 factory 已能隔离语义;新 importer/daemon 只会增加 低配设备的安装、SBOM、内存、连接和运维成本。

让部署配置任意覆盖 Worker profile

拒绝。Worker caller 的用途是产品协议而非部署偏好。允许环境变量覆盖会把 confused-purpose 风险 移给每个部署者,并可能使副本间产生不一致认证语义。

影响

  • 现有 Plugin Package token 与 keyset 不变;
  • Worker IdP/client 必须改为签发 Worker 专属 typ/purpose,旧的 Plugin-purpose Worker token 会在 认证阶段失败;
  • Worker keyset 的 issuer、audience、JWK、assurance mapping 与 rotation 流程不变;
  • 共享实现仍位于既有 cluster-admin package 内,不增加 workspace importer
  • 此变更是有意的 3.0 alpha protocol correction,不提供接受旧 Worker token 的兼容窗口。

验证

  1. verifier 单元测试证明 Plugin 与 Worker profile 分离;即使 issuer、key、audience 相同,两种 token 仍不能互换,并拒绝非规范 profile;
  2. keyset 测试证明 Worker factory 接受 Worker token、拒绝同 audience 的 Plugin-purpose token
  3. 默认 Worker manager 进程以真实 Ed25519 keyset 和 PostgreSQL ledger 交互桩装配,证明生产 caller 选择 Worker factory,而不只是测试直接调用 verifier;定向 21/21 通过;
  4. cluster-admin 完整测试为 177 pass、0 fail、1 条无真实 Kubernetes API 时的条件 skip
  5. PostgreSQL 18.4 arm64 physical-HA Docker 门再次通过:Worker quota 与 identity ledger 跨实例、 重启和 promotion 收敛,remote_apply、timeline 1→2、旧主 fence、pg_rewind 只读同步重入与 fresh control replicas 均为 true,最终 gates.passed=true;门退出后 ql3-ha Docker 资源为 0
  6. GitNexus 对当前已索引 tracked diff 报告 LOW、0 affected processQL3 新文件尚未完整进入索引, 因此该结果不替代上述进程级、全包与真实 HA 证据;
  7. 固定 v1.34.3+k3s1 arm64 三节点 K3s live gate 已用新 profile 完成两个跨节点 manager Pod、TLS 1.3 client、8 admitted/8 limited、identity generation 1→2→3 overlap/revoke、rollback surge 失败关闭、数据库故障 availability fence、fresh activation 双副本恢复与一次性 client Job, 最终 gates.passed=true;退出后 ql3-wcm Docker 容器、网络、卷和临时镜像均为 0。fixture 仍使用仓库内确定性强 User 断言,不冒充外部 IdP 证据。

后续门禁

  • ADR-0245 已增加外部 OIDC 两用户 ceremony 协议、runner 与离线审计器;仍需在真实外部 IdP 上 采集报告。requester plan/propose、自批失败、reviewer approve/inspect 均不得让 assertion、原始 subject/session 标识进入低敏结果或 durable plan
  • 将 identity 共享实现中历史性的 Plugin 命名作为单独重构评审项;只有能减少错误类型/公共 surface 且不制造兼容 facade 或新 package 时才执行。