在之前的讨论中,我们探讨了通过环境变量进行API Key轮换的方法。虽然这种方法比将明文密钥存储在配置文件中要好得多,但环境变量仍然存在一定的暴露风险(例如通过进程列表、内存转储或不恰当的日志记录可能被访问)。对于对安全要求极高的场景,OpenClaw提供了更先进的SecretRef系统,可以实现API Key的真正隐蔽存储。
🔐 SecretRef系统:零明文存储的凭证管理
OpenClaw的SecretRef系统允许您将凭证完全从配置文件和环境变量中分离出来,而是存储在安全的后端系统中(如加密文件、密码管理器或专用的秘密管理服务),仅在启动时解析到内存中使用。
核心优势
- 零明文存储:凭证永不以明文形式出现在配置文件中
- 内存中快照:解析后的凭证仅存在于内存中的激活快照
- 启动时失败快速:如果无法解析必需的SecretRef,网关启动将失败
- 原子重载:配置重载使用原子交换要么完全成功要么保持最后已知良好的状态
- 表面过滤:仅对有效活跃的表面解析SecretRef,非活跃表面不会导致启动失败
🛠️ SecretRef基本契约
SecretRef使用统一的对象形状:
json5
{ source: "env" | "file" | "exec", provider: "default", id: "..." }
三种来源类型详解
1. Env来源(环境变量引用)
json5
{ source: "env", provider: "default", id: "NVIDIA_API_KEY_1" }
- 验证:
provider必须匹配^[a-z][a-z0-9_-]{0,63}$,id必须匹配^[A-Z][A-Z0-9_]{0,127}$ - 优势:比直接在配置中写入key更安全,因为环境变量可以受到更好的进程级别保护
- 注意:尽管比明文好,但环境变量仍可能通过
ps或/proc泄露
2. File来源(加密文件引用)
json5
{ source: "file", provider: "filemain", id: "/providers/nvidia/apiKey" }
- 需要配置
secrets.providers.filemain指向加密的secrets文件 - 支持两种模式:
mode: "json"- 期望JSON对象载荷,通过JSON Pointer解析idmode: "singleValue"- 期望文件仅包含单个值,id必须是"value"
- 路径必须通过所有权和权限检查
- 在Windows上,如果ACL验证不可用,则失败(除非显式设置
allowInsecurePath: true用于受信任路径)
3. Exec来源(与秘密管理器集成)
json5
{ source: "exec", provider: "vault", id: "providers/nvidia/apiKey" }
- 与外部秘密管理器集成的最强大方式
- 验证:
provider必须匹配^[a-z][a-z0-9_-]{0,63}$,id必须匹配特定模式且不允许路径遍历 - 执行绝对路径的二进制文件(不使用shell)
- 支持超时、输出限制、环境变量允许列表和受信任目录
🔑 高级集成示例
示例1:使用HashiCorp Vault
json5
{
secrets: {
providers: {
vault_nvidia: {
source: "exec",
command: "/usr/local/bin/vault",
allowSymlinkCommand: true,
trustedDirs: ["/usr/local/bin"],
args: ["kv", "get", "-field=NVIDIA_API_KEY", "secret/openclaw/nvidia"],
passEnv: ["VAULT_ADDR", "VAULT_TOKEN"],
jsonOnly: false,
},
},
defaults: {
exec: "vault_nvidia",
},
},
models: {
providers: {
nvidia: {
baseUrl: "https://integrate.api.nvidia.com/v1",
api: "openai-completions",
apiKey: { source: "exec", provider: "vault_nvidia", id: "value" },
models: [
{ id: "nvidia/nemotron-3-super-120b-a12b", name: "NVIDIA Nemotron 3 Super 120B" },
{ id: "deepseek-ai/deepseek-v4-flash", name: "deepseek-v4-flash" }
]
}
}
}
}
示例2:使用1Password CLI
json5
{
secrets: {
providers: {
1password_nvidia: {
source: "exec",
command: "/opt/homebrew/bin/op",
allowSymlinkCommand: true, // 为Homebrew symlink必需
trustedDirs: ["/opt/homebrew"],
args: ["read", "op://Personal/OpenClaw NVIDIA API Key/password"],
passEnv: ["HOME"],
jsonOnly: false,
},
},
},
models: {
providers: {
nvidia: {
apiKey: { source: "exec", provider: "1password_nvidia", id: "value" },
// ... 其他配置
}
}
}
}
示例3:使用sops加密文件
json5
{
secrets: {
providers: {
sops_secrets: {
source: "exec",
command: "/usr/local/bin/sops",
allowSymlinkCommand: true,
trustedDirs: ["/usr/local/bin"],
args: ["-d", "--extract", '["providers"]["nvidia"]["apiKey"]', "/etc/openclaw/secrets.enc.yaml"],
passEnv: ["SOPS_AGE_KEY_FILE"],
jsonOnly: false,
},
},
},
models: {
providers: {
nvidia: {
apiKey: { source: "exec", provider: "sops_secrets", id: "value" },
// ... 其他配置
}
}
}
}
⚙️ 配置SecretRef的步骤
1. 配置secrets.providers
在~/.openclaw/openclaw.json中添加:
json5
{
secrets: {
providers: {
// 选择您需要的提供者类型
env: { source: "env" },
filemain: {
source: "file",
path: "~/.openclaw/secrets.json",
mode: "json"
},
vault: {
source: "exec",
command: "/usr/local/bin/vault",
args: ["kv", "get"
...(truncated)...