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

我小龙虾的 openclaw.json 里明文存着 27 个 API 密钥。
我之前知道这个问题,但总觉得"以后再说"。直到在群里看到远明分享了一篇文章,他把「OpenClaw」的密钥全部迁进了 1Password,openclaw.json 里实现了零明文。
看完我坐不住了。正好已经用了几年的 1password,所以动手把这个方案实现。
写在前面:
这个方案并不需要在 openclaw 上登录你的 1password 账号,所以不用担心这个方案会暴露你存在 1password 上所有的信息,本质是读取你在 1password 上创建的一个仓库而已。
你的密钥到底裸奔在哪里
文章里列了一个让我印象深刻的清单:当你把 API Key 发给助理,密钥至少在四个地方留下了痕迹。
在 Telegram 云端,你和 Bot 的对话不是端到端加密的,每条消息以明文永久存在 Telegram 服务器上。 LLM 上下文窗口,密钥进入了大语言模型的 token 流,经过了模型提供商的 API 端点。 本地日志,OpenClaw 在本地记录会话,你在对话里发的密钥会被写进日志文件。 还有 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/

夜雨聆风