mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
6.1 KiB
6.1 KiB
ADR-0245:Worker 管理外部 OIDC 双用户 Ceremony 证据
- 状态:Accepted(证据协议、runner 与离线审计器已实现;真实外部报告待采集)
- 日期:2026-08-01
- 关联 RFC:QL-RFC-0001 D-58、D-226、D-228、D-229
- 关联 ADR:ADR-0148、ADR-0242、ADR-0244
背景
ADR-0244 已让 Worker Credential management 使用独立 JWT type/purpose,并由进程级、 PostgreSQL HA 和三节点 K3s fixture 证明生产装配。但 K3s fixture 的两名强 User assertion 由仓库内 确定性密钥签发,不能证明真实外部 IdP、真实不同人员或生产身份策略。
直接把原始 assertion、subject、session ID 或管理响应存为“证据”会扩大凭据与个人身份数据暴露; 直接执行 credential delivery 又会把身份验证与 Secret mutation 混成一个不可独立复核的门。
决策
- 新增 caller-driven
ql3-worker-credential-management-live-ceremony.cjs。它只允许固定顺序: requesterplan→ requesterpropose→ requesterdecide必须 403 → reviewerdecide→ reviewerinspect。runner 不接受 operation 参数,也没有execute、TokenRequest 或 delivery 路径。 - requester/reviewer assertion 必须来自同一个 canonical 外部 HTTPS issuer、拥有不同 User subject,
并精确绑定:
aud=qinglong3-worker-credential-management;typ=ql3-worker-credential-management+jwt;ql3_purpose=worker-credential-management;- 有界 lifetime/authentication age、非
nonealgorithm、canonical compact encoding。
- runner 在任何管理 mutation 前读取 OIDC discovery/JWKS,并复用生产 Worker management client 的 TLS 1.3、CA/servername、canonical file、body/response/timeout 与 exact result validation。manager 对两枚 assertion 的真实签名、keyset、assurance 和 Policy 验证仍是最终认证 authority;runner 的 envelope 检查不是签名验证替代品。
- ceremony 输入是 mode 0600 的 exact-shape 文件。所有 identifier 与 plan request 在首个网络请求前
通过 production transport normalizer;requester/reviewer decision identity 必须不同。只接受新建
pending@1approval,避免把已有决定误写为本次现场证据。 - 输出使用
qinglong/worker-credential-management-live-ceremony@v1,写入 unused canonical mode 0600 文件。只保留外部 issuer、discovery/JWKS SHA-256、domain-separated subject/key/request/project/ action 摘要、plan/preview digest、五步状态和dispatchCreated=false、approvalConsumed=false;禁止 assertion、JWT、Authorization、Secret、token、DSN、password 或私钥。 - 独立 audit CLI 只读验证 exact report shape、外部 issuer、Worker profile、不同 subject digest、 五步状态、未 dispatch/consume、全 true gate 与敏感材料扫描。runner 自审通过后才原子 no-replace 写报告;没有真实报告时发布门仍未完成。
- 该能力只增加两个短生命周期脚本和一个根级命令,不新增 workspace package、第三方依赖、 migration、数据库角色、镜像、listener、timer、watcher、controller 或 sidecar。Edge/Standalone/ Worker 常驻闭包不导入它。
失败与恢复
- OIDC discovery/JWKS、TLS、认证、self-deny、reviewer decision 或 inspect 任一步失败都不生成报告;
plan/propose已 durable 后失败时,operator 必须先 inspect。若 approval 仍为pending@1,可用同一 immutable ceremony 继续;若已决定,则本 runner 拒绝把它包装为新现场证据,应创建新的无执行 ceremony identity;- 主请求不做业务自动重试。生产 client 的无响应语义仍要求 durable inspection;缺少响应不能解释为 rollback;
- 输出路径不可覆盖,防止把两次不同现场证据混为一份报告。
被拒绝的替代方案
把 K3s 自签 token 标为外部 IdP
拒绝。它只能证明协议与部署 wiring,不能证明外部 issuer、人员分离或生产 IdP policy。
接受一个 assertion 并在客户端改 subject
拒绝。subject 是 issuer 签名事实;客户端改写既不能通过签名,也不能证明两名人员。
Ceremony 顺便 consume approval 或执行 delivery
拒绝。身份/职责分离证据不应产生 Worker credential、Kubernetes token 或 Secret mutation。执行证据由 ADR-0242 的独立 caller-driven executor gate 负责。
将原始 subject、JTI、request ID 或 assertion 写入报告
拒绝。这些值对离线合规判断没有必要,且会扩大个人信息、会话关联和 credential 泄漏面。域分离 摘要足以证明同份报告内部的不同身份与请求链。
验证
- runner/audit 7/7:外部双 User happy path、自批被错误接受时失败关闭、same-user、错误 purpose、
.testissuer、过期/Plugin-type assertion、宽权限/symlink/已存在输出文件、widened/false-gate/敏感 报告、五个 path-only CLI 参数;私有读取使用O_NOFOLLOW与 descriptor 前后 stat; - happy path 明确观测五个 operation,零
worker-credential.execute,输出 mode 0600,并由独立 audit 子进程再次判定compatible=true; - production client/transport 的 Cluster Admin 全量回归为 177 pass、0 fail、1 条真实 Kubernetes API 条件 skip,继续覆盖 TLS 1.3、远端错误、exact response 和四个公开 operation;
- 根 back/legacy 全量回归为 881 pass、0 fail、2 条平台条件 skip;dependency、deployment、Edge
audit 均
compatible=true、findings=[],workspace importer 保持 19。
尚未完成
- 在真实外部 IdP 与生产等价 manager endpoint 上采集一份 mode 0600 report,并由 audit CLI 通过;
- 按 ADR-0246 用部署侧短期、exact SELECT-only PostgreSQL evidence role 采集 proposal/decision durable security audit;collector/audit 协议已实现,真实报告仍待采集;
- 外部 client certificate 的运行时/客户端/Kubernetes 协议已由 ADR-0247 补齐;生产 PKI、生产 ingress、 证书或 IdP 身份撤销后的新请求失败关闭仍需现场证据,不能由本报告推导。