Files
qinglong/docs/adr/ADR-0191-private-cluster-plugin-package-management-client.md
T

139 lines
5.9 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-0191:私有 Cluster Plugin Package 管理客户端
- 状态:Accepted
- 日期:2026-07-29
- 关联:RFC D-140、D-144、D-145、D-175、D-178、D-180、D-181
ADR-0144、ADR-0145、ADR-0185、ADR-0188、ADR-0190
## 背景
Cluster 已有独立、默认关闭的 Plugin Package management HTTPS process,服务端具备
TLS 1.3、强 User assertion、Project Policy、durable quota、Approval 与低敏响应。
`ql3-plugin-package-manage` 只是该服务端进程入口;现有调用端仅是 release live-evidence
脚本,不是可交付的日常 operator CLI。
因此 D-180 虽已完成数据库与 transport 能力,部署者仍需要自行拼 HTTP header、JSON 和
TLS 参数。直接建议 `curl` 会让 assertion 进入 shell history/process argv,并容易关闭
证书验证或把完整错误响应写入日志。
## 决策
### 1. 新增 client binary,不复用 server binary
在既有 `@qinglong/cluster-admin` 内新增:
- `./plugin-package-management-client` library subpath
- `ql3-plugin-package-client` executable。
不新增 workspace package、第三方生产依赖、数据库角色、Service、listener、timer、
watcher 或 controller。server 的 `ql3-plugin-package-manage` 名称和启动语义保持不变,
避免一个 binary 同时承担入站 authority 与出站 client。
### 2. 私有文件是唯一 credential/command 输入
CLI 只接受三个非秘密路径参数:
- `--config=/absolute/client.json`
- `--command=/absolute/command.json`
- `--assertion=/absolute/assertion.jwt`
禁止从 argv、环境变量、stdin 或 command JSON 接收 assertion、Bearer token、私钥、
数据库 DSN 或 CA 内容。
config、command、assertion 必须是当前 POSIX UID 拥有、规范绝对路径、非 symlink、
`0600` regular file,并通过 `lstat → O_NOFOLLOW open → fstat` 在同一 descriptor
读取。config/assertion 最大 16 KiBcommand 最大 256 KiB。CA 是公开验证材料,但仍须
是规范、非 symlink、owner 为当前 UID 或 root、group/world 不可写的 regular file
最大 256 KiB。
config schema v1 精确包含:
- `endpoint`:固定 `/api/v3/plugin-packages/management` 的 HTTPS URL
- `servername`:显式 DNS 名,必须等于 URL hostname
- `caFile`:绝对 CA bundle 路径;
- `requestTimeoutMs`130 秒。
不读取 `HTTP_PROXY``HTTPS_PROXY``NO_PROXY` 或系统代理。
### 3. 一次进程只执行一个 exact command
command 必须是 management transport 已公开的 schema v1 commandoperation 只能是:
- Package install `propose|decide|inspect`
- publisher emergency revocation `propose|decide|inspect`
- publisher trust transition `propose|decide|inspect`
客户端不补 ID、不改 expected version、不派生 digest、不上传 PEM/snapshot,也不自动
重试。网络结果不确定时,operator 必须用原 command 文件显式重放;服务端 exact replay
负责收敛。
### 4. TLS 与 HTTP 严格失败关闭
client 固定:
- TLS 1.3 min/max
- `rejectUnauthorized=true`
- endpoint hostname 与显式 `servername` 一致;
- CA bundle 显式注入;
- 无 redirect、无 connection pooling、无压缩、单一 POST
- request/response 各 256/128 KiB 硬上限;
- exact `application/json` request 与
`application/json; charset=utf-8` response
- bounded timeout,超时销毁 socket。
成功响应必须是 exact schema v1 envelope、带有 bounded request ID,且 result operation
与 command operation 完全一致。非 200 响应只保留 status、bounded error code、
request ID 和可选 Retry-After;不回显 response body、header、assertion、路径或 TLS
diagnostic。
### 5. 输出保持低敏
stdout 只输出服务端已经审查过的低敏 result envelope。stderr 失败事实只包含稳定
component/event/error code、可选 HTTP status/request ID/retry-after;不输出 Error
message、stack、文件路径、endpoint、assertion、command 原文或证书内容。
客户端在请求结束后清零可变 assertion/CA/command Buffer。Node.js/HTTP 内部可能产生
不可控复制,因此本能力不声称 secure enclave 或零内存残留;短生命周期进程和不落盘/
不回显是当前边界。
## 不采用方案
### 用 curl 文档代替产品 client
Bearer 参数容易进入 shell history/process argvTLS/redirect/response 上限也无法被
仓库门禁稳定约束。
### client 自行持有 IdP 私钥并签 assertion
会把身份签发 authority 混入 Package 管理客户端;本 CLI 只消费外部 ceremony 产生的
短期 assertion。
### 把 client 合入 cluster-control
常驻 runtime 不应获得管理 assertion 或出站管理 authority。
### 新增独立 workspace package
客户端与现有 management protocol 同发布、无新依赖或独立制品矩阵;新增第 23 个包不满足
ADR-0185。
### 自动重试
网络断开不能证明服务端未提交。自动重试会隐藏 outcome unknown;显式 exact replay 才是
可审计恢复。
## 验收证据
- `@qinglong/cluster-admin/plugin-package-management-client`
`ql3-plugin-package-client` 已发布在既有 cluster-admin 包,workspace 仍为 22 包,
未新增第三方生产依赖、listener、timer、watcher 或 controller。
- client 专项 5/5 通过:真实 TLS 1.3 + CA + DNS hostname、one request、九种 operation、
unknown operation、private/canonical/no-follow 文件、redirect、content-type、128 KiB
response、timeout 与 CLI 输出脱敏均有正负向证据。
- cluster-admin 全量回归为 121 pass、0 fail、1 条真实 Kubernetes 条件 skip;构建闭包
同时编译 runtime-core、cluster-postgres 与 cluster-admin。
- cluster deployment audit 18/18dependency boundary 37/3722 个 package importer、
31 个 cluster-admin source、CloudNativePG 与 edge-import 审计均无 finding。
- operator 使用契约见
`docs/operations/ql3-plugin-package-management-client.md`