夜雨聆风学习资料网

ARTICLE · 1200655

OpenClaw 密钥怎么管才安全?官方 SecretRef 实践记录

OpenClaw 密钥怎么管才安全?官方 SecretRef 实践记录

一篇有官方文档背书的密钥管理实践:不臆想、不泄露、可复现。
后记:我最终将模型的密钥转移了,没迁移gateway token,担心移走之后gateway没办法启动登录进来。

引子:一次"被锁在门外"的教训

前两天我在配置 OpenClaw 的时候,踩了一个挺典型的坑。

为了"更安全"一点,我把登录用的 token 从明文改成了环境变量引用 ${env:GATEWAY_AUTH_TOKEN},还老老实实写进了 ~/.openclaw/.env。结果一重启 Gateway,页面直接登不上去了。

排查半天才搞明白两件事:

第一,Gateway 服务根本不读普通 .env;

第二,登录 token 属于"fail-closed"(解析失败就拒绝)——解析不出来,等于自己把自己锁在门外。

这个坑逼着我认真读了一遍 OpenClaw 的官方文档。今天就把结论完整讲清楚:密钥到底该放哪、怎么被读取、官方推荐怎么做。所有做法都能在 OpenClaw 官方文档 里找到出处。

一、官方立场:明文能用,但推荐 SecretRef

先给一个可能反直觉的结论。官方文档写得很清楚:

"OpenClaw supports additive SecretRefs so supported credentials do not need to live as plaintext in configuration."—— Secrets management · OpenClaw Docs

翻译过来:OpenClaw 支持 SecretRef,让受支持的凭据不必以明文形式出现在配置里。但文档紧接着用一句话定了调子:

"Plaintext still works. SecretRefs are opt-in per credential."—— Secrets management · OpenClaw Docs

明文仍然能用,SecretRef 是"按需开启"的,不是强制的。

这个态度很重要。它意味着你有选择权,不用为了安全把整套系统推倒重来。官方推荐的是"渐进式迁移",而不是一刀切。

二、SecretRef 到底长什么样

官方给出了一个"到哪都一样"的统一结构:

{ source: "env" | "file" | "exec" | "store", provider: "default", id: "..." }

你原来在配置里写的是 "apiKey": "sk-xxxxxxxx"(明文),迁移后变成:

"apiKey": { "source": "store", "provider": "default", "id": "OPENAI_API_KEY" }

区别就是:配置里不再放"钥匙本身",只放"保险箱的编号"。

官方支持四种来源,各有适用场景:

  • env
    从环境变量读,最轻量。写法:
    { source: "env", provider: "default", id: "OPENAI_API_KEY" },也可以简写成 "${OPENAI_API_KEY}"
  • file
    从某个 JSON 文件里按路径读(id是 JSON pointer)
  • exec
    外部命令/密码管理器动态提供,适合 1Password、Vault 这类
  • store
    从 OpenClaw 自带的共享密钥库读——这也是我推荐日常用的那一种

三、共享密钥库(Shared secret store):放哪里?

这是本文的重点。官方在 Shared secret store 一节定义了它:

"The shared secret store is a Gateway-wide, team-scoped place for secrets and environment values that should be available to every Gateway process using the same state database."—— Secrets management · OpenClaw Docs

它是一个 Gateway 级别、团队作用域的密钥存放处,管理方式有两种:Control UI 的 Settings → Secrets,或者命令行 openclaw secrets store。

关键点在于,官方把它分成两种访问模式,这个区分特别实用:

受保护密钥(kind: secret)保存后只写不可读。
官方原话:"Protected secret (kind: "secret") values are write-only after saving." 列出、界面、命令行 get 都不会返回它的值,也没有"显示"接口。
用官方 CLI 实测确认:openclaw secrets store get <NAME>会直接拒绝,退出码 2。
代理可读环境值(kind: env)
管理员可见,store list/store get能读回来。适合那些本来就不敏感、只是想让子进程用到的配置。

日常凭据(API Key、Token)应该用 secret模式——存进去就取不回来,从机制上杜绝了"页面上不小心看到明文"的可能。

⚠️ 一个官方特别标注的诚实提醒:密钥库的值在磁盘上不是加密的,它以未加密形式存在共享状态数据库 state/openclaw.sqlite里,靠的是文件 0600、目录 0700这类权限保护。如果你的威胁模型需要更强的存储隔离,官方建议改用外部 exec provider(如 1Password 或 Vault 插件)。

这一点我认为必须如实转述——没有神话它。官方自己说了"not encrypted at rest",我们不替它吹。

四、值是怎么被读取的?运行时快照机制

存好了之后,Gateway 怎么用这个值?官方在 Runtime model 里给了一个很关键的描述:

"Secrets resolve into an in-memory runtime snapshot, eagerly during activation, not lazily on request paths."—— Secrets management · OpenClaw Docs

用大白话拆解这条链路:

启动时一次性解析
(eager,不是每次请求现取):Gateway 读配置,发现是个 SecretRef,就去对应的源(比如密钥库)取值;
解析进内存快照
值只活在 Gateway 进程内存里,不反复落盘;
请求时只读快照
"Runtime requests read only the active in-memory snapshot."——运行时请求只读内存快照,不来回解析;
日志自动打码
"Resolved secret values are also registered for exact-value log redaction as a defense in depth measure."

为什么这样设计?官方解释:这样能把"密钥提供者的故障"挡在热请求路径之外("This keeps secret-provider outages off hot request paths")。密钥源出问题,不会拖垮每一次调用。

五、模型 Key 的额外一层:出网哨兵(Sentinel)

