Files
qinglong/docs/adr/ADR-0114-fenced-batch-remote-worker-secret-delivery.md
T

109 lines
6.4 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ADR-0114:围栏化 Remote Worker 批量 Secret 交付
- 状态:Accepted
- 日期:2026-07-23
- 关联 RFCQL-RFC-0001 D-24、D-72、D-85、D-109、D-111、D-112、D-113
- 关联 ADRADR-0058、ADR-0073、ADR-0108、ADR-0109、ADR-0110、ADR-0113
## 背景
ADR-0113 已固定 Secret-before-Artifact 的 Worker materializer,但只留下抽象 provider。
若 provider 仅凭 Project/Task/SecretRef 向控制面取值,被替换 Session、过期 Lease、旧
Attempt 或被篡改 execution revision 都可能重放同一 Secret capability;若把 lease token
直接交给通用 provider,又会扩大 bearer capability 的内存与日志暴露面。
独立 Worker ingress 使用最小权限 `ql3_worker_ingress` PostgreSQL role。该角色按既有
架构不能读取 Run execution revision,更不能获得 Run/Lease mutation 权限;因此不能为
实现 Secret 路由而把 runtime authority 临时塞进 HTTP handler 的数据库连接。
## 决策
### 1. 使用一个 exact versioned 批量协议
协议固定为 `qinglong/remote-secret-delivery@v1`。单次 request 最多 64 KiB、64 个唯一
`qlsecret:v1` referenceresponse 最多 128 KiB,单值最多 16 KiB、值总量最多 64 KiB。
response 必须按请求顺序返回 exact `{secretRef,value}`,并回绑 Run、Attempt、offer 与
execution digest;未知字段、缺项、乱序、重复、跨 Project reference、NUL、超限或身份
漂移全部 fail closed。
Worker 继续复用 ADR-0112 的单一 `WorkerIngressHttpsClient`、TLS 1.3 mTLS credential
provider 与最多一个 keep-alive socket。现有 offer/activation 的默认 request 上限保持
4 KiB;只有 `/secrets` 显式申请 64 KiBclient 仍以 64 KiB 作为不可提升的硬上限。
### 2. 明文解析前必须验证完整数据库权威围栏
每次 delivery command 必须同时绑定:
- 认证 path 的 Worker ID 与 Session ID
- Worker generation
- Run、Attempt、Project、Task 与 pinned Task revision
- offer ID 与 execution digest
- Lease generation、token 与 expected version
- 完整且有序的 SecretRef 集合。
runtime authority repository 在 Attempt advisory transaction lock 下使用 PostgreSQL 时钟,
要求 Run=`dispatching`、Attempt=`starting`、executor=`remote_worker`、Session 为当前
`online|draining` 且未过期、Lease=`leased` 且未过期,并逐项比较 Attempt/Session/Lease
中的 worker、generation、offer、token digest 与 version。随后重新规范化 immutable
`task_execution_revisions.plan_json`,要求 execution digest 与 SecretRef 集合完全一致。
任一漂移都在调用明文 provider 前拒绝。
同一仍然有效的 starting fence 可以因网络丢包进行幂等重试;它不产生“已消费”事实。
Lease/Session/version/Attempt 状态变化后的重放必须被拒绝。这样既不因响应丢失让 Worker
无法启动,也不允许旧 capability 跨 authority 生命周期继续取密。
### 3. 保持 ingress role 与 provider capability 最小化
PostgreSQL authority repository 只从 runtime entrypoint 导出。独立 Worker ingress 只能
接收由外层 composition root 注入的受保护 delivery service`ql3_worker_ingress` role
不新增 Run、Task revision 或 Lease 权限。HTTP pipeline 只负责 mTLS/`ql3w` principal、
path identity、低敏 audit 与 wire projection。
Worker materializer 的通用 Secret provider 请求只增加 capability-free 的 offer ID 与
execution digest,仍不包含 lease token/digest、Worker credential、command、callback 或
完整 Offer。具体 HTTPS provider 从单一私有 inbox 重读 canonical Offer,完整复验请求后
才在其内部装配 lease capability。控制面完成 authority 后才调用外置 Secret/KMS/Vault
provider;该 provider 接收不含 token 的 authority projection。
Secret 明文不得持久化、进入 audit/diagnostic/错误文本或普通日志。transport bytes 在解析
后清零,provider resolution 必须支持失败与 handoff 后 cleanupJavaScript string 无法可靠
zeroize,因此实现不得缓存它,并在 materialized context dispose 后释放全部引用。
### 4. 默认仍不可达
本 ADR 不选择具体 KMS/Vault/Secret store,不实现 Artifact writer、Executor 或 production
headless composition,也不新增 package、数据库表、timer、watcher或第三方依赖。未注入
authority repository 或 plaintext provider 时 `/secrets` 返回 unavailable;现有默认关闭
行为不变。
## 被否决的替代方案
1. **只按 Project/SecretRef 取值**:无法证明请求仍属于当前 Attempt/Lease。
2. **把 lease token 交给通用 materializer provider**:扩大 bearer capability 的传播面。
3. **让 worker-ingress role 直接读取所有 Run/Task 表**:破坏独立入口最小权限与 ADR-0109
的受保护 runtime boundary。
4. **每个 Secret 单独请求**:最多 64 次 TLS/JSON 往返,不适合低性能路由设备。
5. **使用一次性消费记录**:响应丢失会让合法启动无法重试,并额外引入表和清理生命周期。
6. **为 delivery 新拆 package**:协议、服务、adapter 都已有明确现有归属,无独立部署责任。
## 影响与剩余门禁
已完成:runtime wire contract、完整 authority repository、受保护 service、认证 ingress
route、共享 mTLS client 的 opt-in 64 KiB request、Worker inbox-bound HTTPS provider、exact
ref/value/response identity、stale Session/Lease/version/Attempt 与 capability 泄漏负向测试。
仍未完成:具体 cluster KMS/Vault adapter、Secret 管理与轮换产品面、Artifact writer/upload/
retention、具体 Executor 输出绑定、completion/lease-loss/cancellation/recovery 组合,以及
固定 Edge 与多架构真实传输资源证据。生产 Worker execution 继续默认关闭。
## 验收证据
1. authority repository 在读取 execution revision 前取得 Attempt advisory lock,并使用数据库
时钟拒绝过期 Session/Lease。
2. stale Lease version、running Attempt、错误 digest 或非完整 SecretRef 集合都不会调用
plaintext provider。
3. Worker provider 请求不含 lease capability;只有 inbox-bound HTTPS adapter 内部装配它。
4. response 不包含 lease token/digest,且 Run/Attempt/offer/digest 任一漂移都被 Worker 拒绝。
5. offer、activation 与 Secret delivery 共用一个 Agent;普通请求仍受 4 KiB 默认上限。
6. package 数、依赖树、数据库 schema 与 `ql3_worker_ingress` privileges 不增加。