mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-20 16:07:11 +08:00
feat(ql3): add direct Vault KV worker secret custody
This commit is contained in:
@@ -11,6 +11,8 @@
|
||||
|
||||
最新增量证据(2026-08-24):
|
||||
|
||||
- D-404/ADR-0499(已验收):Cluster Worker 现在有可选的直接外部 Secret custody adapter,而不再只能依赖 Kubernetes Secret value projection。`vault-kv-v2` 位于既有 `@qinglong/cluster-control` Remote Execution 子域,只有显式选择 provider 的 Cluster 进程才动态加载;基础部署继续使用 `mounted-files`,Edge/Standalone 不新增 package、依赖、daemon、timer、watcher、连接池或常驻内存。adapter 只在 durable Run/Attempt/Lease/Worker Session/execution digest/SecretRef authority 通过后,用 `SHA-256(canonical SecretRef)` 路径读取 KV v2;只接受显式私有 CA 的 TLS 1.3、每次重新打开的短期 orphan/non-renewable service token 和唯一精确 policy,不跟随 redirect、不使用系统 CA 回退、不缓存值或 token。Kubernetes overlay 删除 value Secret projection,只挂载 CA 与 token;普通 Secret、opaque environment bundle 和总响应仍受原 16/96/256 KiB 边界约束,空 Secret 保持合法,异常 envelope、metadata、digest、token、TLS 或 Vault availability 均失败关闭且不回退。真实 arm64 Vault 1.21.4 gate 已完成 3-share/2-threshold init、两个普通 Secret 与一个 bundle、value/token 原子轮换、旧 accessor revoke、缺失 material、不可信 CA、seal/unseal 与同持久存储容器替换;`0600` content-free 报告 SHA-256 为 `df225509cb763009b610cb0aea2207e0b07b5e05a44cf8cf0dff1633c1624d52`,audit 为 `compatible=true/findings=[]`。Cluster Control 为 `279 total / 277 pass / 2 conditional skip / 0 fail`,backend 为 `1574 total / 1572 pass / 2 conditional skip / 0 fail`,18-package clean build/test 退出 0;package、Cluster dependency、122-module Edge import、部署和 14 档 Local artifact 审计全部 compatible,基础 Edge/Standalone 仍为 `2,669,390 / 2,669,468 bytes`、325 files、58 modules。共享 CI 新增原生 x64/arm64 live matrix。该 fixture 关闭 QingLong 直接 custody adapter/data-boundary 门,不冒充生产 Vault HA、KMS/HSM seal、审计设备或灾备证明;ADR-0491 现在只剩固定低性能物理 Edge 的真实空间、RSS/I/O、写放大、ENOSPC 与断电恢复门。
|
||||
|
||||
- D-397/ADR-0491(进行中):Secret/Config reconciliation 已先冻结行为保持边界,不能把“密文已保存”冒充“任务已迁移”。2.x `Envs`
|
||||
的 active 行必须按 `isPinned DESC、position DESC、createdAt ASC、id ASC` 重放旧顺序,同名值用 `&` 形成唯一 effective Secret;该
|
||||
Secret 后续必须在同一事务中绑定到经 Automation adoption ledger 证明的全部 Legacy Task 新修订,并同步追加指向新 Task revision 的 Trigger/dispatch
|
||||
@@ -87,8 +89,7 @@
|
||||
因而不重跑且不重新占有 PostgreSQL HA 证明;相邻已通过的 remote CI/HA 只作为基线。
|
||||
|
||||
D-385~D-388 的 `config.sh`/Keyv/SSH data-directory lineage 与 SQLite `Envs` 保持分离;当前无稳定生产 schema 的历史 `Configs` 表继续 sealed+manual,
|
||||
不猜字段。ADR-0494 已关闭基础 Cluster mounted-files provider live 子门;后续切片仍必须完成固定低性能设备的真实 Edge 空间/写放大/断电证据,
|
||||
以及 Cluster Legacy Env migration 的专用 PostgreSQL SERIALIZABLE ledger、Task/Trigger revision mutation 与直接外部 custody adapter。HA promotion 后 receipt replay 已由 D-403/ADR-0498 关闭。D-397 apply
|
||||
不猜字段。ADR-0494 已关闭基础 Cluster mounted-files provider live 子门,ADR-0495~ADR-0498 已关闭 Cluster plan/application/HA replay,ADR-0499 已关闭直接 Vault KV 外部 custody adapter;后续仍必须完成固定低性能设备的真实 Edge 空间、RSS/I/O、写放大、ENOSPC 与断电证据。D-397 apply
|
||||
只声明 sealed source retained 且 `physicalErasureGuaranteed=false`;明文销毁必须在 restart/
|
||||
readiness、观察窗和 rollback retention 之后另行强认证。Cluster 必须使用 PostgreSQL SERIALIZABLE ledger、外部 KMS/Secret provider 与 HA evidence,
|
||||
不复用 Local SQLite/POSIX authority,也不得把明文写入 PostgreSQL、ConfigMap、Pod env 或 Job command。
|
||||
@@ -174,8 +175,8 @@
|
||||
`a7c8a05e08c748d677475a09ce2998b741ed9326e27678613e93d431bc3769aa`;
|
||||
真实用例覆盖 Trigger 固定 Task r1、Task current r2、原子生成 Task r3/Trigger r2 并重定向 pin,
|
||||
同时证明 bundle ref-only execution、schedule reset、无流消费 replay 与数据库角色隔离。D-402
|
||||
关闭 mutation/receipt 边界;相邻 D-403 已继续关闭 promotion 后 receipt replay,direct external
|
||||
custody 与固定低性能 Edge 物理证据仍是 ADR-0491 转 Accepted 前的门禁。
|
||||
关闭 mutation/receipt 边界;相邻 D-403 已继续关闭 promotion 后 receipt replay,D-404/ADR-0499 已关闭 direct external
|
||||
custody adapter;固定低性能 Edge 物理证据是 ADR-0491 转 Accepted 前唯一剩余门禁。
|
||||
|
||||
- D-403/ADR-0498(已验收):ADR-0497 application receipt 已进入真实 PostgreSQL 18 physical HA
|
||||
领域门,而不是继续引用通用表存活作为间接证据。主库与 standby 达到
|
||||
@@ -199,8 +200,8 @@
|
||||
`1569 total / 1567 pass / 2 conditional skip / 0 fail`,四项 package/依赖/import 边界均 compatible。
|
||||
基础 Edge/Standalone 仍只包含 Local SQLite、runtime-core 与 SemVer,均为 325 files/58 modules,
|
||||
大小 `2,669,390 / 2,669,468 bytes`,距 4 MiB 上限保留 `1,524,914 / 1,524,836 bytes`;它只证明
|
||||
常驻闭包未扩大,不冒充真实设备证据。D-403 关闭 promotion replay;ADR-0491 现在只剩 direct
|
||||
external custody 与固定低性能 Edge 空间/写放大/断电恢复两项硬门。
|
||||
常驻闭包未扩大,不冒充真实设备证据。D-403 关闭 promotion replay,D-404/ADR-0499 关闭 direct
|
||||
external custody adapter;ADR-0491 现在只剩固定低性能 Edge 空间、RSS/I/O、写放大、ENOSPC 与断电恢复硬门。
|
||||
|
||||
- D-396/ADR-0490(已验收):Run History 不再只有永久 `manual_external`,但也没有被错误实现为 Legacy 日志到 3.0 Run ledger 的回灌。
|
||||
新的 Local adapter 以 ADR-0482 sealed capture bundle 作为 append-only 保全资产:Legacy history 必须逐事实选择 `retain_both`,Target history
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# ADR-0491:有界 Secret/Config Reconciliation 与任务环境绑定
|
||||
|
||||
- 状态:Proposed(D-397 已实现 Legacy Env inspection、私有有界 row plan、durable plan publication、独立 signed decision、逐项 Automation adoption provenance、Local SQLite 原子 application publisher、Owner prepared/apply/rollback 编排、ADR-0492 completion v3;ADR-0494 完成 Cluster mounted-files provider live 子门,ADR-0495 完成 content-free Cluster plan ledger,ADR-0496 完成 opaque environment bundle 数据面,ADR-0497 完成 Cluster Task/Trigger 原子 mutation 与 receipt,ADR-0498 完成 promotion 后 exact replay;真实 Edge 空间证据与直接外部 custody gate 尚未完成)
|
||||
- 状态:Proposed(D-397 已实现 Legacy Env inspection、私有有界 row plan、durable plan publication、独立 signed decision、逐项 Automation adoption provenance、Local SQLite 原子 application publisher、Owner prepared/apply/rollback 编排、ADR-0492 completion v3;ADR-0494 完成 Cluster mounted-files provider live 子门,ADR-0495 完成 content-free Cluster plan ledger,ADR-0496 完成 opaque environment bundle 数据面,ADR-0497 完成 Cluster Task/Trigger 原子 mutation 与 receipt,ADR-0498 完成 promotion 后 exact replay,ADR-0499 完成直接 Vault KV 外部 custody adapter;仅固定物理 Edge 证据尚未完成)
|
||||
- 日期:2026-08-23
|
||||
- 决策:D-397
|
||||
- 关联:ADR-0073、ADR-0074、ADR-0092、ADR-0094、ADR-0480、ADR-0482、ADR-0483、ADR-0484、ADR-0485、ADR-0486、ADR-0487、ADR-0488、ADR-0490、ADR-0495、ADR-0496、ADR-0497、ADR-0498
|
||||
- 关联:ADR-0073、ADR-0074、ADR-0092、ADR-0094、ADR-0480、ADR-0482、ADR-0483、ADR-0484、ADR-0485、ADR-0486、ADR-0487、ADR-0488、ADR-0490、ADR-0495、ADR-0496、ADR-0497、ADR-0498、ADR-0499
|
||||
|
||||
## 背景
|
||||
|
||||
@@ -147,4 +147,4 @@ D-397 当前八切片已经实现:absent、unsupported、Edge over-budget、2.
|
||||
|
||||
ADR-0494 已完成 Cluster `mounted-files` provider live 子门:真实三节点 K3s 中两个 management replica、direct exact-key executor 和两个跨节点 provider observer 完成 PostgreSQL durable approval/binding、Kubernetes atomic projection rotation、无 Secret API 权限/ServiceAccount token、只读 `0440`、内容脱敏及删除后 fail-closed;v2 私有报告 24/24 gates 为 true,并保持 v1 verifier 兼容。该门不增加 Edge 闭包,也不等于直接 Vault/KMS/HSM custody。
|
||||
|
||||
转为 Accepted 前仍必须完成:固定低性能 Edge 设备的真实空间/写放大/断电恢复证据,以及直接外部 custody adapter。ADR-0495 已完成专用 PostgreSQL plan ledger,ADR-0496 已完成只保存 pinned bundle ref、通过 fenced remote delivery 取回 typed carrier 并在 Worker 内存展开的数据面;ADR-0497 又在一个 Project-serialized SERIALIZABLE transaction 中完成逐项 Task/Trigger current-head revalidation、revision/execution mutation、schedule reset 和 content-free append-only receipt,并支持合法历史 Task pin。ADR-0498 已证明该首次提交在 `remote_apply` 下到达 standby,并在 timeline `1→2`、`pg_rewind` 重建同步副本后由 Automation Manager 精确重放为 `existing`,不打开 mutation stream 或增加 durable row。它仍不写入 Secret material,也不等于 direct Vault/KMS/HSM custody。ADR-0492 已完成本机 completion schema 演进和 completed-head 后 rollback material 回收,ADR-0493 又让没有 Legacy 身份输入的 fresh v52 目标身份经 signed `retain_target` 正确形成 no-effect,并精确消除六张已知目标表的 `unknown` 误判。Legacy `Auths/Users` 或真正未知表仍保持 manual;Local Owner 编排、mounted-files gate、plan/application ledger 或 HA replay 证据都不得冒充完整外部密钥托管。
|
||||
转为 Accepted 前仍必须完成固定低性能 Edge 设备的真实空间、RSS/I/O、写放大、ENOSPC 与断电恢复证据。ADR-0495 已完成专用 PostgreSQL plan ledger,ADR-0496 已完成只保存 pinned bundle ref、通过 fenced remote delivery 取回 typed carrier 并在 Worker 内存展开的数据面;ADR-0497 又在一个 Project-serialized SERIALIZABLE transaction 中完成逐项 Task/Trigger current-head revalidation、revision/execution mutation、schedule reset 和 content-free append-only receipt,并支持合法历史 Task pin。ADR-0498 已证明该首次提交在 `remote_apply` 下到达 standby,并在 timeline `1→2`、`pg_rewind` 重建同步副本后由 Automation Manager 精确重放为 `existing`,不打开 mutation stream 或增加 durable row。ADR-0499 进一步增加可选 `vault-kv-v2` provider:它只在 durable delivery authority 通过后,以 digest-derived path、显式 CA、TLS 1.3 和每次重新验证的短期最小权限 token 直接读取外部 Vault;Kubernetes overlay 不再投影真实值,本地 arm64 live gate 已覆盖 value/token rotation、revoke、seal/unseal、容器替换持久恢复与 content-free evidence。该单机 Vault fixture 只关闭 QingLong adapter/data-boundary 门,不冒充生产 Vault HA、KMS/HSM seal、审计设备或灾备证明。ADR-0492 已完成本机 completion schema 演进和 completed-head 后 rollback material 回收,ADR-0493 又让没有 Legacy 身份输入的 fresh v52 目标身份经 signed `retain_target` 正确形成 no-effect,并精确消除六张已知目标表的 `unknown` 误判。Legacy `Auths/Users` 或真正未知表仍保持 manual。
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
# ADR-0499:直接 Vault KV Worker Secret 外部托管
|
||||
|
||||
- 状态:Accepted
|
||||
- 日期:2026-08-24
|
||||
- 决策:D-404
|
||||
- 关联:ADR-0058、ADR-0114、ADR-0233、ADR-0491、ADR-0494、ADR-0496、ADR-0497、ADR-0498
|
||||
|
||||
## 背景
|
||||
|
||||
ADR-0494 已证明 `mounted-files` provider 可以在 Kubernetes atomic projection 轮换后无重启读取新值,并且 Worker ingress 不需要 Secret API 权限。但该模式仍由 Kubernetes Secret 保存真实值,不能满足要求控制面只持有短期访问能力、密钥材料始终由外部托管系统保管的部署。
|
||||
|
||||
QingLong 3.0 需要一个可选的直接外部 custody adapter,同时保持小型 Edge/Standalone 默认闭包不变,也不能把 Vault token、Secret 值、Legacy Env 名称或 provider 路径写入 PostgreSQL、Pod environment、公开 evidence 或日志。
|
||||
|
||||
## 决策
|
||||
|
||||
### 1. Provider 边界
|
||||
|
||||
在既有 `@qinglong/cluster-control` Remote Execution 子域中增加 `vault-kv-v2` provider,不新建 workspace package。基础 Kubernetes 部署继续默认使用 `mounted-files`;只有显式选择 `QL3_WORKER_SECRET_PROVIDER=vault-kv-v2` 的 Cluster overlay 才加载该实现。Edge/Standalone 不导入 Cluster Control,因此其制品、常驻内存和依赖树不增加 Vault 客户端。
|
||||
|
||||
provider 只在 durable Worker delivery authority 已经通过 Run、Attempt、Lease、Session、execution digest 和精确 SecretRef 集合校验后执行。每个路径由 `SHA-256(canonical SecretRef)` 推导,不把 SecretRef 或环境变量名放入 URL。普通 Secret 与 opaque environment bundle 继续分别服从 16 KiB、96 KiB 和总交付上限。
|
||||
|
||||
### 2. 传输与身份
|
||||
|
||||
实现只接受无凭据、无 path/query/fragment 的 `https://` authority,使用显式投影 CA,并要求协商 TLS 1.3;不跟随 redirect,不使用系统 CA 回退。控制 Pod 只投影 CA 和短期 token,不投影真实 Secret 值,也不挂载 ServiceAccount token。
|
||||
|
||||
token 必须同时满足:
|
||||
|
||||
- orphan、non-renewable、service token;
|
||||
- 只含一个精确配置的读取 policy;
|
||||
- 剩余 TTL 大于 0 且不超过配置上限,部署默认上限为 900 秒;
|
||||
- 每次 `verify` 或 `resolve` 都重新打开投影文件并调用 `auth/token/lookup-self`。
|
||||
|
||||
实现没有 cache、watcher、timer、renewal loop 或后台连接。token 轮换由外部部署 authority 原子替换投影文件;旧 token 的撤销与新 token 的签发不由 QingLong 接管。Vault 不可达、封存、CA 不可信、token 过宽/过期或材料缺失时交付失败关闭,不回退到 `mounted-files`。
|
||||
|
||||
### 3. KV v2 数据合同
|
||||
|
||||
每个值固定存放在:
|
||||
|
||||
```text
|
||||
<mount>/data/<prefix>/<sha256(canonical SecretRef)>
|
||||
```
|
||||
|
||||
KV payload 必须是 exact shape:
|
||||
|
||||
```json
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"secretRefDigest": "<same 64-hex digest>",
|
||||
"encoding": "base64",
|
||||
"value": "<canonical base64>"
|
||||
}
|
||||
```
|
||||
|
||||
KV metadata 必须表明 version 为正整数、未删除且未销毁。空 Secret 是合法的 canonical base64;超限、非 canonical 编码、digest 不一致、未知字段或异常 metadata 均失败关闭。成功 material 在调用方 `dispose()` 时清零;报告和错误只暴露有界分类,不包含 endpoint path、token、SecretRef 或 value。
|
||||
|
||||
### 4. Kubernetes 部署
|
||||
|
||||
`deploy/kubernetes/ql3-cluster/vault-kv-worker-secret` overlay 删除基础部署的 value Secret env/mount/volume,只增加私有 CA 与短期 token 投影。示例文件只含占位符,仓库不保存可用 credential。
|
||||
|
||||
Vault policy 固定为:
|
||||
|
||||
```hcl
|
||||
path "worker-secrets/data/values/production/*" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
|
||||
path "auth/token/lookup-self" {
|
||||
capabilities = ["read"]
|
||||
}
|
||||
```
|
||||
|
||||
外部 Vault 的 HA、unseal、KMS/HSM seal、审计设备、备份和灾备属于部署方独立门禁。本 ADR 证明 QingLong 的直接 custody 数据边界,不把单机 Vault file storage fixture 冒充生产 Vault HA。
|
||||
|
||||
## 被拒绝的替代方案
|
||||
|
||||
### 在 PostgreSQL 或 ConfigMap 保存密文
|
||||
|
||||
拒绝。即使值已加密,也会扩大数据库/配置平面的 custody、备份和读取权限,并把轮换与数据库生命周期绑定。
|
||||
|
||||
### 给控制 Pod Kubernetes Secret API 权限
|
||||
|
||||
拒绝。它扩大为 namespace 级读取能力,无法把访问限制到 durable delivery authority 中的精确引用。
|
||||
|
||||
### 引入 Vault SDK、Agent sidecar 或常驻续租器作为必选依赖
|
||||
|
||||
拒绝。直接 HTTPS adapter 已能满足有界请求;额外 SDK 或 sidecar 会扩大依赖、镜像、常驻内存和凭据生命周期。部署方可以负责 token projection,但不得通过该机制把真实值重新投影进 Pod。
|
||||
|
||||
## 验证
|
||||
|
||||
真实 arm64 live contract 使用 digest-pinned Vault 1.21.4、私有 TLS CA、3-share/2-threshold 初始化和短期 orphan token,完成两个普通 Secret 与一个 opaque environment bundle 的读取,并证明:
|
||||
|
||||
- value 轮换和 token 原子轮换均无需重启;
|
||||
- 旧 token accessor 撤销后不再可用;
|
||||
- 缺失 material、不可信 CA 和 sealed Vault 均失败关闭;
|
||||
- unseal 后恢复,Vault 容器在同一持久存储上替换后值仍可读取;
|
||||
- 私有 `0600` 报告不含 token、SecretRef、value、证书私钥或 Vault path。
|
||||
|
||||
最终本地报告 SHA-256 为 `df225509cb763009b610cb0aea2207e0b07b5e05a44cf8cf0dff1633c1624d52`,离线 audit 为 `compatible=true`、`findings=[]`。共享 CI 在原生 x64/arm64 runner 上分别构建 provider、审计 overlay、拉取同一 digest-pinned Vault image 并重跑完整 live contract;远程运行结果作为提交后的独立证据。
|
||||
|
||||
本地完整验证中,Cluster Control 为 `279 total / 277 pass / 2 conditional skip / 0 fail`,backend 为 `1574 total / 1572 pass / 2 conditional skip / 0 fail`,18-package clean build/test 退出 0。package boundary 保持 18 packages、`singleSourcePackages=[]`、`shallowSourcePackages=[]`;Cluster dependency、122-module Edge import、service-manager bridge、Cluster deployment、Local image、Vault overlay 和 14 档 Local artifact 均 compatible。基础 Edge/Standalone 制品仍为 `2,669,390 / 2,669,468 bytes`、325 files、58 loaded modules,不包含 Cluster Control 或 Vault adapter。
|
||||
|
||||
## 影响与剩余门禁
|
||||
|
||||
D-404 关闭 ADR-0491 的直接外部 custody adapter 门。ADR-0491 转 Accepted 前只剩固定低性能物理 Edge 的真实空间、RSS/I/O、写放大、ENOSPC 与断电恢复证据;开发机、Docker、CI runner 和 Cluster Vault live gate 均不能替代该设备证据。
|
||||
+3
-1
@@ -494,13 +494,15 @@
|
||||
| [ADR-0488](./ADR-0488-cross-domain-reconciliation-completion-fence.md) | 跨领域 Reconciliation 完成围栏与目标重启授权 | Accepted |
|
||||
| [ADR-0489](./ADR-0489-service-manager-completion-restart-lineage.md) | Service Manager 完成围栏重启谱系 | Accepted |
|
||||
| [ADR-0490](./ADR-0490-run-history-terminal-preservation.md) | Run History 终态保全与跨领域完成证明 | Accepted |
|
||||
| [ADR-0491](./ADR-0491-bounded-secret-config-reconciliation-and-task-binding.md) | 有界 Secret/Config Reconciliation 与任务环境绑定 | Proposed(D-397 local apply/rollback/completion complete;Edge/Cluster gate pending) |
|
||||
| [ADR-0491](./ADR-0491-bounded-secret-config-reconciliation-and-task-binding.md) | 有界 Secret/Config Reconciliation 与任务环境绑定 | Proposed(直接外部 custody 已完成;仅固定物理 Edge gate pending) |
|
||||
| [ADR-0492](./ADR-0492-compatible-secret-config-completion-v3.md) | 兼容 Secret/Config 的 Reconciliation Completion v3 | Accepted |
|
||||
| [ADR-0493](./ADR-0493-target-native-reconciliation-domain-preservation.md) | 目标原生 Reconciliation 域分类与身份保留 | Accepted |
|
||||
| [ADR-0494](./ADR-0494-postgresql-secret-binding-and-mounted-provider-live-rotation.md) | PostgreSQL Secret Binding 与 Mounted Provider 在线轮换门 | Accepted |
|
||||
| [ADR-0495](./ADR-0495-content-free-cluster-legacy-env-migration-plan-ledger.md) | 无敏感内容的 Cluster Legacy Env 迁移计划账本 | Accepted |
|
||||
| [ADR-0496](./ADR-0496-opaque-cluster-environment-bundle-delivery.md) | Cluster 不透明环境 Bundle 的有界交付与 Worker 内存展开 | Accepted |
|
||||
| [ADR-0497](./ADR-0497-atomic-cluster-legacy-env-migration-application.md) | Cluster Legacy Env 的原子 Task/Trigger 迁移与只追加回执 | Accepted |
|
||||
| [ADR-0498](./ADR-0498-cluster-legacy-env-application-ha-replay.md) | Cluster Legacy Env Application 的 HA Promotion 后精确重放 | Accepted |
|
||||
| [ADR-0499](./ADR-0499-direct-vault-kv-worker-secret-custody.md) | 直接 Vault KV Worker Secret 外部托管 | Accepted |
|
||||
|
||||
## 规则
|
||||
|
||||
|
||||
Reference in New Issue
Block a user