# ADR-0242:受批 Worker Credential 管理与一次性执行边界 - 状态:Proposed - 日期:2026-08-01 - 关联 RFC:QL-RFC-0001 D-23、D-58、D-175、D-207、D-224、D-225、D-226 - 关联 ADR:ADR-0141、ADR-0142、ADR-0185、ADR-0217、ADR-0234、ADR-0240、ADR-0241 - 承接:ADR-0241 尚未完成的强 User、双人批准与 TokenRequest session 产品组合 ## 背景 ADR-0241 已把 Kubernetes delivery capability 收敛为 callback-scoped、内存中的一次性 TokenRequest session,但它只解决“已获得执行授权后如何安全签发和销毁 token”。如果产品入口 直接让调用者构造 delivery 参数,仍会缺少三个关键事实:谁申请、批准的精确目标是什么、执行时 是否仍与批准内容和 Project authority 一致。 该问题也不能通过新增一组细粒度 workspace package 或常驻 credential controller 解决。 QingLong 同时面向低配路由设备与集群节点:前者不应安装 PostgreSQL/Kubernetes SDK、连接池和 后台轮换循环;后者则必须把可被网络调用的管理 authority 与持有 Kubernetes delivery capability 的执行 authority 分开。 ## 决策 ### 1. 产品链固定为四段持久事实 Cluster Worker credential 的 `issue|rotate` 固定执行: 1. 强 User principal 在 Authority Project 内通过 `worker.manage`,创建最长 15 分钟、不可变且 不含 token/Secret/kubeconfig 的 management plan; 2. 同一申请者基于 plan digest 发起 `high` risk、`separation_of_duty` ApprovalRequest; 3. 另一名具有 `approval.decide` 的强 User 对 exact action/plan/preview digest 作出决定; 4. caller-driven executor 重新读取 plan/approval/Project fence,原子 consume approval 并取得 durable dispatch 后,才进入一次性 TokenRequest session 和可恢复 delivery issuer。 approval、dispatch、credential mutation 与 delivery 都使用稳定 identity 和 exact replay。token 只存在于 session callback 内,不能进入 plan、approval、PostgreSQL、结果、日志或审计事件。 ### 2. Manager 与 Executor 使用不同数据库角色 `ql3_worker_credential_manager` 只读 Project/RoleBinding/schema facts,可创建 plan、 ApprovalRequest 和 Audit;它不得读写 credential、delivery、stage discard 或 dispatch。 `ql3_worker_credential_executor` 只读 plan 与 Project authority,可 consume ApprovalRequest、追加 dispatch/credential/mutation/delivery/stage-discard/Audit;它不能创建或改写 plan,也不能取得其他 runtime、Package 或 migration authority。两个角色都不是 superuser、owner、createdb、createrole、 replication 或 bypassrls;每个部署连接上限为 4,并只执行 approval policy fence function。 迁移 `pg-0047` 建立 immutable plan 与上述 grant,`control-core` 推进到 v46;`pg-0048` 只调整 credential lifetime check,使批准时刻早于实际创建时刻仍可执行,同时要求 expiry 晚于 `GREATEST(createdAt, notBefore)`,并推进到 v47;`pg-0049` 把 durable execution receipt 的 SELECT/INSERT/UPDATE 仅授予 executor 并推进到 v48;`pg-0050` 再建立使用数据库时钟、 exact replay receipt 的 manager quota bucket,把共享 identity keyset ledger 的 authority 严格扩展为 Plugin Package/Worker Credential 两值,并仅给 Worker manager 相应读写权限,推进到 v49。历史迁移 不原地改写。 共享 `approved_action_executions` 表的 dispatcher 必须把自身注册 handler 的 action types 下推到 repository 查询。没有匹配 handler 的 executor 不得领取、租约或 block 其他 authority 的动作。 ### 3. 批准时间与执行时间必须分离 plan 固定批准的 `credentialNotBeforeAtMs` 与 `credentialExpiresAtMs`。执行因人工审批延迟时, 不得把 not-before 改成当前时间,否则批准摘要失效;也不得创建已经到期的 credential。执行端 要求当前时间仍早于 plan、dispatch 和 credential expiry,再按批准的原始时间签发。rotation 还必须确认 predecessor 是同一 Worker 当前有效 credential。 ### 4. 不按源码文件拆 workspace package 本能力分别落在既有 package 的显式 subpath: - `runtime-core/worker-credential-management-plan`:Profile-neutral plan contract; - `cluster-postgres/worker-credential-manager`:manager-only repository/readiness; - `cluster-postgres/worker-credential-executor`:executor-only repository/readiness; - `cluster-admin/worker-credential-management`:强 User 管理 facade; - `cluster-admin/worker-credential-management-executor`:一次性执行组合。 它们不是新的发布、部署或 dependency root,因此不建立单文件 package。只有出现独立制品、独立 第三方重依赖、必须从常驻闭包排除的 authority,或三个以上 package 需要稳定依赖反转时,才允许 重新评审 package 边界。 ### 5. Edge/Standalone 与 Cluster 不共担部署成本 Edge/Standalone 不导入上述 PostgreSQL/Kubernetes 管理 subpath,不创建这两个角色、连接池、 TokenRequest client、timer 或常驻进程;本机身份和 credential ceremony 继续由短生命周期 Owner CLI 与 SQLite authority 完成。路由设备运行 Worker 时仍使用同一受预算约束的 Worker runtime, 但 Cluster 管理 SDK 不进入其制品闭包。 Cluster 可提供独立认证后的 manager transport,但 executor 必须保持一次一命令/一次 Job 的 caller-driven 生命周期:打开至多一个受限数据库资源,consume durable approval,创建一次 TokenRequest session,执行或重放 delivery,然后销毁 Kubernetes client 并关闭数据库。不得把 executor 变为常驻 controller、轮换 timer、watcher、leader election 或 sidecar。 ## 不采用方案 ### 把 manager 与 executor 合成一个 admin role/process 拒绝。网络管理入口一旦被利用,就会同时获得 approval 创建和 Kubernetes delivery capability, separation-of-duty 只剩应用层约定,无法由数据库 grant 和部署凭据证明。 ### 每个 plan/repository/service 新建一个 package 拒绝。这些模块没有独立部署、发布或第三方依赖边界,会增加 importer、lock、SBOM、build 和升级 成本,却不能进一步缩小运行时 authority;显式 subpath 已能提供需要的可见性和审计门。 ### 常驻 controller 自动签发和轮换 拒绝。它会长期持有 issuer、delivery 与数据库 authority,并增加 timer、重试、leader 和连接 生命周期;低配设备不需要这套成本,Cluster 的低频高风险操作也更适合显式受批执行。 ### 批准后把 not-before 重写为执行时间 拒绝。它会改变已批准 plan 的语义与 digest;若不重写 digest 就是越权,若重写 digest 则必须 重新审批。正确做法是保留批准时间并验证执行时尚未过期。 ## 影响 - CloudNativePG 数据库角色由六个增至八个,新增两个离散 credential Secret 示例; - workspace package 数不增加,Edge/Standalone production closure 不增加 Cluster 依赖; - Cluster Admin 在同一 package 内增加 management transport/HTTP/client/process 显式 subpath、 manager/client/executor CLI binary、opt-in 双副本 Kubernetes Deployment 与 caller-driven Job; 不增加 workspace package。 manager process 使用独立 Worker manager Pool、durable quota 与 authority-scoped identity ledger, 不取得 executor、Kubernetes API、Secret 或 pepper authority;executor Job 只取得显式 600 秒 issuer token、exact delivery ServiceAccount 的 TokenRequest 和 executor PostgreSQL role; - 运维工作站通过独立 opt-in management client Job 发起单条命令;该 Job 无 RBAC/API token, 只把不可变 request、短期强 User assertion 与受审 CA 分离投影,预检仅重试 TLS 1.3 `/readyz`,生产 client 主进程不自动重试业务请求; - executor 在 approval consume 后失败时保留 durable dispatch,后续以同一 identity 恢复,不重新 请求人工批准,也不重签不同语义的计划; - executor 对 execution baseline 执行 claim→start→complete;成功回执精确绑定 delivery identity 与 publication digest,重放只读 durable delivery,不再次进入 TokenRequest session; - plan 与 PostgreSQL 只持目标、摘要、时间和低敏证据,不持 bearer token。 ## 验证 当前实现证据: 1. manager/executor PostgreSQL readiness 正向与越权负向测试通过,两个 package entrypoint 的 capability 集合互斥; 2. management 的 plan/propose/decide/inspect happy path 已覆盖强 User、Project `worker.manage`/`approval.decide`、双人决定、immutable exact replay 与配置收窄; 3. runtime/admin/delivery 已覆盖审批延迟后仍按原 not-before 创建、已过期拒绝与 delivery recovery; 4. PostgreSQL migration/schema/manifest 全量测试通过,`pg-0047`/`pg-0048`/`pg-0049`/`pg-0050` 有独立 predecessor、capability 和 grant/constraint 契约;control-core 已到 v49; 5. CloudNativePG deployment audit 已验证八角色和 Secret 映射; 6. 真实 K3s `v1.34.3+k3s1` + PostgreSQL 18 纵切面完成两次 plan、职责分离批准、consume、 TokenRequest、delivery 与 succeeded execution receipt;同一 execution 的精确重放没有再次签发 token; 7. PostgreSQL 18.4 arm64 physical HA 在 v49 上通过 `remote_apply`、timeline 1→2、旧主 fencing、 未确认分区提交排除、`pg_rewind` 只读同步重入、fresh control replicas 与全部领域 gate。 8. management transport 仅公开 plan/propose/decide/inspect,认证失败、弱 assurance、扩展 shape 与 内部 execute 均在管理 authority 前拒绝;响应只含 plan/approval 低敏摘要; 9. Worker HTTPS host 复用既有 TLS 1.3、认证前连接/peer/global shield、并发/超时/body/response 上限,但路径固定为 `/api/v3/worker-credentials/management`,Plugin Package 路径在同一实例返回 404;Worker/Plugin HTTP 11 项联合回归与原普通/Kubernetes tunnel client 15 项回归通过; 10. Worker client/CLI 复用 canonical 私有文件、CA/servername、TLS 1.3、无 redirect、单请求与 bounded response 实现,四类结果 exact-validate,附加 authentication ID、secret-bearing shape 或 内部 execute 结果失败关闭;本能力未新增 package,ADR-0243 删除孤立 cutover 后当前为 19; 11. manager durable quota 在 Project Policy 后、任何 plan/approval state read 前执行,四类 operation 使用数据库时钟、固定窗口与有界 receipt ledger;精确重放不重复计数,拒绝映射为 HTTP 429; 12. Worker manager process/CLI 已接入专用 role readiness、authority=`worker-credential-management` identity ledger、quota、TLS 1.3 HTTP 与有序 drain/close;禁用态只读 enable 开关且零文件/数据库 副作用。新旧 manager 进程 14/14;caller-driven executor process/CLI 已固定 exact command、私有 32-byte pepper、单连接 Pool、两次 issuer authorization confirmation、一次 TokenRequest session 与 失败保真销毁与低敏 CLI 输出,专项 7/7;cluster-admin 全量 174 pass/1 条件 skip; 13. opt-in Kubernetes base/CloudNativePG overlay 已完成双副本、PDB、required anti-affinity、零 ServiceAccount token、只读 TLS/identity/CA 投影、label-only ingress、DNS/PostgreSQL-only egress、 manager-only CNPG credential 与 fail-closed image digest;独立 executor base/CNPG operation 采用 caller-driven Job、`backoffLimit=0`、600 秒投影 issuer token、existing exact TokenRequest RoleBinding、 command/pepper/CA 分离只读投影、executor-only CNPG credential、无 ingress 与 DNS-only base egress; Kubernetes API 必须由私有 overlay 指定 exact CNI destination。独立 management client operation 固定 `backoffLimit=0`、零 token/RBAC、DNS + manager:8444-only egress、不可变三输入和独立 fail-closed digest;deployment audit 28/28 变异测试通过; 14. PostgreSQL 18.4 arm64 physical HA 在 v49 再次运行,八角色专用 readiness 在 promotion 前后均 通过;新增 Worker manager 双数据库实例矩阵以 16 个并发请求证明 8 admitted/8 limited、重放 零额外计数、autocommit response loss 精确收敛,并把 identity ledger 推进到 generation 3,证明 restart rollback、same-generation rewrite、implicit removal 拒绝与 COMMIT response loss 收敛。 `remote_apply`、timeline 1→2、fencing/partition/`pg_rewind`/只读同步重入和总 gate 均继续为 true; 该证据不冒充真实 Kubernetes Pod、HTTP listener 或外部 IdP 演练。 15. 真实 K3s `v1.34.3+k3s1` + PostgreSQL 18 门已用生产 `cluster-admin` 镜像运行第三次 caller-driven credential rotation:首次 Job 返回 `published` 且 `tokenRequestUsed=true`,第二个 独立 Job 精确重放相同 command 时返回 `existing` 且 `tokenRequestUsed=false`。两个 Job 均使用 `backoffLimit=0`、executor-only 单连接数据库凭据、无 automount token、600 秒投影 issuer token、 无 ingress 和精确 API Service/backend/PostgreSQL `/32` egress。最终 3 个 plan/consumed approval/ dispatch/succeeded execution/credential/published delivery、12 条安全审计、Recreate stop-before-start、 Bound PVC journal 与 identity generation rollout 全部收敛,总 gate 为 true。 16. 三节点 K3s + PostgreSQL 18 的独立 manager 门以两个 required anti-affinity Pod、生产 Worker management client 和 TLS 1.3 精确 Pod 寻址完成 8 admitted/8 limited;配额已满后的 跨 Pod exact replay 返回 `existing`,最终 plan/consumed/receipt 均为 8。identity projection 依次覆盖 generation 1、2 overlap、3 revoke,generation 2 rollback surge 以 exit 1 失败关闭且 两个旧 Pod 保持 Ready。停库后两个业务请求均为 503、Ready 均为 503、Live 均为 200;数据库 重启不允许旧实例原地解除 availability fence,只有 fresh rollout 的两个 Pod 返回 200。一次性 client Job 仅对没有远端响应的 transport failure 复用同一幂等命令做有界重试,不重试任何 HTTP 业务拒绝。该门同时发现并修复计划 repository 把 `plannedAtMs`、`expiresAtMs` 与派生 digest 错当为调用方语义、导致跨 Pod exact replay 500 的问题;不同 target/requester 仍冲突。facade 同时把无效计划和 semantic conflict 分别稳定映射为 HTTP 400/409,不再泄漏成 500。 17. 同一三节点 K3s 门现在直接加载仓库内 management client ServiceAccount、NetworkPolicy 与 Job, 只把镜像替换为本次构建的生产 Admin image。固定 `qinglong3-system` DNS、TLS 1.3 `/readyz` init、不可变 request/assertion/CA、零 projected token 条件下,init/main 均 exit 0,client `restartCount=0`,`worker-credential.inspect` Job Complete;报告新增 `gates.committedOneShotClientOperation=true` 且总 `passed=true`。该证据不依赖 kubelet 日志代理, 以 Kubernetes Job/Pod 终态证明执行,避免把管理响应复制到 termination message。 ## 仍未完成 - 外部 OIDC/client certificate 双 User ceremony、撤销审计与真实生产 ingress; - 多节点 Kubernetes API/CSI 故障矩阵,以及固定 x64/arm64 路由设备与集群节点资源报告。