密钥管理
OpenClaw 支持增量式 SecretRef,这样受支持的凭证无需以明文形式存储在配置中。
明文仍然可用。SecretRef 是按凭证逐个选择启用的。
目标与运行时模型
密钥被解析为内存中的运行时快照。
- 解析在激活时立即执行(eager),不是在请求路径上延迟执行(lazy)。
- 启动时如果有效的 SecretRef 无法解析,直接快速失败。
- 重载使用原子交换:要么全部成功,要么保持上一个已知良好的快照。
- 运行时请求只从活跃的内存快照中读取。
- 出站投递路径也从活跃快照中读取(例如 Discord 回复/线程投递和 Telegram action 发送),不会在每次发送时重新解析 SecretRef。
这样可以让密钥提供商的故障远离热请求路径。
活跃表面过滤
SecretRef 只在有效激活的表面上进行验证。
- 已启用的表面:未解析的引用会阻止启动/重载。
- 未激活的表面:未解析的引用不阻止启动/重载。
- 未激活的引用会产生非致命诊断信息,代码为
SECRETS_REF_IGNORED_INACTIVE_SURFACE。
未激活表面的例子:
- 被禁用的通道/账户条目。
- 没有被任何已启用账户继承的顶层通道凭证。
- 被禁用的工具/功能表面。
- 未被
tools.web.search.provider选中的 Web 搜索提供商密钥。 在自动模式(provider 未设置)下,密钥按优先级逐个尝试用于提供商自动检测,直到有一个解析成功。选定后,未选中的提供商密钥视为未激活。 gateway.remote.token/gateway.remote.passwordSecretRef 在以下任一条件为真时激活:gateway.mode=remote- 配置了
gateway.remote.url gateway.tailscale.mode为serve或funnel- 在没有上述远程表面的本地模式下:
gateway.remote.token在 token 认证可能生效且未配置环境变量/auth token 时激活。gateway.remote.password仅在密码认证可能生效且未配置环境变量/auth password 时激活。
- 当
OPENCLAW_GATEWAY_TOKEN(或CLAWDBOT_GATEWAY_TOKEN)已设置时,gateway.auth.tokenSecretRef 在启动认证解析中不激活,因为环境变量 token 在该运行时优先。
网关认证表面诊断
当 gateway.auth.token、gateway.auth.password、gateway.remote.token 或 gateway.remote.password 上配置了 SecretRef 时,网关启动/重载会显式记录表面状态:
active:该 SecretRef 是有效认证表面的一部分,必须解析成功。inactive:该 SecretRef 在本次运行时被忽略,因为其他认证表面优先,或者远程认证未启用/不激活。
这些条目以 SECRETS_GATEWAY_AUTH_SURFACE 记录,包含活跃表面策略使用的原因,方便你了解为什么某个凭证被视为激活或未激活。
引导流程中的引用预检
交互式引导流程中选择 SecretRef 存储时,OpenClaw 会在保存前执行预检验证:
- 环境变量引用:验证变量名并确认引导期间能看到非空值。
- 提供商引用(
file或exec):验证提供商选择、解析id、检查解析后的值类型。 - 快速启动复用路径:当
gateway.auth.token已经是 SecretRef 时,引导流程在 probe/dashboard 引导前先解析它(对env、file和exec引用使用相同的快速失败门控)。
验证失败时,引导流程会显示错误并允许重试。
SecretRef 合约
统一使用一种对象格式:
{ source: "env" | "file" | "exec", provider: "default", id: "..." }
source: "env"
{ source: "env", provider: "default", id: "OPENAI_API_KEY" }
验证规则:
provider必须匹配^[a-z][a-z0-9_-]{0,63}$id必须匹配^[A-Z][A-Z0-9_]{0,127}$
source: "file"
{ source: "file", provider: "filemain", id: "/providers/openai/apiKey" }
验证规则:
provider必须匹配^[a-z][a-z0-9_-]{0,63}$id必须是绝对 JSON 指针(/...)- RFC6901 转义规则:
~=>~0,/=>~1
source: "exec"
{ source: "exec", provider: "vault", id: "providers/openai/apiKey" }
验证规则:
provider必须匹配^[a-z][a-z0-9_-]{0,63}$id必须匹配^[A-Za-z0-9][A-Za-z0-9._:/-]{0,255}$id的斜杠分隔路径段中不能包含.或..(例如a/../b会被拒绝)
提供商配置
在 secrets.providers 下定义提供商:
{
secrets: {
providers: {
default: { source: "env" },
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json", // or "singleValue"
},
vault: {
source: "exec",
command: "/usr/local/bin/openclaw-vault-resolver",
args: ["--profile", "prod"],
passEnv: ["PATH", "VAULT_ADDR"],
jsonOnly: true,
},
},
defaults: {
env: "default",
file: "filemain",
exec: "vault",
},
resolution: {
maxProviderConcurrency: 4,
maxRefsPerProvider: 512,
maxBatchBytes: 262144,
},
},
}
环境变量提供商
- 可通过
allowlist配置可选白名单。 - 缺失或为空的环境变量值会导致解析失败。
文件提供商
- 从
path指定的本地文件读取。 mode: "json"期望 JSON 对象载荷,id作为指针解析。mode: "singleValue"期望引用 id 为"value",返回文件内容。- 路径必须通过所有权/权限检查。
- Windows 注意:如果无法对某路径进行 ACL 验证,解析会失败。仅对受信路径设置
allowInsecurePath: true来绕过路径安全检查。
Exec 提供商
- 运行配置的绝对路径二进制文件,不经过 shell。
- 默认情况下,
command必须指向常规文件(不是符号链接)。 - 设置
allowSymlinkCommand: true允许符号链接命令路径(例如 Homebrew shim)。OpenClaw 会验证解析后的目标路径。 - 将
allowSymlinkCommand与trustedDirs配合使用(例如["/opt/homebrew"])。 - 支持超时、无输出超时、输出字节限制、环境变量白名单和受信目录。
- Windows 注意:如果无法对命令路径进行 ACL 验证,解析会失败。仅对受信路径设置
allowInsecurePath: true来绕过路径安全检查。
请求载荷(stdin):
{ "protocolVersion": 1, "provider": "vault", "ids": ["providers/openai/apiKey"] }
响应载荷(stdout):
{ "protocolVersion": 1, "values": { "providers/openai/apiKey": "<openai-api-key>" } } // pragma: allowlist secret
可选的按 id 错误:
{
"protocolVersion": 1,
"values": {},
"errors": { "providers/openai/apiKey": { "message": "not found" } }
}
Exec 集成示例
1Password CLI
{
secrets: {
providers: {
onepassword_openai: {
source: "exec",
command: "/opt/homebrew/bin/op",
allowSymlinkCommand: true, // required for Homebrew symlinked binaries
trustedDirs: ["/opt/homebrew"],
args: ["read", "op://Personal/OpenClaw QA API Key/password"],
passEnv: ["HOME"],
jsonOnly: false,
},
},
},
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
models: [{ id: "gpt-5", name: "gpt-5" }],
apiKey: { source: "exec", provider: "onepassword_openai", id: "value" },
},
},
},
}
HashiCorp Vault CLI
{
secrets: {
providers: {
vault_openai: {
source: "exec",
command: "/opt/homebrew/bin/vault",
allowSymlinkCommand: true, // required for Homebrew symlinked binaries
trustedDirs: ["/opt/homebrew"],
args: ["kv", "get", "-field=OPENAI_API_KEY", "secret/openclaw"],
passEnv: ["VAULT_ADDR", "VAULT_TOKEN"],
jsonOnly: false,
},
},
},
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
models: [{ id: "gpt-5", name: "gpt-5" }],
apiKey: { source: "exec", provider: "vault_openai", id: "value" },
},
},
},
}
sops
{
secrets: {
providers: {
sops_openai: {
source: "exec",
command: "/opt/homebrew/bin/sops",
allowSymlinkCommand: true, // required for Homebrew symlinked binaries
trustedDirs: ["/opt/homebrew"],
args: ["-d", "--extract", '["providers"]["openai"]["apiKey"]', "/path/to/secrets.enc.json"],
passEnv: ["SOPS_AGE_KEY_FILE"],
jsonOnly: false,
},
},
},
models: {
providers: {
openai: {
baseUrl: "https://api.openai.com/v1",
models: [{ id: "gpt-5", name: "gpt-5" }],
apiKey: { source: "exec", provider: "sops_openai", id: "value" },
},
},
},
}
支持的凭证覆盖范围
规范的支持和不支持凭证列表见:
运行时生成或轮换的凭证和 OAuth 刷新材料被刻意排除在只读 SecretRef 解析之外。
行为要求与优先级
- 字段没有引用时:不变。
- 字段有引用时:在激活表面上,激活期间必须解析成功。
- 如果同时存在明文和引用,引用在支持的优先级路径上胜出。
警告和审计信号:
SECRETS_REF_OVERRIDES_PLAINTEXT(运行时警告)REF_SHADOWED(auth-profiles.json凭证优先于openclaw.json引用时的审计发现)
Google Chat 兼容行为:
serviceAccountRef优先于明文serviceAccount。- 设置了同级引用时,明文值被忽略。
激活触发点
密钥激活在以下时机运行:
- 启动(预检 + 最终激活)
- 配置重载热更新路径
- 配置重载重启检查路径
- 通过
secrets.reload手动重载
激活合约:
- 成功时原子交换快照。
- 启动失败时中止网关启动。
- 运行时重载失败时保持上一个已知良好的快照。
- 在出站辅助/工具调用中提供显式的每次调用通道 token,不触发 SecretRef 激活;激活点仍然是启动、重载和显式
secrets.reload。
降级与恢复信号
重载时激活失败(在之前健康的状态之后),OpenClaw 进入密钥降级状态。
一次性系统事件和日志代码:
SECRETS_RELOADER_DEGRADEDSECRETS_RELOADER_RECOVERED
行为:
- 降级:运行时保持上一个已知良好的快照。
- 恢复:在下一次成功激活后触发一次。
- 已处于降级状态时重复失败只记录警告,不刷屏发事件。
- 启动快速失败不触发降级事件,因为运行时从未变为活跃状态。
命令路径解析
命令路径可以通过网关快照 RPC 选择性地使用 SecretRef 解析。
有两种大类行为:
- 严格命令路径(如
openclaw memory远程内存路径和openclaw qr --remote)从活跃快照读取,必需的 SecretRef 不可用时快速失败。 - 只读命令路径(如
openclaw status、openclaw status --all、openclaw channels status、openclaw channels resolve以及只读的 doctor/config 修复流程)也优先使用活跃快照,但在目标 SecretRef 不可用时降级而非中止。
只读行为:
- 网关运行时,这些命令先从活跃快照读取。
- 如果网关解析不完整或网关不可用,它们会尝试对特定命令表面进行本地回退。
- 如果目标 SecretRef 仍不可用,命令继续运行但输出降级的只读结果,并显示明确诊断信息如”已配置但在此命令路径中不可用”。
- 这种降级行为仅限命令本身。它不会削弱运行时启动、重载或发送/认证路径。
其他说明:
- 后端密钥轮换后的快照刷新通过
openclaw secrets reload处理。 - 这些命令路径使用的网关 RPC 方法:
secrets.resolve。
审计与配置工作流
默认操作员流程:
openclaw secrets audit --check
openclaw secrets configure
openclaw secrets audit --check
secrets audit
发现项包括:
- 静态存储中的明文值(
openclaw.json、auth-profiles.json、.env以及生成的agents/*/agent/models.json) - 生成的
models.json条目中的明文敏感提供商 header 残留 - 未解析的引用
- 优先级遮蔽(
auth-profiles.json优先于openclaw.json引用) - 历史遗留残留(
auth.json、OAuth 提醒)
Header 残留说明:
- 敏感提供商 header 检测基于名称启发式(常见的认证/凭证 header 名称和片段如
authorization、x-api-key、token、secret、password、credential)。
secrets configure
交互式助手,功能包括:
- 首先配置
secrets.providers(env/file/exec,添加/编辑/删除) - 选择
openclaw.json和某个 agent 范围下auth-profiles.json中的密钥字段 - 可以在目标选择器中直接创建新的
auth-profiles.json映射 - 采集 SecretRef 详情(
source、provider、id) - 运行预检解析
- 可以立即应用
快捷模式:
openclaw secrets configure --providers-onlyopenclaw secrets configure --skip-provider-setupopenclaw secrets configure --agent <id>
configure apply 默认行为:
- 为目标提供商擦除
auth-profiles.json中匹配的静态凭证 - 擦除
auth.json中旧版静态api_key条目 - 擦除
<config-dir>/.env中匹配的已知密钥行
secrets apply
应用保存的计划:
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json
openclaw secrets apply --from /tmp/openclaw-secrets-plan.json --dry-run
严格的目标/路径合约和详细的拒绝规则见:
单向安全策略
OpenClaw 故意不写入包含历史明文密钥值的回滚备份。
安全模型:
- 预检必须在写入模式之前通过
- 运行时激活在提交前验证
- apply 使用原子文件替换更新文件,失败时尽力恢复
旧版认证兼容说明
对于静态凭证,运行时不再依赖明文旧版认证存储。
- 运行时凭证来源是解析后的内存快照。
- 发现旧版静态
api_key条目时自动擦除。 - OAuth 相关的兼容行为保持独立。
Web UI 说明
部分 SecretInput union 在原始编辑器模式下比表单模式更容易配置。
相关文档
- CLI 命令:secrets
- 计划合约详情:Secrets Apply 计划合约
- 凭证覆盖范围:SecretRef 凭证覆盖范围
- 认证配置:认证
- 安全态势:安全
- 环境变量优先级:环境变量