乐于分享
好东西不私藏

OpenClaw进阶:别让API密钥裸奔,1Password实战

OpenClaw进阶:别让API密钥裸奔,1Password实战

大家好,我是青澈君,一个喜欢捣鼓openclaw的80后,顺便学学Vibe Coding,也在坚持写日记。

我小龙虾的 openclaw.json 里明文存着 27 个 API 密钥。

我之前知道这个问题,但总觉得"以后再说"。直到在群里看到远明分享了一篇文章,他把「OpenClaw」的密钥全部迁进了 1Password,openclaw.json 里实现了零明文。

看完我坐不住了。正好已经用了几年的 1password,所以动手把这个方案实现。

写在前面:

这个方案并不需要在 openclaw 上登录你的 1password 账号,所以不用担心这个方案会暴露你存在 1password 上所有的信息,本质是读取你在 1password 上创建的一个仓库而已。

你的密钥到底裸奔在哪里

文章里列了一个让我印象深刻的清单:当你把 API Key 发给助理,密钥至少在四个地方留下了痕迹。

  1. 在 Telegram 云端,你和 Bot 的对话不是端到端加密的,每条消息以明文永久存在 Telegram 服务器上。
  2. LLM 上下文窗口,密钥进入了大语言模型的 token 流,经过了模型提供商的 API 端点。
  3. 本地日志,OpenClaw 在本地记录会话,你在对话里发的密钥会被写进日志文件。
  4. 还有 openclaw.json 本身,Time Machine 备份?iCloud 同步?不小心 cat 到屏幕上?一个配置文件,几十个明文密钥,整整齐齐等着被泄露。

我跑了一遍审计,扫出 328 条明文引用,去重约 35 个独立密钥。

那一刻决定:这笔账现在就还。

我直接把需求发给了助理:

我想把 openclaw.json 里的所有明文密钥迁移到 1Password。请帮我:1)扫描配置文件,列出所有明文密钥字段;2)给出完整的迁移步骤,包括 1Password 的配置和 openclaw.json 的改法。我用的是 macOS + launchd,网关以 daemon 方式启动。

助理查了文档,提供了两种方案,然后我选了一个。

方案怎么选

「OpenClaw」原生支持一套叫 SecretRef 的密钥管理机制,思路是:配置文件里不放密钥的值,只放一个"指针",告诉「OpenClaw」去别处拿真正的密钥。

落地上有两种方式。

方案 A(file provider):写一个同步脚本,定期从 1Password 拉密钥,存到本地 secrets.json,「OpenClaw」从文件读。密钥还是以明文存在磁盘上,只是换了个文件名,但比直接放在 openclaw.json 里,风险收窄不少。

方案 B(exec provider 直连):把每个密钥字段改成 SecretRef 对象,「OpenClaw」启动时直接调 op read 实时读取,内存里用,不落盘。理论上最干净,但启动时需要等所有 op 进程跑完,26 个密钥大约要 30-40 秒。

我先选了方案 B,也就是更优雅的那个。后来折腾了一圈,最终落地的是改良版方案 A,下面讲。

完整实现步骤

第一步:建专用保险库

打开 1Password,新建一个 Vault,名字叫「OpenClaw」(按自己喜欢取就行),专门放 AI 助理用的密钥,和个人密码完全隔离。

第二步:创建 Service Account

在 1password.com 网页端,进入 Developer → Service Accounts,新建一个账户,只授权 OpenClaw vault 的"读取"权限。创建完成页面会显示 Service Account Token,只显示一次,立刻保存好。

这个 token 存进 launchd plist 的 EnvironmentVariables,让网关启动时能读到。

第三步:安装 op CLI

Mac 上一行搞定:

bash

brew install --cask 1password-cli

验证能用:

bash

OP_SERVICE_ACCOUNT_TOKEN=你的token op vault list

能看到 OpenClaw vault,就行了。

第四步:批量导入密钥

用 Python 脚本从 openclaw.json 提取所有明文密钥,生成 CSV,导入 1Password 的 OpenClaw vault。全程约 30 分钟。

一个细节:CSV 导入时表头行会被当成一条数据,进去之后手动删掉那条标题为"Title"的空条目(这种坑只有踩过才知道)。

第五步:改配置

每个密钥字段从明文改成 SecretRef 对象:

json

"apiKey":{"source":"exec","provider":"op-brave-search","id":"value"}