如果你在意的是模型 provider 的 Key(OpenAI、DeepSeek、MiniMax 这类),官方还上了一层更细的保护,叫 Egress-time injection (sentinels):

"For model-provider credentials backed by SecretRefs, OpenClaw mints an opaque, process-local sentinel during model-auth resolution."—— Secrets management · OpenClaw Docs

机制是:系统先铸一个"哨兵"字符串(形如 oc-sent-v2.<...>.end),认证存储、流选项、SDK 配置、日志、错误对象看到的都是哨兵,不是真值;只有请求真正要离开进程的那一刻,才在 URL 和 Header 里把哨兵换回真值("immediately before each request leaves the process")。

更狠的是 fail-closed 设计:遇到无法识别的哨兵形态,直接拒绝发送,宁可失败也不把未解析的哨兵发给 provider。

这样一来,模型调用链路上大部分环节(日志、报错、SDK 配置)暴露的都是哨兵,真值只出现在最后的适配器边界。官方也诚实地补了一句:"they are not process isolation"——哨兵不是进程隔离,真值仍然存在于同进程内存中。还是那句话:如实转述,不夸大。

六、官方推荐的迁移流程(三步走)

前面讲了原理,这里给可直接照着做的流程。官方在 Audit and configure workflow 里明确列出"默认操作流程":

第一步:审计当前状态

openclaw secrets audit --check

这个命令会找出:配置文件里的明文、SQLite 认证档案行里的明文、.env里的明文、生成文件里的敏感残留、无法解析的引用等。

第二步:配置并应用 SecretRef

openclaw secrets configure --apply

交互式助手,会帮你配置 Provider、选择要保护的字段、采集 SecretRef 细节、做预检并应用。

第三步:重新审计

openclaw secrets audit --check

这里有一条官方划的重点,我认为是整篇文档最重要的一句话:

"Do not treat the migration as complete until the re-audit is clean. If the audit still reports plaintext values at rest, the agent-access risk remains even when runtime APIs return redacted values."—— Secrets management · OpenClaw Docs

只要重新审计还能查到明文,迁移就没完成。因为即使运行时接口显示的是打码值,磁盘上的明文依然会被 agent 读取——这是一个"agent-access boundary(代理访问边界)"的问题,不是靠接口打码能解决的。

七、命令行实操:怎么安全地写入

如果你更习惯用命令行,官方 Secrets CLI 里有两个我认为特别值得记住的点。

第一,secret 类型的值不允许用 --value直接写在命令里。

官方给了明确理由:命令行参数会通过 shell 历史记录和进程列表泄露。所以正确姿势是三种安全输入之一:

  • 管道输入(stdin 非 TTY 时)
  • --value-file <path>
    从文件读
  • 交互式的无回显提示(no-echo prompt)

举个官方示例,从 1Password 读取并写入:

op read 'op://Engineering/OpenAI/apiKey' | \  openclaw secrets store set OPENAI_API_KEY --kind secret

第二,改了值之后要重载运行时快照。

openclaw secrets reload

官方说明:直接命令行写入是本地操作,改完之后要跑一次 reload,让"活跃的内存快照"跟上("so the active in-memory snapshot picks it up")。好消息是——这是原子重载,不需要重启整个服务。

八、给"关键入口"留一条后路

最后说一段文档里没有明说、但我在实践中体会很深的原则。

官方文档提到了一个概念叫"fail-closed owners"——解析失败就拒绝执行的组件。登录 token(gateway.auth.token)就属于这一类。

这意味着:如果你把它也强行 SecretRef 化,一旦解析环节出任何问题(比如值不可取回、源不可用),你就会被锁在自己系统外面。而密钥库里的 secret又是"只写不可读"的——存进去就再也取不出来。

所以我的结论是:关键入口密钥,保留明文的可用性,可能比追求"全盘加密"更重要。这是一种工程权衡,而不是偷懒。文档也支持这个思路——它一再强调"Plaintext still works",就是承认现实世界的可用性需求。

这一点和官方"渐进式、按需迁移"的立场是完全一致的。

总结

把这次实践的核心结论浓缩成一张卡片:

  • 官方立场
    明文可用,SecretRef 是推荐但可选的增强("Plaintext still works")
  • 推荐做法
    日常凭据用共享密钥库的 secret模式(只写不可读),配置里只放 SecretRef 指针
  • 读取机制
    启动时 eager 解析进内存快照,请求只读快照,日志自动打码,模型 Key 还有出网哨兵
  • 迁移流程
    audit --check→ configure --apply→ 再次 audit --check,审计干净才算完成
  • 诚实边界
    密钥库的值"not encrypted at rest",靠文件权限保护;哨兵"不是进程隔离"
  • 可用性权衡
    关键入口(登录 token)建议保留明文,别把自己锁在门外

密钥管理这件事,最怕的不是"做得不够",而是"为了做得漂亮,把系统搞挂"。官方的态度其实很务实:能安全就安全,但要为可用性留余地。

希望这篇能帮你少踩一个坑。

参考资料

  • OpenClaw 官方文档 · Secrets management:https://docs.openclaw.ai/gateway/secrets
  • OpenClaw 官方文档 · Secrets CLI:https://docs.openclaw.ai/cli/secrets
  • OpenClaw 官方文档 · Secrets 工具:https://docs.openclaw.ai/tools/secrets
  • OpenClaw 官方文档 · Secrets apply plan contract:https://docs.openclaw.ai/gateway/secrets-plan-contract
备注:本文源自个人的openclaw实践,并且将处理的过程,利用AI进行了整理总结。

相关学习资料