Files
qinglong/docs/adr/ADR-0144-cluster-plugin-package-management-transport-boundary.md
T

219 lines
13 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-0144Cluster Plugin Package 管理 Transport 与双 Authority 边界
- 状态:Proposedtransport-neutral 强认证适配器、源码边界、manager/executor
PostgreSQL 角色拆分、dedicated assertion/keyset、TLS 1.3 HTTP process、可选
management Kubernetes overlay、静态权限门和 PostgreSQL 18.4
physical-promotion readiness、durable distributed quota 与全副本重启
keyset anti-rollback 已实现;真实四眼与 live ingress 证据尚未实现)
- 日期:2026-07-25
- 关联 RFCQL-RFC-0001 D-05、D-08、D-09、D-49、D-85、D-127、D-139 至 D-142
## 上下文
ADR-0142 已在 `@qinglong/cluster-admin/plugin-package-management` 组合
PostgreSQL proposal、Approval、Project Policy 和 caller-driven dispatcher,并固定
`separation_of_duty`。这仍只是认证后的 application service,不是可公开的管理 API。
现有 `cluster-control` Bearer credential authenticator 对 User 只产生
`single_factor` principal;它适合普通控制面 API,但不能被 transport 自行升级为
`multi_factor`。现有 cluster-admin recovery Job 又同时具备 admin PostgreSQL、
Registry credential 和 Kubernetes ConfigMap publish authority。若直接给该 Job
增加长驻 HTTP listener,一个 transport 漏洞将同时取得数据库准入、供应链下载和
资源发布权限。
## 决策
### 1. 不新增 package,不复用 cluster-control
Cluster 管理 transport 留在既有 `@qinglong/cluster-admin`,使用显式子路径和独立
process binary。它不从 package root 导出,也不进入 `cluster-control`、Worker、
edge 或 standalone 闭包。
部署上它是独立且默认关闭的 management Deployment/Service,不复用 recovery Job
Pod。使用同一 workspace package 不代表使用同一 ServiceAccount、数据库角色、
Secret 投影或进程入口。
第一阶段只实现
`@qinglong/cluster-admin/plugin-package-management-transport`
transport-neutral command adapter,不监听 socket、不解析 HTTP、不打开 PostgreSQL
也不直接导入 Kubernetes、Registry 或 Package execution authority。源码门禁只允许
它依赖共享 Approval、Package proposal/management 与 Security contract;其他 package
不得导入该管理子路径。这样先冻结公开操作和 Principal 注入形状,再选择具体协议,
避免临时 HTTP handler 先成为事实标准。
### 2. 人类路由与系统执行分离
公开路由只允许:
- propose:提交 exact Package install action,生成 immutable proposal 与 pending
Approval
- decide:由另一名强认证 User approve/reject
- inspect:只返回 proposal、Approval 与 installation 的低敏摘要。
`consume``dispatch` 不公开为人类 HTTP 路由。它们由受信 composition 注入固定
system consumer,并通过独立 caller-driven Job/process 执行。外部请求不能提供
consumer subject、authentication ID、ceremony、数据库时间或 dispatcher identity。
### 3. Transport 注入强 Principal
请求 body 不得携带 `principal`。认证 adapter 必须验证部署显式配置的 issuer、
audience、签名 key、有效期、not-before、不可变 subject 与 step-up fact,然后只
映射为 active User 的 `multi_factor``hardware` principal。
现有 cluster-control API credential 对 User 生成的 `single_factor` principal 必须
失败关闭;service credential 不能替代人类 decide。Cluster ceremony 永久固定为
`separation_of_duty`requester 与 approver 必须是不同 User。
具体 OIDC、mTLS+step-up 或企业 IdP adapter 在后续 ADR 中选择;在 assertion
验证、key rotation 与撤销证据完成前,本管理 Deployment 保持关闭。
首个 assertion contract 已通过
`@qinglong/cluster-admin/plugin-package-identity-assertion` 固定为专用 compact
JWS,而不是直接信任通用 access token
- protected header 必须精确为
`typ=ql3-plugin-package-management+jwt`、reviewed `kid` 与 key-bound
`EdDSA|ES256|RS256`,拒绝算法降级、未知 key 和额外 header
- issuer 是 canonical HTTPS URLaudience 与
`ql3_purpose=plugin-package-management` 必须精确匹配,claim 集合固定且有总字节
上限;
- key set 最多 8 把,可用新旧 key 重叠完成 restart-based rotation;每把 JWK 必须
是 exact public signing keyRSA 仅接受 20484096 bit/65537EC 仅 P-256
OKP 仅 Ed25519,私钥字段或未知字段均拒绝;
- 每个受信 `acr` 必须由部署配置显式映射到 `multi_factor|hardware`,并列出全部
required `amr`,verifier 不从任意字符串自行推断 assurance;
- assertion lifetime、authentication age、not-before 与 clock skew 都有硬上限;
subject 只生成 User Principal,原始 `jti` 通过 issuer-domain-separated SHA-256
派生内部 authentication ID,不进入 service request、审计响应或低敏结果;
- verifier 只使用 Node 24 `node:crypto` 和 profile-neutral Security contract,不读取
网络、数据库、Kubernetes 或 Registry authority;源码门禁止其他 package
import 此子路径。
ADR-0145 已将 verifier 绑定到有界 keyset 文件和独立 HTTP process。keyset 支持
overlap rotation、显式 revocation、同进程 generation rollback/rewrite 拒绝和每请求
重新读取;HTTP 先处理 Authorization 再读取 content/body,只开放 reviewed command
endpoint,并由可选 Kubernetes operation 部署。management Service 仍不进入默认
Kustomize。ADR-0146 已关闭 durable quota 缺口,ADR-0147 又关闭全副本重启
anti-rollback;在真实 IdP 与 live ingress 证据完成前仍不得接入生产 ingress。
### 4. PostgreSQL Authority 拆分
现有广义 admin role 必须收敛为至少两个不共享 LOGIN credential 的部署角色:
- manager:只允许 proposal、Approval、Project Policy 与低敏 Audit 所需的 exact
SELECT/INSERT/UPDATE/function EXECUTE
- executor:只允许 consume、execution/start barrier、Package installation、
recovery 与发布所需的 exact authority。
management Pod 不挂载 Registry credential,不授予 Kubernetes write RBAC,不取得
stage/publish Secret。executor/recovery Job 不暴露 HTTP Service。
角色拆分必须通过 reviewed PostgreSQL migration、schema readiness、unknown-grant
拒绝、连接角色回读和 PostgreSQL 18 physical-promotion 门;不能在启动脚本中使用
superuser 动态 GRANT。
`pg-0022-plugin-package-authority-split` 已把 control-core capability 推进至 v21
并执行以下收敛:
- `ql3_admin` 撤销全部 Package proposal、Approval/dispatch/execution、
installation/head/mutation/admission table authority,以及两个 Package fence
function 的 EXECUTE
- `ql3_package_manager` 只取得 Project/RoleBinding 读取、Audit
SELECT/INSERT、proposal SELECT/INSERT、Approval SELECT/INSERT/UPDATE 和 Approval
policy fence
- `ql3_package_executor` 只取得 Project/RoleBinding/proposal 读取、Audit
SELECT/INSERT、Approval consume、dispatch/execution、Package install/head/
mutation/admission 和两个所需 fence
- 两个角色都是独立非特权 LOGIN,不得 `SUPERUSER``CREATEDB``CREATEROLE`
`REPLICATION``BYPASSRLS`,也没有 schema CREATE、owner 或 DELETE authority。
`pg-0023-plugin-package-management-quota` 又将 capability 推进至 v22,只增加
`plugin_package_management_quota_buckets`。该表仅允许 `ql3_package_manager`
SELECT/INSERT/UPDATEadmin、executor、runtime 与 worker-ingress 均为零权限。
`pg-0024-plugin-package-identity-keyset-ledger` 继续推进至 v23,增加一行有界
`plugin_package_identity_keyset_ledger`,以数据库事务固定 trust domain、
generation、active/revoked key 集合和 digest。
ADR-0151 的后续 `pg-0025-plugin-package-materialized-revisions` 已推进至 v24
新增 immutable revision 表只允许 `ql3_package_executor` SELECT/INSERT
manager/admin/runtime/worker-ingress/PUBLIC 均无权限。
Cluster recovery process 已只从
`@qinglong/cluster-postgres/package-executor` 导入连接与 readiness,并只接受
`QL3_POSTGRES_PACKAGE_EXECUTOR_*`。CloudNativePG 清单固定六个数据库角色,恢复
Job 不再投影 `ql3_admin` credential。
### 5. 有界请求、配额和低敏响应
- request body 最大 256 KiBJSON 深度、节点数、字符串和数组均使用现有 Package
contract 上限;
- 认证前只使用进程内有界并发/连接/超时 shield,避免为匿名流量访问数据库;
- 认证后以 PostgreSQL 数据库时钟、Project+subject+operation key 执行 durable
quota,多 Pod 共享同一裁决;
- mutation 必须使用 caller 提供的稳定业务 ID,但时间由认证后的 authority 生成;
- response 不回显 bearer/assertion、完整 Manifest、source locator、Registry
credential、DSN、authentication ID 或底层数据库错误。
进程内 shield 不是分布式 rate limitdurable quota 也不能取代 ingress 层容量保护。
## Package 粒度影响
本决策不创建 `cluster-package-api` 一文件包。`cluster-admin` 已拥有独立镜像、Node
engine、Kubernetes/PostgreSQL 第三方闭包和管理供应链生命周期;新的 transport 是
同一部署域内的显式子路径。真正需要拆分的是运行时 credential、数据库 GRANT、
ServiceAccount 和 process,而不是再增加 workspace importer。
## 验证门禁
1. single-factor User 和 service principal 都不能 decide
2. 同一 User propose+decide 在数据库 mutation 前拒绝;
3. 两名强认证 User 可完成 propose+decide,且 body 中不存在 principal
4. 公开路由不存在 consume/dispatch,伪造 system consumer 失败;
5. manager role 无 installation/recovery/Kubernetes authorityexecutor role 无公开
management route
6. 多 Pod durable quota 使用数据库时间保持一致,COMMIT response loss 可重放;
7. 256 KiB body、并发、超时、低敏错误和 audit 门通过;
8. manager/executor role readiness、未知 GRANT 拒绝和 PostgreSQL HA promotion 后
重新连接门通过;
9. management Kubernetes overlay 不挂载 Registry credentialRoleBinding 不含
ConfigMap/Secret 写权限;
10. workspace importer 仍为 21cluster-control/edge/worker 制品闭包不变化。
当前已经通过第 1、3、4、5、6、7、8、9、10 项的适用子集:
- 专用 assertion 已验证 EdDSA、ES256、RS256,固定 issuer/audience/purpose、
ACR+AMR、短 lifetime 与 key-bound algorithm;签名篡改、unknown key、通用 JWT、
weak RSA、额外 claim/header、过期/未来 token、弱 assurance、非 User 与空
principal 都在 service 访问前失败;
- 公开 command union 不包含 consume/dispatch,未知 operation 在认证前失败;
- command body 不能携带 principal 或 authority timeproposal 半提交恢复复用
durable `createdAtMs`exact decision replay 不重复 mutation
- 结果不回显完整 manifest、source locator、Secret permission 或 authentication ID
- v24 migration、manager/executor exact readiness、旧 admin Package 权限否定、
六角色 CloudNativePG 部署审计和 executor-only recovery binding 已通过;
- PostgreSQL 18.4 physical streaming fixture 已在原 primary 和 promotion 后的新
primary 分别用 manager/executor credential 重新连接并通过 readiness;同一门还继续
通过 fencing、`pg_rewind`、双控制副本恢复与既有 COMMIT-response-loss 矩阵。
- bounded keyset 已通过 overlap/revoke、rollback/rewrite、implicit removal、
append-only revocation、malformed/private/oversized 与 no-stale-fallback 门;
- TLS 1.3 HTTPS host 默认 body 64 KiB、硬上限 256 KiB,并通过 auth-before-body、
peer/global shield、并发、keyset unavailable、readiness withdraw 与 drain 门;
- management operation 固定双副本、零 ServiceAccount token/RBAC、独立 TLS/
keyset/CA 投影、manager-only CloudNativePG credential、HTTPS probe、NetworkPolicy
与 fail-closed admin image digest;两个 Kustomize 层均可实际 render。
- durable quota 使用数据库 `clock_timestamp()` 和单语句 UPSERT;同一 window 的
receipt 与 count 共同行锁、最多 1000 项。PostgreSQL 18.4 HA fixture 已用两个独立
manager 实例并发 16 个请求,精确 8 allow/8 rejectexact replay 不重复计数,
autocommit response loss 后回读仍为 1,数据库时钟窗口可重置。
- durable keyset ledger 已以两个 manager 实例验证并发同代观察、全新 repository
重启后的旧代拒绝、同代 rewrite/隐式移除拒绝,以及 COMMIT response-loss 后
generation 3 精确收敛。
第 2、3 的真实双 User/实际 IdP 部分,以及第 7、9 项的真实双
Pod/ingress/rotation live evidence仍未完成。
## 后续
- 取得真实双 User、双 Pod、ingress/rotation 和权限否定证据;
- 在管理入口稳定后再实现 UIUI 不复制 Policy/Approval 协议。