Files
qinglong/docs/adr/ADR-0147-postgresql-durable-plugin-package-identity-keyset-ledger.md
T

92 lines
4.2 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-0147PostgreSQL 持久 Plugin Package 身份 keyset ledger
- 状态:Accepted
- 日期:2026-07-25
- 关联:ADR-0144、ADR-0145、ADR-0146、QL-RFC-0001 D-142/D-143
## 背景
ADR-0145 的文件式 keyset 已能在单进程生命周期内拒绝 generation 回退、同代
rewrite、隐式 key 移除和 revocation 撤销。但全部管理 Pod 同时重启后,进程内
monotonic state 会丢失;若部署投影回退到旧 Secret,旧签名 key 可能重新被接受。
不能用 watcher、timer、Redis 或 Pod 本地持久卷补这个缺口:它们分别引入额外常驻
资源、第二事实源或副本不一致,并不能与现有 PostgreSQL HA 故障域共同收敛。
## 决策
### 1. 单一持久 trust ledger
`pg-0024-plugin-package-identity-keyset-ledger` 新增
`ql3.plugin_package_identity_keyset_ledger`,固定只有
`plugin-package-management` 一个 authority。行内保存:
- generation 与完整 keyset SHA-256 base64url digest
- immutable issuer/audience
- 最多 8 个 active key ID
- 最多 64 个 append-only revoked key ID
- 数据库时钟更新时间。
migration stream 推进至 24 条、`control-core` capability v23、37 张表,并新增
`plugin_package_identity_keyset_ledger:1`
### 2. 原子单调推进
`PostgresPluginPackageIdentityKeysetLedgerRepository.observe()` 使用同一
package-manager 连接池的短事务:
1. `INSERT ... ON CONFLICT DO NOTHING` 竞争首次建账;
2. `SELECT ... FOR UPDATE` 串行化同一 authority
3. 同 generation 只接受 digest、trust domain、active/revoked 集合完全一致的重放;
4. 新 generation 必须保持 issuer/audience 不变;
5. 历史 revoked key 必须全部保留;
6. 历史 active key 必须仍 active,或显式进入 revoked
7. 通过后才以数据库时钟更新并提交。
COMMIT 响应丢失统一返回 unavailable;调用方以同一 snapshot 重试会读取已提交行并
精确收敛,不产生新 generation。
### 3. 认证路径复核
生产 management process 先完成 package-manager schema/role readiness,再创建带
PostgreSQL ledger 的 keyset file provider。首次启动、文件发生变化和文件 digest
未变化的每次认证 reload 都必须调用 ledger
- 新副本拿到旧文件时在监听前失败关闭;
- 已运行副本在 ledger 被另一副本推进后,不得继续把旧进程内 verifier 当持久事实;
- 文件损坏、数据库不可用、ledger conflict 均映射为 keyset unavailable,不使用
stale fallback。
基础 file provider 保留可选 ledger port,供纯单元测试或非生产组合使用;正式
cluster process 永远注入 PostgreSQL 实现。
### 4. 权限和资源边界
- 只有 `ql3_package_manager``SELECT/INSERT/UPDATE` ledger
- runtime、admin、package-executor、worker-ingress 与 PUBLIC 均无权限;
- 不新增 workspace package、第三方依赖、Redis、timer、watcher 或后台清理;
- edge/standalone 不导入该 repository,仍保持零额外常驻成本;
- 表恒定一行,revocation 列表与 JSON 字节数均有硬上限。
## 验证
- cluster-postgres 全量 141/141
- cluster-admin 全量 97 通过、1 个真实 Kubernetes API 条件跳过;
- PostgreSQL 18.4 arm64 physical HA 报告新增
`durableIdentityKeysetLedgerSurvivesReplicaRestart`
- 两个独立 package-manager 实例并发观察同一 generation
- 新 repository 实例模拟全副本重启,旧 generation 被拒绝;
- 同代 rewrite、隐式移除和 trust-domain 漂移被拒绝;
- driver 已确认 COMMIT 后注入响应丢失,再次观察精确收敛到 generation 3
- ledger 与既有 quota、physical promotion、`remote_apply`、旧主 fencing/rewind
一起通过 24 个具体 gate 和总 `passed`
## 后续非本 ADR 范围
本 ADR 关闭“全副本重启后的 durable keyset anti-rollback”阻断项,但不自动开放公网
管理入口。真实 IdP 两名 User 四眼、双 Pod live NetworkPolicy/ingress、Secret 投影
传播窗口、TLS/keyset 自动轮换和真实 Kubernetes control-plane HA 证据仍是生产前置。
ADR-0148 已冻结这些真实环境事实的低敏 evidence schema,并默认拒绝 management
公网 egress;它不把“审计器存在”当作真实报告已经取得。