Files
qinglong/docs/adr/ADR-0183-emergency-local-publisher-key-revocation-and-quarantine.md
T

129 lines
7.0 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-0183:本机 Publisher Key 紧急撤销与隔离证据
- 状态:Accepted
- 日期:2026-07-28
- 关联:RFC D-133、D-169、D-170、D-171、D-172、D-173ADR-0135、
ADR-0179、ADR-0180、ADR-0181、ADR-0182
## 背景
ADR-0182 的正常退休要求旧 signer 引用和未决 catalog transaction 都归零,这不适合
疑似或确认泄露的 key。继续等待重签与 collect 会允许攻击者发布新的 recovery
entry;直接删 key 又会把“信任根已删除”误写成“已经运行的 Package、Task 和 Tool
均已停止”,并遗漏受影响 durable lock 的审计锚点。
本机 trust、catalog/bundle 文件与 SQLite 仍是不同介质。紧急动作必须先建立一个跨
重启可见的阻断事实,再以双人或显式 break-glass 完成不可逆删除;不能依赖进程内
锁、watcher 或一次目录扫描。
## 决策
### 1. 提案先阻断,再确认删除
第一位 authenticated current Owner 执行
`plugin-package.publisher-trust.revoke.propose`。短生命周期命令先有界分析全部
retained catalog entry 和未决 transaction,并把受影响 lock digest 的排序集合、
计数、publisher/key、expected generation、mutation、提案 Owner 与 audit 时间绑定
为 immutable proposal 和 `impactDigest`
proposal 以 hard-link no-replace 写入受管 `0700` trust root;一旦 durable
- 目标 signer 的 catalog publication 立即失败;
- application 在 queued stage 前和 staging 后、返回 evidence 前各复验阻断事实;
- rotate、retire 和另一生命周期 mutation 不能越过该 pending proposal
- 命令返回 `runtimeAction=stop_required`,要求 operator 停止 application。
proposal 不提供 abort 或 unblock。疑似泄露事实一旦发布就只能通过精确确认继续,
避免删除提案恢复已受怀疑 signer 的 authority。
### 2. 默认双人确认,break-glass 必须显式绑定影响
第二条命令 `plugin-package.publisher-trust.revoke.confirm` 必须精确重放 proposal 的
publisher、key、expected generation、mutation、`proposerSubjectId`
`expectedImpactDigest`,并选择:
- `dual_control`:确认者与提案者必须是两个不同 subject,且两者在确认时都仍是
current default Project Owner
- `break_glass`:允许同一 current Owner 独立完成,但必须显式选择该模式,并提交
`suspected_key_compromise``confirmed_key_compromise` reason code。
两种模式都重新执行强认证、current Owner fence 和既有低敏 SecurityAudit。确认后先
写 immutable revocation receipt,再生成显式 `revoke` snapshotsnapshot 必须精确
等于前一 generation 删除一个目标 key,不得改写其他 key。
紧急撤销允许删除最后一个 key。此时 `current.json` 的空 key 集合是可恢复、可审计的
管理状态,但 runtime trust registry 构造失败关闭;operator 必须通过受审 provision/
recovery 流程重建信任,不能让 runtime 使用隐式默认 key。
### 3. Quarantine 是不可变证据,不是假热停止
receipt 保存 proposal 时观察到的受影响 lock digest 集合,并在 inspect 中只聚合返回
`quarantinedLockCount`,不回显 publisher、key 或 lock identity。它证明这些 lock
必须按 compromise 处置,但本切片不修改既有 Package installation 状态枚举,也不
声称已撤下:
- 已经 `active` 的 Package
- 已物化的 Task/Tool resource generation
- 已进入 `staged``activating` 的事务。
确认成功返回 `runtimeAction=restart_required`。这不是自动重启许可:operator 应在
停机状态审查受影响 lock、替代 key 与恢复源。后续 D-174 必须新增持久化
Package deactivation/quarantine 状态机,并让 Task/Tool publication 和 invocation
admission 按 durable fence 撤出已激活资源。
### 4. 恢复、容量与低配约束
proposal、receipt、snapshot 或 current 提升任一窗口崩溃,只允许同一 authenticated
command 和同一 impact/authorization/reason 精确重放;漂移失败关闭。trust root
最多保留 32 个 revocation proposal、32 个 receipt、32 组 retirement evidence、
64 代 snapshot 和 64 个临时文件;未知或超限 entry 失败关闭。
实现复用已有:
- `@qinglong/local-admin/package-publisher-trust`
- `@qinglong/local-admin/package-recovery-catalog`
- `@qinglong/local-owner-cli/package-publisher-trust-command`
- `@qinglong/local-application/plugin-package-recovery-catalog`
没有新增 workspace package、第三方依赖、timer、watcher、listener、socket 或 steady
state I/O。空队列仍不加载 catalogproposal guard 只在真实 publication/stage 或
显式管理命令中读取有界私有目录,适合低配路由设备。
## 拒绝方案
1. **复用正常 retirement**:要求引用为零,无法立即冻结疑似泄露 signer。
2. **单命令立即删除**:缺少第二人复核或显式 break-glass,误操作不可审计。
3. **只删除 trust key**:丢失受影响 lock 集合,也无法驱动后续资源隔离。
4. **新增 `quarantined` 枚举但不接资源消费者**:形成“状态已安全”的虚假保证。
5. **进程内 denylist 或 watcher**:重启丢失且增加路由器 idle 资源和竞态。
6. **删除最后 key 时注入默认 key**:在最危险窗口引入未审计信任根。
## 当前证据
- proposal durable 后目标 signer 的 catalog publish 与 queued application stage 均
失败关闭;
- 同一 Owner 使用 `dual_control` 被拒绝,显式 `break_glass` 可完成产品级流程;
- core 双 Owner 流程验证不同 subject、impact digest、reason 和 authorization mode
- receipt/snapshot/current 崩溃窗口由 exact command 收敛,最后 key 可撤销且 runtime
registry 失败关闭;
- inspect 只返回 revocation、pending 和 quarantined lock 计数;
- 非 Owner 在 proposal 可见前被拒绝,33 个 revocation evidence 触发容量失败关闭;
- local-admin 63/63、local-application 32/32、local-owner-cli 22/22、
dependency/source boundary 30/30 和 Edge import 121 modules 全绿;
- edge/standalone application 为 4,766,330/4,766,474 bytes、607 files、90 loaded
modulesapplication-ai 为 5,444,151/5,444,307 bytes、651 files、89 loaded
modules,四种制品和 RSS 门均在预算内;
- workspace 仍为 22 package,无新增生产依赖或常驻资源。
Cluster 代码、migration、ACL 和部署 manifest 未变化。本 ADR 不声明 Cluster publisher
trust 能力;PostgreSQL HA Docker 门只在后续 Cluster 对等实现发生变更时重跑。
## 后续门禁
1. D-174active/staged/activating Package 的持久 deactivation/quarantine
2. Task/Tool resource generation 撤回、invocation admission fence 与 crash replay
3. 被隔离 lock 的替代发布、恢复或永久 tombstone ceremony
4. 在线 OCI fetch authority 与 publisher metadata/update channel
5. 固定低配 Linux 路由器断电、ENOSPC、闪存写放大与容量证据;
6. Cluster 对等 trust lifecycle 和双人管理 transport。