Files
pikasTech-agentrun/docs/reference/spec-v01-secret-distribution.md
T
2026-06-09 23:42:26 +08:00

229 lines
20 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.
# v0.1 Secret 与 provider credential 分发规格
本文定义 AgentRun `v0.1` 的 Secret 和 Code Agent provider credential 分发边界。真实 Code Agent backend 需要上游模型凭据;Codex stdio profile 测试凭据以 `~/.codex/auth.json``~/.codex/config.toml` 和必要的 profile-local model catalog 形态为输入源,通过 Kubernetes Secret 投影进入 runner/backend Pod。这些值不得进入 Git source、GitOps branch、artifact catalog、event、trace、日志或 CLI 输出。
在装配 SPEC 中,本文承担 SecretRef、projection、rotation 和 redaction 规则;运行时 credential 必须先归入 `ProfileRef``ResourceBundleRef.credentialRef``executionPolicy.secretScope.toolCredentials[]`,再由 runner Job 装配。权威装配模型见 [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md)。
## 设计目标
- API Key、Codex auth/config 等 provider credential 只通过 Kubernetes SecretRef 分发到需要它的 manager、runner 或 backend adapter。
- `deploy/deploy.json` 只记录 SecretRef 名称、key 名称、mount/env intent 和 secret scope,不记录 Secret 值。
- `v0.1-gitops` 的 rendered manifests 只能引用 Secret 名称和 key,不包含 Secret data。
- `agentrun-mgr` 保存 run 的 `executionPolicy.secretScope`,但保存的是 credential source reference,不是 credential value。
- runner 和 backend adapter 只能消费 manager 已授权的 secret scope,不能枚举 namespace 内所有 Secret。
## Secret 分类
| Secret 类别 | 用途 | 默认消费者 | v0.1 规则 |
| --- | --- | --- | --- |
| Postgres DSN | manager 连接 durable store | `agentrun-mgr` | 只通过 `agentrun-v01-mgr-db/DATABASE_URL` 注入。 |
| Codex stdio profile 凭据文件 | 真实 Code Agent backend 调上游模型 | runner 或 backend adapter | `codex``deepseek``minimax-m3` 使用 `auth.json`/`config.toml` 文件形态;`dsflash-go` 额外要求 `model-catalog.json`。这些文件只通过 profile-scoped Kubernetes SecretRef 文件投影注入,不写入 run payload。 |
| Git SSH deploy key | Tekton checkout source/GitOps promotionArgo 读取 GitOps branch | Tekton、Argo CD | 只存在于 `agentrun-ci``argocd` Secret;不进入 runtime Pod。 |
| Registry credential | push/pull private registry | Tekton、runtime imagePullSecret | 只作为 ServiceAccount/imagePullSecret 引用。 |
| Tool credential | GitHub PR、issue、UniDesk SSH passthrough、artifact registry 等 agent shell/tool 授权 | runner/backend adapter | 必须通过 `executionPolicy.secretScope.toolCredentials[]` 的 SecretRef 装配进入运行时;不是 Queue integration,也不能用 `transientEnv` 承载长期 credential。 |
| Future tenant credential | tenant 专属工具或外部服务 | runner/backend adapter | 必须先扩展装配 SPEC 的 SecretRef 和 secret scope,再允许 run 引用。 |
## 固定命名建议
| 对象 | v0.1 建议 |
| --- | --- |
| Manager DB Secret | `agentrun-v01-mgr-db` key `DATABASE_URL` |
| Codex Provider Secret | `agentrun-v01-provider-codex` keys `auth.json``config.toml` |
| DeepSeek Provider Secret | `agentrun-v01-provider-deepseek` keys `auth.json``config.toml` |
| MiniMax-M3 Provider Secret | `agentrun-v01-provider-minimax-m3` keys `auth.json``config.toml` |
| dsflash-go Provider Secret | `agentrun-v01-provider-dsflash-go` keys `auth.json``config.toml``model-catalog.json` |
| Provider projection target | 只读 `/var/run/agentrun/secrets/<profile>-<index>/auth.json``config.toml` 和 profile 需要的额外文件,再复制到当前 run/profile 的 writable `CODEX_HOME` |
| Provider config | 非敏感 base URL/model 可以来自 `config.toml` 或 ConfigMapcredential value 不得放入 ConfigMap。 |
| Tekton Git SSH Secret | `agentrun-ci/agentrun-git-ssh` |
| Argo Git SSH Secret | `argocd/agentrun-git-ssh` |
| GitHub Tool Secret | `agentrun-v01-tool-github-pr` key `GH_TOKEN` |
| UniDesk SSH Tool Secret | `agentrun-v01-tool-unidesk-ssh` key `UNIDESK_SSH_CLIENT_TOKEN` |
| Runtime ServiceAccount | `agentrun-v01-mgr``agentrun-v01-runner` |
命名可以在实现时因集群约束调整,但必须满足 lane 独立、用途单一、最小 RBAC 和不跨 `v0.1`/`v0.2` 复用的原则。
## Codex 测试凭据注入
`v0.1` 综合联调使用的 Codex stdio profile 测试凭据源固定为 operator 环境中的文件形态:
```text
~/.codex/auth.json
~/.codex/config.toml
```
这两个文件只能作为 Kubernetes Secret 创建或轮换的输入源。`codex` profile 默认使用 operator 当前 Codex 配置;`deepseek` profile 使用 operator 准备的 DeepSeek-compatible Codex 配置,可以来自另一个 `--codex-home` 或显式 `--auth-file`/`--config-file``minimax-m3` profile 使用从 HWLAB Code Queue 现有 MiniMax API key 派生的 Codex 配置,模型固定为 `MiniMax-M3`wire API 使用当前 Codex app-server 支持的 `responses``dsflash-go` 使用 `deepseek-v4-flash`、1M/900k context 和 `model-catalog.json`。禁止把宿主机 `~/.codex` 以 hostPath 挂入 runner/backend Pod,禁止复制进镜像,禁止提交到 source branch、GitOps branch、artifact catalog、issue、PR、event、trace、日志或 CLI 输出。
默认 Secret projection 规则:
| 项目 | v0.1 规格 |
| --- | --- |
| Kubernetes Secret | `agentrun-v01/agentrun-v01-provider-codex``agentrun-v01/agentrun-v01-provider-deepseek``agentrun-v01/agentrun-v01-provider-minimax-m3``agentrun-v01/agentrun-v01-provider-dsflash-go` |
| Secret key | `auth.json`,来自 `~/.codex/auth.json` |
| Secret key | `config.toml`,来自 `~/.codex/config.toml` |
| Secret key | `model-catalog.json`,仅 `dsflash-go` 必需,必须与 `config.toml``model_catalog_json` 指向同一 runtime 路径。 |
| Projection path | 只读 Secret projection 挂到 `/var/run/agentrun/secrets/<profile>-<index>/auth.json``config.toml` 和 profile 需要的额外文件;该路径只作为 credential source。 |
| Runtime config path | runner 启动时把当前 `backendProfile` 授权的 Secret projection 复制到 writable `CODEX_HOME`Kubernetes Job 默认使用该 Job 独占的 `/home/agentrun/.codex-<profile>/auth.json``config.toml` 和 profile 需要的额外文件;复用进程必须使用 run/profile 独占目录。 |
| Projection mode | 只读,建议 `0400` 或等价最小权限 |
| Runtime env | `HOME=/home/agentrun``CODEX_HOME=/home/agentrun/.codex-<profile>``AGENTRUN_CODEX_SECRET_HOME=<projection path>`;不得 fallback 到节点宿主机 home。 |
Secret 创建和轮换必须通过 Kubernetes 密钥管理完成。`deploy/deploy.json` 只写 SecretRef 名称、key 和 mount intent`v0.1-gitops` rendered manifests 只引用 Secret,不包含 Secret data。
Provider API Key 的 Web 配置由 [spec-v01-provider-profile-management.md](spec-v01-provider-profile-management.md) 定义:HWLAB Cloud API 鉴权后委托 AgentRun manager 更新受控 profile Secret/config。该路径仍只写 Kubernetes Secret data,不把 API Key 写入 Git、GitOps、Postgres、event、trace、日志或 CLI 输出。
## Run secretScope 合同
Run 的 `executionPolicy.secretScope` 只能包含引用,不包含值。provider credential 使用 `providerCredentials[]`GitHub PR、UniDesk SSH passthrough 等 agent shell/tool 授权使用装配 SPEC 定义的 `toolCredentials[]`,不得混入 `transientEnv`。示例形态:
```json
{
"providerCredentials": [
{
"profile": "codex",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-provider-codex",
"keys": ["auth.json", "config.toml"],
"mountPath": "~/.codex"
}
},
{
"profile": "deepseek",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-provider-deepseek",
"keys": ["auth.json", "config.toml"],
"mountPath": "~/.codex"
}
},
{
"profile": "minimax-m3",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-provider-minimax-m3",
"keys": ["auth.json", "config.toml"],
"mountPath": "~/.codex"
}
},
{
"profile": "dsflash-go",
"secretRef": {
"namespace": "agentrun-v01",
"name": "agentrun-v01-provider-dsflash-go",
"keys": ["auth.json", "config.toml", "model-catalog.json"],
"mountPath": "~/.codex"
}
}
],
"allowCredentialEcho": false
}
```
规则:
- `allowCredentialEcho` 必须固定为 `false`
- `secretRef.namespace` 默认只能是 run 所在 lane namespace 或明确批准的 platform namespace。
- manager 可以保存 `secretRef`,但不得读取 Secret 值后存库。
- runner/backend adapter 获得 Secret 的方式必须来自 Kubernetes env/file projection 或受限 Secret API 读取;Codex 默认从只读 Secret projection 复制 `auth.json``config.toml` 和 profile 需要的额外文件到 writable `CODEX_HOME` 后启动 app-server,不得通过 run payload、event、CLI 参数或日志传递。
- runner/backend adapter 只能选择与 run `backendProfile` 同名的 provider credential`backendProfile=deepseek``backendProfile=minimax-m3``backendProfile=dsflash-go` 缺少 matching SecretRef 时必须 `secret-unavailable`,不得 fallback 到 `codex` 或另一个 profile。
- manager 会按内建 profile 的 `requiredSecretKeys` 规范化 `secretRef.keys`;消费侧旧 payload 即使只提交 `auth.json`/`config.toml``dsflash-go` runner Job 也必须投影 `model-catalog.json`。若实际 Kubernetes Secret 缺少该 keyrun 必须在装配或 readiness 阶段失败为结构化 `secret-unavailable`
- Secret projection 不能直接作为 `CODEX_HOME`。Codex app-server 会读取并可能维护默认配置、PATH 或运行态文件;把只读 Secret volume 直接挂到 `CODEX_HOME` 会造成启动期写入失败。v0.1 的固定边界是:Secret volume 只读、`/home/agentrun``emptyDir` 提供可写 runtime home、复制动作只发生在 runner/backend 容器内且不打印文件内容。
- SecretRef 不存在或 RBAC 不允许时,run 必须失败为结构化 `failureKind=secret-unavailable` 或等价错误,不得降级成无凭证重试风暴。
- `toolCredentials` 的 SecretRef/projection/redaction 规则以 [spec-v01-runtime-assembly.md](spec-v01-runtime-assembly.md) 为准;本文只约束 Secret value 不落库、不输出、不进入 Git source 或 GitOps Secret data。
## runner-job transientEnv
`transientEnv` 用于承接调度方生成的短期、单次 runner Job 运行上下文,例如 HWLAB Code Agent 的 owner-scoped HWPOD/runtime API key、runtime URL 和非敏感 UniDesk frontend 地址。它也可以承接 manager 因 `tool=unidesk-ssh` 自动补齐的受控默认 endpoint env。它不是 provider credential、tool credential,也不是 run durable fact。
规则:
- `transientEnv` 只能出现在 `POST /api/v1/runs/:runId/runner-jobs` 请求中;不得写入 `CreateRunInput`、command payload、event payload 或 result envelope 的 value 明文。
- manager 不对 `transientEnv` 条目数量设固定上限,只校验数组形态、env name 合法且唯一、value 非空和单值长度;runner job payload hash 只纳入 env name 与 value hash。
- 当 run 请求 `executionPolicy.secretScope.toolCredentials[].tool=unidesk-ssh` 且调用方未提供 `UNIDESK_MAIN_SERVER_IP``UNIDESK_MAIN_SERVER_HOST``UNIDESK_FRONTEND_URL` 时,manager 可以从受控默认配置自动补齐一个非敏感 endpoint env。该自动补齐必须遵守同一 redaction 规则,只显示 name/count/hash 和 `valuesPrinted=false`
- response、runner job status、event 和 dry-run manifest 只能展示 env name、count、SecretRef metadata 和 `valuesPrinted=false`dry-run manifest 中的 transient env value 必须显示为 `REDACTED`
- 正式 Kubernetes runner Job 不得把 `transientEnv` value 作为 pod spec plain env value。manager 必须先创建本次 Job 专属的短期 Kubernetes Secret,再在 runner container env 中使用 `valueFrom.secretKeyRef` 引用对应 key。Secret name、namespace、keys、ownerReference attached 状态和 `valuesPrinted=false` 可以出现在 response/event/trace 中,Secret data 和 env value 不得出现。
- 本次 Job 专属 transient env Secret 必须带有 run/command/attempt/runner/job metadata,创建 Job 失败时清理已创建 SecretJob 创建成功后尽量给 Secret 加上 ownerReference,让 Kubernetes 随 Job GC。ownerReference patch 失败必须以 warning 暴露,不能回退为 plain env value。
- `transientEnv` token 必须由调度方控制 TTL、权限和业务授权范围;AgentRun 只负责本次 runner Job 的短期投影和 redaction,不把它升级为长期 credential。
- AgentRun 不解释 HWLAB HWPOD 权限,也不把业务鉴权做成通用 policy;AgentRun 只负责不持久化、不回显、不扩散这类短期 env value。
- GitHub token、UniDesk SSH client token、SSH private key、provider API key、registry token 等 provider/tool 可复用 credential 不得通过 `transientEnv` 注入;必须先进入装配 SPEC 的 SecretRef 路径。HWLAB dispatcher 生成并限定 owner/HWPOD/runtime scope 的 `HWLAB_API_KEY` 属于业务运行上下文,可以作为单次 runner Job env 透传,但不得变成 AgentRun durable fact 或通用授权。
## 分发路径
`v0.1` 默认路径:
```text
deploy/deploy.json
-> declares SecretRef names and mount/env intent only
Tekton promotion
-> renders SecretRef references into v0.1-gitops manifests
Argo CD
-> syncs workload references to agentrun-v01
Kubernetes Secret
-> created from profile-specific auth.json, config.toml and required extra files by operator or approved secret-management flow
runner/backend Pod
-> receives Codex auth/config/model catalog via read-only file projection
-> copies authorized files into writable CODEX_HOME before starting Codex app-server
```
Secret 创建和轮换不由 source branch 自动生成;source branch 只声明需要哪个 SecretRef。后续如果接入 External Secrets、Vault、SealedSecrets 或 SOPS,必须新增或更新本 spec,明确 controller、source of truth、rotation 和 redaction 规则。
## Codex Secret dry-run 工具
`v0.1` 提供只读 CLI 工具,用 operator 本地 `~/.codex/auth.json``~/.codex/config.toml` 和 profile 需要的额外文件构造 Kubernetes Secret 创建计划:
```bash
./scripts/agentrun secrets codex render --dry-run [--profile codex|deepseek|minimax-m3|dsflash-go]
```
可选参数:
- `--codex-home <dir>`:覆盖默认 `~/.codex` 输入目录。
- `--profile <name>`:默认 `codex``deepseek``minimax-m3``dsflash-go` 使用同一文件形态但默认 Secret name 分别为对应 `agentrun-v01-provider-<profile>`
- `--auth-file <path>` / `--config-file <path>`:分别覆盖输入文件路径。
- `--model-catalog-file <path>`:覆盖 `dsflash-go``model-catalog.json` 输入文件路径。
- `--namespace <name>`:默认 `agentrun-v01`
- `--secret-name <name>`:默认随 profile 变化,`codex``agentrun-v01-provider-codex``deepseek``agentrun-v01-provider-deepseek``minimax-m3``agentrun-v01-provider-minimax-m3`
输出必须是 JSON,并且只包含 `namespace``secretName``keys`、每个输入文件的 `bytes``sha256`/`contentHash`、整体 hash、redaction 状态、apply 命令形状和 Secret manifest 摘要。输出不得包含 Secret value、`auth.json` 明文、`config.toml` 明文、`model-catalog.json` 明文、base64 `data` 字段或可直接恢复 credential 的内容。工具只支持 `--dry-run`;不得执行 `kubectl apply`
失败必须结构化返回 `failureKind`:缺文件、不可读文件或空 credential 归类为 `secret-unavailable`;非法 JSON/TOML 归类为 `schema-invalid`
## 日志与事件 Redaction
- event、trace、日志、CLI 输出、health 和 diagnostics 不得打印 Secret 值。
- `Authorization``api_key``token``password`、URL credential、DSN password、Codex `auth.json``config.toml` 文件内容必须 redacted。
- 可以打印 SecretRef 名称、key 名称、credential source、是否存在、是否被挂载、是否通过 readiness 检查。
- provider auth 失败只能报告 failure kind、HTTP status 分类和 request id;不得打印请求 header 或 body 中的凭据。
## 测试规格
### T1 SecretRef render
阅读本文和 [spec-v01-cicd.md](spec-v01-cicd.md),然后检查 `deploy/deploy.json` 只包含 SecretRef 名称/key 和 mount/env intentrendered GitOps manifest 也只包含 SecretRef,不包含 Secret data。
### T2 Runner credential projection
阅读本文,然后分别启动 `backendProfile=codex``backendProfile=deepseek``backendProfile=minimax-m3``backendProfile=dsflash-go` 的最小 backend runner dry-run,确认 Pod file projection 挂在 `/var/run/agentrun/secrets/...` 且只读,`/home/agentrun` 是 writable runtime homerunner/backend 只把当前 profile 授权文件复制到 `CODEX_HOME` 后再启动 Codex`dsflash-go` 必须同时投影并复制 `model-catalog.json`;event、日志和 CLI 输出只显示 redacted credential source,不显示文件内容。
### T3 Missing secret failure
阅读本文,然后用一个不存在的 provider SecretRef 创建 run,确认 run 失败为结构化 `secret-unavailable`,不会打印 Secret 值,也不会无限重试。
### T4 transientEnv SecretRef 投影
阅读本文,然后通过正式 `runner-jobs` 或 Queue dispatch 路径创建带 `transientEnv` 的真实 runner Job。检查 runner job response、event、dry-run manifest 和 Kubernetes Pod specresponse/event 只能输出 env names、Secret name/namespace/keys、ownerReference 状态和 `valuesPrinted=false`Pod spec 中对应 env 必须是 `valueFrom.secretKeyRef`,不能包含 `value`Secret data 只能通过 Kubernetes Secret 保存,验证时只允许读取 key 列表和 metadata,不得输出 value。
## 规格的实现情况
| 规格项 | 状态 | 说明 |
| --- | --- | --- |
| Secret 分发规格 | 已定义 | 本文为 v0.1 provider credential 分发权威。 |
| Kubernetes SecretRef 注入 | 已实现/已通过主闭环 | runner Job dry-run 和正式 Job 创建路径已按 run `executionPolicy.secretScope.providerCredentials` 生成 Secret volume projection、writable runtime home 和 `AGENTRUN_CODEX_SECRET_HOME`;真实 Secret 与 Codex turn 已通过主闭环。 |
| Codex Secret dry-run 工具 | 已实现 | `./scripts/agentrun secrets codex render --dry-run` 只输出 Secret 创建计划、hash 和 redacted manifest 摘要,不执行 apply。 |
| Codex auth/config file projection | 已实现主路径 | backend readiness 检查 `auth.json`/`config.toml` 可读性,缺失时返回 `secret-unavailable`;真实 runner Job 将只读 projection 复制到 writable `CODEX_HOME`。 |
| DeepSeek profile SecretRef | 已实现/已通过主闭环 | 已新增 `agentrun-v01-provider-deepseek` render、GitOps/RBAC 引用、Job projection、profile 选择和负向 missing-secret 自测试;真实 Secret 创建与 Kubernetes Job projection 已通过主闭环,轮换仍由 Kubernetes 密钥管理流程完成。 |
| MiniMax-M3 profile SecretRef | 已实现/待真实主闭环 | 已新增 `agentrun-v01-provider-minimax-m3` render、GitOps/RBAC 引用、Job projection、profile 选择和负向 missing-secret 自测试;真实 Secret 创建使用 HWLAB Code Queue 现有 MiniMax API key,轮换仍由 Kubernetes 密钥管理流程完成。 |
| dsflash-go profile SecretRef | 已实现/待真实主闭环 | 已新增 `agentrun-v01-provider-dsflash-go``model-catalog.json` required key、Secret render、Job projection、writable `CODEX_HOME` 复制和负向 readiness;真实 profile turn 仍需按 provider 管理 canary 和 HWLAB 原入口复测。 |
| Tool credential SecretRef | 已实现最小 env projection | `executionPolicy.secretScope.toolCredentials[]` 已支持 `tool=github``tool=unidesk-ssh``projection.kind=env`runner Job 通过 Kubernetes `secretKeyRef` 注入 envCLI、event、runner job response 和 dry-run 只显示 SecretRef/projection 元数据,不输出值。 |
| redaction 最小规则 | 已实现主路径 | Secret dry-run 工具、event、Job dry-run 输出、self-test 和真实主闭环均不打印 Secret value;复杂审计按 [spec-v01-validation.md](spec-v01-validation.md) 人工抽查。 |
| 外部 secret manager | 未采用 | 如需 Vault/ExternalSecrets/SOPS,后续单独更新规格。 |