8.7 KiB
ADR-0265:有预算的一次性 Model Provider Credential Test Connection
- 状态:Accepted
- 日期:2026-08-03
- 关联:RFC D-08、D-12、D-159、D-175;ADR-0169、ADR-0263、ADR-0264
背景
Provider credential 的 bind/revoke ceremony 已有独立 manager,但“测试连接”若直接放进 manager,会迫使常驻管理进程同时持有 Provider Secret 与任意外网访问能力;若只由客户端传 URL、 deadline 或 retry,又会成为 SSRF、费用放大和绕过部署网络策略的入口。低配路由设备不应为一个 偶发操作长期支付 listener、连接池、timer 或 AI provider 依赖;Cluster 则需要 durable quota、 崩溃后不重复请求 provider、同步复制和晋升后的明确结果。
决策
1. Manager 只签发计划,不接触 Secret 或 Provider 网络
公开操作固定为 provider-credential.test.plan。请求只接受 requestId/testId/projectId/provider,
principal 由 transport 注入;endpoint、adapter、deadline、response/model/cost/retry 预算全部从
server-owned exact allowlist 解析。manager 要求五分钟内的 strong User、secret.manage 和当前
Project/RoleBinding fence,在一个 SERIALIZABLE transaction 内消费 durable quota、写 immutable plan
和 allowed SecurityAudit。相同业务 identity 与相同 lifetime 的晚到 API retry 返回原始 plan,不重复
消费 quota;调用方不能提交 URL、SecretRef、deadline、budget 或 retry。
allowlist 是不含 Secret 的 ConfigMap,单文件不超过 64 KiB、最多 16 个 provider。endpoint 只允许 canonical HTTPS,deadline 1–15 秒、response 1–256 KiB、models 1–256、费用固定为零、retry 固定为零; plan 最长存活五分钟。manager Deployment 继续不挂 Provider Secret,base NetworkPolicy 继续没有 Provider egress。
2. Provider authority 只存在于 caller-driven one-shot tester
新增能力仍留在既有 @qinglong/ai、@qinglong/cluster-admin 和
@qinglong/cluster-postgres 的显式 subpath,不新增 workspace package。tester 只接受 exact
executionId/testId/allowlist command,使用专用 ql3_ai_credential_tester PostgreSQL role 和
maxConnections=1:
- 先提交 immutable execution intent;
- 只有
status=created才在同一个 one-shot Pod 内执行不带 credential 的 CNI 收敛屏障:exact provider TCP 必须可达,同时 deny-canary(Cluster 使用 Kubernetes API Service)必须不可达;两者共用 原始 deadline,不重试 Provider API; - 屏障成立后才逐请求解析 current binding、读取一个 Project-bound projected Secret,并在 Provider 请求前提交 content-free credential-use audit;
- 对计划中的
/models只执行一次 GET; - 只持久化
reachable|unreachable、model count、duration 与 digest,不保存 endpoint response、 SecretRef、token/header 或 raw error; - completion 暂时不可用时只重试同一个结果写入一次,绝不重打 provider。
已有 intent 但无 result 表示 outcome_unknown,必须停止且不得网络重放;已有 result 返回 exact
existing。deadline 使用 AbortSignal 和 monotonic clock 双围栏;超时、provider error、响应超限或
model 超限统一保存 content-free unreachable。
3. PostgreSQL 与部署权限分离
pg-9015 新增 plan/quota/execution/result 四张表。manager 只能写 plan/quota/allowed audit,tester
只能读 plan/current binding、append execution/result/use audit;tester 不能读写 quota、SecurityAudit、
Prompt output、invocation、price、Package、Worker、admin、maintenance 或 migration authority,也没有
ql3 schema USAGE。readiness 对拒绝权限使用 pg_catalog OID 检查,不能为让自检通过而扩权。
Kubernetes tester 是 opt-in、caller-driven Job:backoffLimit=0、activeDeadlineSeconds=60、
ttlSecondsAfterFinished=300、tokenless ServiceAccount、non-root/read-only/drop ALL,request 为
25m CPU/48 MiB、limit 为 500m/192 MiB。base 只有 DNS egress,因此故意不能访问 provider;
CloudNativePG overlay 只增加 tester role 的 PostgreSQL 5432,部署者再以私有 overlay 为 exact private
provider /32:443 放行。标准 NetworkPolicy 不能表达 FQDN,故应用 exact HTTPS allowlist 与部署 CIDR
必须同时成立;公网 SaaS 需要 CNI FQDN policy 或受审 egress proxy,不能静默放宽 0.0.0.0/0。
4. Edge/Standalone 保持零常驻成本
本 ADR 不把 Cluster manager/tester、pg、Kubernetes client、listener 或 pool 带入 Edge/Standalone。
低配设备若后续需要同等产品入口,应复用短生命周期本机 Owner/SQLite ceremony 和 AI feature gate;
不得为了 API 对称启动常驻 daemon。Cluster 可由 Job 横向处理不同请求,但每个 test 仍是唯一 intent、
零 provider retry;不能把副本数变成隐式 provider 重试。
被否决方案
- 让 manager 直接测试:合并身份管理、Secret read 和任意 provider egress 三种 authority。
- 客户端直接传 URL/预算:打开 SSRF、长连接、响应放大和费用绕过。
- 已有 intent 自动重打 provider:COMMIT 响应丢失时会产生重复外部副作用和费用。
- 按 provider 建 workspace package:只有少量协议/adapter 文件,没有新的独立交付或依赖反转价值。
- base NetworkPolicy 放行公网 443:无法证明流量只去 allowlist hostname。
- 给 tester
ql3schema USAGE 以通过 readiness:扩大实际 authority,并掩盖拒绝权限探针缺陷。
当前验证
- AI 全量 176 项:173 通过、3 条条件跳过、0 失败;Cluster Admin 全量 242 项:240 通过、 2 条条件跳过、0 失败;plan/execution PostgreSQL 定向 9/9;
- manager service/transport/client/process、executor/process/CLI、Kustomize base/CNPG、manager/tester/ CloudNativePG/dependency audit 均通过;workspace 仍为 19,没有为 test connection 新增 package;
- PostgreSQL 18.4 arm64 physical HA 实际使用
ql3_ai_credential_tester单连接池,证明 plan/execution exact replay、provider 调用恰好一次、Secret material 清零一次、completion COMMIT 已提交但响应 丢失后以同结果收敛、四类 durable fact 无 Secret、remote_apply同步 WAL、timeline 1→2 晋升后 facts/readiness 完全一致;新增五个具体 gate 和总gates.passed=true; - HA 运行后
ql3-ha-*容器、网络、卷零残留,既有ql3-cnpg-evidence-control-plane容器保持运行且未被操作。 - 显式 opt-in 的真实三节点 K3s/arm64 纵切面使用锁定的 K3s
v1.34.3+k3s1、CloudNativePG1.30.0与 PostgreSQL18.4,三个 PostgreSQL 实例分别预绑定到两个 worker 和唯一 control-plane; 初始主库固定在 worker A,停止该 worker 后 primary 成功切换,worker 恢复后数据库回到 3/3 Ready, 唯一 control-plane 始终在线; - 纵切面真实执行 8 个 one-shot Job(7 个 execution、1 个 exact replay),证明 projected Secret
material generation 1→2、旧 material 拒绝、新 Pod 重解析、Provider Pod/CIDR 轮换、旧 CIDR
fail-close、exact private
/32:8443、DNS/CloudNativePG allow 与 Kubernetes API/公网 deny。CNI 在新 Pod 创建后存在短暂策略编程窗口,因此 tester 现在必须在 Secret/binding/audit 前同时证明 Provider allow 与 Kubernetes API deny,不能以另一个预检 Pod 代替; - 最终 content-free 报告为
gates.passed=true:7 plan/execution/result、7 plan audit、5 次实际到达 credential-use 阶段的 use audit、4 reachable、3 unreachable、5 次 Provider/models请求、零 replay duplicate,并在 CloudNativePG failover 后完整存活;报告审计和部署审计均无 finding; - Docker K3s 的本地
imagePullPolicy: Never镜像会在节点重启或 containerd GC 后消失,测试夹具在 节点恢复后重新导入 exact 本地 admin image,再执行全节点收敛。这是离线测试制品恢复,不是生产 Provider 或数据库重试。成功运行后随机 K3s 容器、网络、卷和测试镜像零残留,受保护的既有 evidence control-plane 未被操作。
剩余生产证据与边界
本 ADR 的私有 Provider test-connection 接受门已经关闭,但该 Docker 夹具使用 privileged K3s、
fixture-only prebound hostPath、单个 Docker host 和唯一 Kubernetes control-plane;它不能冒充动态 CSI、
基础设施 STONITH、control-plane HA 或跨故障域证据。确定性私有 HTTPS Provider 也不是外部 SaaS。
公网 SaaS 仍必须选择并验证 CNI FQDN policy 或 egress proxy,不能复用私网 /32 结论;真实外部
OIDC/mTLS、KMS/Vault/HSM custody、首次 provision/active rotation/lost-secret recovery 继续由后续
ADR 和发布门负责。