Files
qinglong/docs/adr/ADR-0078-posix-local-owner-console-proof-and-secret-delivery-gate.md

67 lines
7.1 KiB
Markdown
Raw Permalink 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-0078POSIX 本机 Owner Console 证明与 Secret 交付门禁
- 状态:ProposedPOSIX proof、staged Secret 恢复、摘要绑定确认与 Owner ceremony CLI 已实现;fresh setup 和实机故障门禁待完成)
- 日期:2026-07-21
- 关联 RFCQL-RFC-0001 D-27、D-74、D-76、D-77、D-78
- 关联 ADRADR-0063、ADR-0075、ADR-0076、ADR-0077、ADR-0079
> ADR-0087 现行增量:原 `@qinglong/local-owner-bootstrap` 与 `@qinglong/local-owner-credential-recovery` 已物理合并为无聚合根入口的 `@qinglong/local-owner-ceremony/bootstrap` 与 `/credential-recovery`;本文中的旧包名保留为当时实现证据,现行依赖与权限门禁以新 subpath 为准。
## 上下文
ADR-0077 已提供默认不可达的 Identity provisioning、challenge 与原子首 Owner claim,但 `provision/issue` 请求仍携带结构化 `issuer`。包边界能够阻止默认 application 导入 authority,却不能把一段调用方构造的 JSON 变成可信 `local_console` 事实。
直接增加 CLI 还有另一个崩溃窗口:数据库事务可能已经提交,而 credential/challenge plaintext 尚未写入用户指定文件。此时 exact replay 按设计只能返回 `null`,如果没有先暂存、提交后发布和重启恢复协议,fresh install 会得到无法取回的凭据。3.0 不以“多数时候能写成功”替代可恢复交付。
## 决策
### 1. Authority 在组合根绑定,不进入请求 DTO
`ProvisionLocalIdentityRequest``IssueLocalOwnerBootstrapRequest` 不再包含 `issuer``createLocalOwnerBootstrapService` 在构造时绑定短时 `local_console` authority,并在每次操作时重新验证其时间和 subject/assurance;公开请求若添加 issuer、User、principal 或 credential identity 会被 exact-shape 校验拒绝。
这不是把 TypeScript 对象当成不可伪造 capability。真正的生产入口只能是受依赖审计保护的 `@qinglong/local-owner-console` 组合根;默认 runtime/application 和其他 package 不能导入 bootstrap authority。
### 2. POSIX 证明绑定部署根、数据库、pepper 与进程用户
短生命周期 console 要求 real/effective UID 存在且相同;显式 `deploymentRoot` 必须是当前 UID 拥有的真实 `0700` 目录,数据库和 pepper 必须是该根下经逐段验证、无 symlink 的真实 `0600` 普通文件。路径必须是规范化、有界绝对路径,两个 authority 文件不能同路径或共享 inode。
该证明表达“当前进程已取得这个私有部署目录的 OS 文件权限”,不把 `localhost`、TTY、环境变量或 HTTP body 当成身份。容器中能否执行该短命令、volume ownership 与宿主管理权限是否等价,仍由部署模板和实机证据负责;库本身不伪造宿主 attestation。
### 3. 打开前后和每次操作都复核路径身份
组合根先捕获 root/intermediate/database/pepper 的 `(device,inode,uid,mode,type)`,再打开唯一 SQLite bootstrap connection,打开后立即复核一次;每次 provisioning/issue/claim 前再次复核。路径替换、权限放宽、UID 变化或 symlink 都在触发数据库 authority 前 fail closed。
console 不增加 listener、timer、watcher、scanner、cache、sidecar 或第二 SQLite connection,关闭继续复用同一 operation authority 的幂等 close fence。
### 4. Pepper 只从私有普通文件读取
pepper 不接受 argv、环境变量、stdin 或 JSON。组合根以 `O_RDONLY|O_NOFOLLOW` 打开已证明的 `0600` 文件,比较 fd 与路径的 device/inode,施加 32256 bytes 上限,只接受无空白的 base64url 内容,并在转成短生命周期字符串后清零读取 Buffer。
本 ADR 不负责 pepper 创建、轮换、备份或恢复;这些动作需要 no-replace 文件发布、版本化引用与恢复策略,不能由 migration/application 启动时自动生成。
### 5. Secret 可恢复交付已实现,但 CLI 继续受剩余门禁
`@qinglong/local-owner-console` 已按 ADR-0079 实现有界、私有、no-replace 的 staged secret record:数据库提交前耐久暂存,提交并核对数据库事实后原子发布;重启以 mutation/database 事实恢复。启用 delivery 后 provision/issue 响应始终返回 `token: null`,明文只存在于私有 ready record,不进入 stdout、日志或错误。
该包仍不声明 `bin`ADR-0086 由独立 `@qinglong/local-owner-cli` 组合它,并以 command-file-only 的 `ql3-owner` 开放 provisioning/claim/delivery acknowledgement/credential recovery。ADR-0080/0081/0082/0083/0084 已补齐 pepper no-replace provision/backup/restore、ready record 摘要绑定确认、SQLite acknowledgement ledger、pepper/credential rotation 与可恢复 tombstone retention/GCfresh setup、rotation 管理命令、断电/真实 ENOSPC/只读文件系统和 Linux/容器权限证据仍未完成。HTTP/UI 继续禁止,因为它们还需要独立的 origin/CSRF/rate-limit/transport 与恢复设计。
## 被否决的替代方案
1. **请求继续携带 issuer**:让 transport 字段冒充平台 authority,拒绝。
2. **只检查 `stdin.isTTY` 或 loopback**:两者都不证明部署文件权限或调用者身份,拒绝。
3. **pepper 通过 argv/env/stdin**:会进入进程列表、诊断或继承边界,拒绝。
4. **事务成功后直接写 secret 文件**:崩溃或 ENOSPC 会永久丢失一次性 secret,拒绝。
5. **为 console 另开常驻服务或 watcher**:扩大攻击面并破坏路由设备零常驻成本,拒绝。
6. **把本机 POSIX proof 复用于 cluster-control**:集群仍使用独立 PostgreSQL/cluster-admin/Worker 身份与传输边界,拒绝。
## 验收证据
1. `@qinglong/local-owner-bootstrap` 8 项真实 SQLite 测试在 issuer 构造期绑定和跨进程时间漂移后继续通过;请求注入 issuer/identity 被拒绝,稳定 authentication identity 不变时 exact replay 成功,不同 identity 冲突。
2. `@qinglong/local-owner-console` 19 项测试通过:私有 POSIX proof、完整 provision/issue/transport-free claim、预提交 pending 保留、数据库提交后 credential/challenge 自动恢复、文件删除后数据库事实重放、权限/摘要篡改与 64 条目录预算 fail closed、数据库 inode 替换、幂等关闭与无 `bin`/默认 runtime 导出。
3. dependency audit 登记 32 个 QL3 package importer;只有 local-owner-console 可以直接导入 local-owner-bootstrap,产品 CLI 只能导入 console facade,默认根继续禁止全部 QL3 authority 包。
4. 32 个 QL3 production importer 的 low/moderate/high/critical advisory 均为零;legacy 根 3 low/9 moderate/2 high 独立可见。
## 未完成项
credential `pepper_key_id` provenance、受审 keyring/active CAS、credential rotate/revoke/recovery、versioned acknowledgement tombstone retention/GC 与 Owner ceremony CLI 已由 ADR-0083/0084/0086 完成;仍需 Linux rootless/root 容器与 volume ownership 证据、真实断电/ENOSPC/只读文件系统故障注入、固定低配路由设备 RSS/闪存写放大门禁,以及 fresh setup/rotation 运维入口。ready record 显式确认、安全删除与 SQLite 账本已由 ADR-0081/0082 完成。