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

4.2 KiB
Raw Permalink Blame History

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_managerSELECT/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;它不把“审计器存在”当作真实报告已经取得。