一、事情的起因
事情要从一枚戒指说起。
我给 OpenClaw 写了一个 Oura Ring 健康数据同步的 Skill——每天自动拉取睡眠、心率、活动数据,生成健康日报。Skill 写好了,需要配置 Oura 的 Personal Access Token(PAT)。
按照以前的习惯,我准备直接在 Telegram 里把 token 贴给我的 Agent(没错,就是那只龙虾),让它帮我配到环境变量里。
手指悬在发送键上,突然犹豫了。
“等一下,我把 API Key 直接发到 Telegram 里,这安全吗?”
我问了龙虾。它说:不太安全,建议我看看 OpenClaw 的 SecretRef 机制,支持从 1Password 读取密钥。
这一查不得了。不只是"不太安全"——简直是在裸奔。
二、你的 API Key 发出去之后都去了哪
第一站:Telegram 服务器
你和 Bot 的对话不是端到端加密的(那是 Secret Chat 的专利)。你发出去的每一条消息——包括那串 API Key——都会以明文形式永久存储在 Telegram 的云端服务器上。
“但我可以删消息啊?"——你确定 Telegram 真的从所有备份和副本中物理删除了?
第二站:LLM 的上下文窗口
你的 API Key 不只是"发给了 Agent”。它进入了大语言模型的上下文窗口,成了一段 token。如果你用的是云端模型(大概率是),这意味着你的密钥被发送到了模型提供商的 API 端点。
虽然主流模型提供商声称不会用 API 调用数据训练模型,但这串 key 确实经过了他们的服务器、在他们的内存里被处理过。如果对方出了安全事故呢?
第三站:本地日志和会话存储
OpenClaw 在本地有日志(~/.openclaw/logs/gateway.log),也有会话存储。你在对话里发的 API Key,会作为消息内容被记录下来。任何能访问你电脑的人——或者你自己不小心把日志打包发出去——都能看到。
第四站:openclaw.json
就算 Agent 帮你配好了,那串 key 最终也是以明文躺在 ~/.openclaw/openclaw.json 里:
| |
Time Machine 备份?iCloud 同步?不小心 cat 到屏幕上?一个配置文件,十几个明文密钥,整整齐齐等着被泄露。
你的 API Key 至少在四个地方留下了痕迹:Telegram 云端、LLM 服务器、本地日志、配置文件。
别傻了。
三、发现 OpenClaw 早就准备好了工具
回到 Oura 的事。龙虾让我去翻 OpenClaw 的文档,我发现官方原生支持一套叫 SecretRef 的密钥管理机制——不是第三方插件,不用额外安装,就在核心里。
思路很简单:配置文件里不再直接放密钥的值,而是放一个"指针",告诉 OpenClaw 去别处拿真正的密钥。
我又追问龙虾:“那 openclaw.json 里的十几个密钥,是不是全都能这样处理?”
龙虾帮我查了一圈文档,结论是:
几乎全部都能迁。 SecretRef 支持的字段覆盖了:
- 所有模型提供商的
apiKey和自定义认证头 - 所有搜索引擎的
apiKey(Brave、Perplexity、Grok、Gemini、Kimi) - 所有通信渠道的认证密钥(Telegram、Discord、Slack、Matrix、飞书……)
- Gateway 认证 token / password(2026.3.7 版本新增!)
- TTS 的 API Key(ElevenLabs、OpenAI)
- Cron webhook token、Skill 级别的
apiKey
不能迁的是系统自动生成/轮换的东西:OAuth 刷新令牌、Matrix 的 accessToken、WhatsApp 凭证文件。合理——这些本来就不该由人类手动管理。
简单说:你手动填进去的静态密钥,全都能迁。
特别值得一提的是:2026.3.7 版本开始,channels.telegram.botToken 和 gateway.auth.token 也支持 SecretRef 了。 这是之前版本做不到的。这意味着你的 openclaw.json 可以实现 完全零明文密钥。
四、为什么选 1Password
密钥要从 openclaw.json 搬出去,总得有个地方放。我选了 1Password——不是因为它最好,而是因为它最顺手:
- 不需要额外搞一个系统 — 大部分人已经在用 1P 管理日常密码了,不用再学一套新东西
- 单独 Vault 做隔离 — 建个叫
Agent的 Vault,专门放 AI Agent 用的密钥,和个人密码完全分开 - Vault 级别的只读权限 — 给 Agent 的 Service Account 只开 Agent vault 的读取权限,碰不到你的其他密码
- 随时随地管理 — 手机 App、电脑 App、网页端都能操作。新增一个 API Key?掏出手机在 Agent vault 里建一个 item,告诉你的龙虾"去 1P 拿"就行了。不用开电脑,不用碰终端,不用在聊天里发密钥
- 不需要新账户 — 用你现有的 1P 账户就行,加个 Vault 的事
两种集成方式
1Password CLI(op)提供了两种方式和 OpenClaw 集成:
方式一:桌面 App 集成(交互式)
在 1P 桌面 App 的设置里打开 “Integrate with 1Password CLI”,之后终端里每次调用 op 命令时,桌面 App 会弹出认证窗口——用指纹(Touch ID)、Face ID、Apple Watch 或系统密码授权。
安全性最高(每次操作都有人类授权),但不适合无人值守——你总不能让 Agent 每天凌晨 3 点叫你起来按指纹吧。
适合场景: 你自己在终端里手动管理密钥时用。
方式二:Service Account(无人值守)
1Password 支持创建 Service Account——一个不绑定人类账户的 token,专门给机器用:
- 精确授权只能读取特定 Vault(比如只给 Agent vault 的只读权限)
- 不能写入、不能删除、不能访问其他 Vault
- token 存在本地文件里,Agent 自动读取,全程无需人类介入
适合场景: 让 Agent / Cron 任务无人值守地读取密钥。
我们选方式二。 日常管理(增删改密钥)在手机或电脑上操作 1P;Agent 只负责读取,用 Service Account 就够了。
五、实操开始
前置准备:安装 1Password CLI
macOS 用 Homebrew 一行搞定:
| |
验证安装:
| |
其他平台参考 1Password CLI 官方安装文档
第一步:在 1Password 里建一个专属 Vault
打开 1Password(手机 App 或电脑 App 都行):
- 点击左上角账户名旁边的 "+" 或进入 Settings → Vaults → New Vault
- 名称填
Agent(或任何你喜欢的名字) - 创建完成
这个 Vault 专门放 AI Agent 用的密钥,和你的个人密码完全隔离。
第二步:创建 Service Account
这一步在网页端操作(手机也行,网页更方便):
- 打开 1Password.com 并登录
- 进入 Developer → Directory,在 Infrastructure Secrets Management 下选 Other,然后点 Create a Service Account
- 或直接打开 Service Account 创建向导
- 按向导操作:
- Name:起个名字,比如
openclaw-agent - Create vaults:选 No(不需要创建 vault 的权限)
- Vault access:选择你刚创建的
Agentvault,权限选 Read Items(只读)
- Name:起个名字,比如
- 点 Create Account
- ⚠️ 重要! 页面会显示一个 Service Account Token——这个 token 只显示一次。点 Save in 1Password 把它保存到你的个人 vault 里(不是 Agent vault)
保存好了吗?确认一下。关了页面就再也看不到了。
第三步:把 Service Account Token 存到本地
在终端里执行:
| |
验证 token 能正常工作:
| |
能看到你的 Agent vault?配置成功。
第四步:先拿 Oura 试水
回到最初的问题。Oura 的 PAT 是非关键密钥——搞坏了最多是今天的睡眠数据晚同步几小时,Agent 核心功能不受影响。拿它来做第一个试验。
在 Agent vault 里创建 item:
打开 1Password → 切换到 Agent vault → 新建 item:
- 类型:Password
- 名称:
oura(随便起,不需要和代码里的变量名一致) - password 字段:粘贴你的 Oura Personal Access Token
验证能读到:
| |
吐出了 Oura token 的值。成了。
在 Cron 任务里直接用 1P 读取 token,传给同步脚本:
| |
数据正常同步。第一个密钥成功脱离明文——就是那个差点在 Telegram 里裸发的 Oura PAT。
第五步:胃口变大——清空 openclaw.json
Oura 验证可行之后,我盯上了 openclaw.json 里的十几个明文密钥。
5.1 写同步脚本
创建 ~/.openclaw/sync-secrets.sh——一个从 1P 批量同步到本地 JSON 的脚本:
| |
这个脚本有个巧妙之处:不硬编码密钥列表。它自动枚举 Agent vault 里的所有 item,逐个读取。以后在 1P 里新增一个密钥,跑一次脚本就自动同步。
| |
5.2 在 1P Agent vault 里批量创建 item
打开 1Password,在 Agent vault 里逐个创建(一边喝咖啡一边操作,不用碰终端):
| 1P item 名称 | 对应的 openclaw.json 字段 |
|---|---|
brave | tools.web.search.apiKey |
zenmux1 | models.providers.zenmux1-claude.apiKey |
zenmux2 | models.providers.zenmux2-claude.apiKey |
openclaw-api | models.providers.openclaw-api.apiKey |
perplexity | tools.web.search.perplexity.apiKey |
grok | tools.web.search.grok.apiKey |
gemini | tools.web.search.gemini.apiKey |
kimi | tools.web.search.kimi.apiKey |
每个 item 的 password 字段填对应的 API Key 值。
5.3 同步到本地
| |
5.4 在 OpenClaw 里注册 File Provider
| |
5.5 先拿 Brave Search 试刀
和 Oura 时一样的策略——先迁最不关键的:
| |
id: "/brave" 是 JSON Pointer,指向 secrets.json 里 key 为 brave 的值。
OpenClaw 自动热重载(不需要重启 Gateway),搜索功能正常。
5.6 批量替换剩余密钥
| |
每改一个,OpenClaw 自动热重载,功能无缝切换。
第六步:最后的堡垒——Telegram Bot Token 和 Gateway Auth
这两个是核心中的核心。Telegram token 断了就收不到消息,Gateway auth 断了连不上控制台。
2026.3.7 版本之前,这两个字段不支持 SecretRef——你被迫只能用明文。现在支持了。
在 1P Agent vault 里再创建两个 item:
| 1P item 名称 | password 值 |
|---|---|
botToken | 你的 Telegram Bot Token |
gateway | 你的 Gateway Auth Token |
同步 + 替换:
| |
设完之后,消息收发正常,Gateway 连接正常。
至此,openclaw.json 里零明文密钥。
六、迁移前后对比
迁移前:
| |
迁移后:
| |
干干净净。这个文件现在可以放心备份、甚至公开分享结构——里面看不到任何密钥。
七、日常工作流
迁移完成后,日常操作变得很轻松:
新增一个 API Key:
- 手机上打开 1Password → Agent vault → 新建 item → 填入密钥
- 回到电脑,跑一次
~/.openclaw/sync-secrets.sh - 用
openclaw config set加一个 SecretRef 指向它 - 完事。全程不在聊天里发任何密钥
换一个 API Key:
- 在 1P 里改 item 的值
- 跑一次同步脚本
- OpenClaw 自动热重载。不用重启,不用改配置
新电脑迁移:
- 拷贝
openclaw.json(里面全是 SecretRef,没有明文,放心拷) - 拷贝
.op-token - 跑一次同步脚本
- 搞定
八、安全设计细节
OpenClaw 在密钥管理上有几个值得一提的设计:
- 启动时 fail-fast:任何活跃的 SecretRef 解析失败 → Gateway 直接拒绝启动,不带着残缺密钥运行
- 热重载原子交换:全部解析成功才切换新快照,任何一个失败就保持旧的
- 活跃表面过滤:只验证当前真正在用的密钥。配了 5 个搜索引擎但只启用了 Brave?其他 4 个解析失败不阻塞启动
- config get 自动 redact:
openclaw config get显示 SecretRef 字段时会输出__OPENCLAW_REDACTED__,防止泄露
九、还没搞定的部分
~/.zshrc 里还有些环境变量(ANTHROPIC_API_KEY、GEMINI_API_KEY 等),这些是给 Claude Code 等外部工具用的,暂时没动。迁移它们需要用 op run -- 命令 包裹执行,改动面较大,以后再说。
总结
| 项目 | 数量 |
|---|---|
| 迁移到 1P 的密钥 | 12+ |
| openclaw.json 残留明文 | 0 |
| 整个过程耗时 | ~30 分钟 |
一句话总结:别再在聊天里发 API Key 了。1Password 当保险柜,sync 脚本当搬运工,SecretRef 当钥匙卡。30 分钟搞定,从此 openclaw.json 里干干净净。
你的 AI Agent 帮你管理着越来越多的东西。它的配置文件里密钥的含金量,可能比你想象的高得多。
花 30 分钟,给它装个保险柜。别傻了。