对应的 provider 定义:

json

"op-brave-search":{"source":"exec","command":"/opt/homebrew/bin/op","args":["read","op://OpenClaw/{条目UUID}/password"],"passEnv":["HOME","OP_SERVICE_ACCOUNT_TOKEN"]}

25 个 provider,对应 25 条密钥。配置文件里没有一个明文密钥。

然后翻了两次车

第一次:launchd 没有环境变量

迁移完第一条密钥,执行网关重启,然后网关开始反复崩溃:Exec provider exited with code 1,接着 Gateway failed to start: required secrets are unavailable

查了 12 分钟才找到根因:OP_SERVICE_ACCOUNT_TOKEN 只写进了 ~/.zshrc。在终端里 op read 完全正常,但网关是 launchd daemon 启动的,launchd 不读 .zshrc。

修复:把 token 补进 launchd plist 的 EnvironmentVariables。网关立刻恢复正常。

教训:shell 测试通过不等于服务环境能跑。exec provider 依赖的环境变量,必须同时配到 launchd plist 里。

第二次:无限重启循环,持续 40 分钟

全量迁移 30 个字段后,网关每约 80 秒重启一次,从 08:05 到 08:40 循环了 20 多次。

表面上网关在"运行",实际一直在重启。助理发出的消息全被 drain 拦截,外面看起来完全正常,里面已经瘫了。这种状态持续了 40 多分钟我才发现。

根因是 openclaw-aicodewith-auth 插件。它每次启动都会修改 openclaw.json(更新 provider config),触发文件变更监听,然后 config reload → SIGUSR1 重启 → 再次启动,无限循环。修复很无奈:把 aicodewith 的 3 个密钥改回明文,禁用那个插件。

这次比第一次难查,因为没有明显报错,就是一直在重启。"好像在运行"是比"明显崩溃"更难诊断的故障状态。

Ps:这个问题只要没用 aicodewith 就可以无视。

最终落地:退一步,更稳

折腾一圈,稳定架构是:27 个密钥中 24 个走 SecretRef,3 个 aicodewith 保留明文。

同时做了一个关键调整:把 exec provider 的读取方式,从"启动时实时调 op read"改成了 file provider 模式——网关启动前先跑一次同步脚本,把最新密钥写进本地 secrets.json,「OpenClaw」从文件读。

这是远明文章里用的方案。兜了一圈,最终落回了更稳的选择。

不一样的地方在:同步脚本用 op item list --vault OpenClaw 自动发现所有条目,不硬编码任何 item。新增密钥不需要改脚本,在 1Password 里加了条目,跑一次同步就生效。网关启动 wrapper 保证每次重启都先同步,密钥永远是最新的。

26 个 exec provider 启动需要 30-40 秒。file provider 读本地文件,瞬间完成。

更稳,也更快。

有一个没解的问题

Service Account Token 本身以明文存在 launchd plist 文件里。这是 launchd 的限制,绕不开。

所以这套方案不是"零风险"——一把钥匙还在磁盘上。但比起 27 把钥匙全裸奔,风险面收窄了 96%。那个 token 只有 OpenClaw vault 的只读权限,即使泄露,影响范围也有限。

完美方案不存在,这已经是 launchd 环境下能做到的最优解。

另外,朋友说过一句:用 1Password 每次要指纹授权,太麻烦。这个误解比我想象的常见——Service Account + op CLI 模式不需要桌面 App,不需要指纹,完全无人值守自动化。

现在是什么状态

日常操作变成这样:

新增密钥,在 1Password 里建条目,告诉助理条目名,助理改配置 + 同步 + 重启,完成。修改密钥,在 1Password 里改值,同步一次,生效。

我不需要记任何 UUID 或 op:// 路径。配置文件的活全交给助理干。

密钥安全这件事,是一笔早还比晚还省心的技术债。

之前"以后再说"了很久。动手之后发现最难的不是配置,是两次翻车之后还没放弃。结果证明,值得。

如果你也在跑「OpenClaw」或者其他本地 AI 框架,配置文件里的明文密钥是第一个值得认真对待的安全问题。你用的是什么方案?欢迎留言聊聊。

延伸阅读:远明的原版文章,比我写得更系统,还有完整的代码和迁移对比。

《还在把 API Key 发给你的龙虾么?别傻了》

https://blog.yuanming.ai/posts/openclaw-1password-secrets/