运维 | 给 AI 助手一把只属于自己的钥匙近期更新
给 AI 助手一把只属于自己的钥匙
那天深夜,我给助手加了个自动备份的看门狗,顺手问了一句:"你每天往网盘里备份的东西,到底传上去没有?"
结果扒出来一个让我后背发凉的事实:它已经连续十四天,在一份从未真正上传成功的备份后面,工工整整地写下"上传成功"。
(一)一份"成功"了半个月的假备份
备份脚本里用的是 curl 把文件推到网盘。curl 有个脾气:服务器返回错误的时候,只要没加那个让它较真的参数,它的退出码照样是零。于是服务器那边分明已经回了"本月上传流量已用尽"的错误,脚本却因为退出码是零,认认真真地打印"上传成功",再把本地旧包清一清,完美收官。
云端最新的一份备份,停在了半个月前。而这一切,没有触发任何告警,因为任务记录里写的也是"成功"。
流量为什么用尽?因为免费账号每个月只有 1GB 的上传额度,而一份完整备份压缩后有两百多兆。一个月三十天,塞不进三个 G 的口袋。
(二)脚本里躺着两行明文密码
修这个问题的时候,我顺手把机器上所有脚本扫了一遍,又发现两处更糙的地方:有两个脚本,把网盘的账号密码和一个加密口令,直接硬编码写在了文件里,一行注释都没有。
这意味着任何能读到脚本的人,都能直接登进那个网盘。而更早的备份包因为没加密,里面还躺着整套服务的密钥。
(三)一把只能开一个抽屉的钥匙
治本的办法,是把机器要用的凭证,收进自建的密码库(Bitwarden 的开源实现,跑在自家服务器上),让脚本按需去取,而不是每个脚本自己揣一份。
但这里有个绕不过去的硬限制:这套协议里,解锁密码库的密钥是由主密码派生出来的,服务端只存密文。也就是说,只要想让机器自己取凭证,机器上就必须留一把能解开某个库的钥匙——没有"纯令牌访问"这种好事。
既然钥匙躲不掉,那就让它的作用范围尽可能小。我没有让助手去拿主账号的主密码,而是给它单独开了一个"专用账号",只放机器要用的那十几条凭据。这样即使机器被攻破,损失被钉死在这个小抽屉里,主账号里那些更重要的东西安然无恙。
(四)新客户端登不进老服务端
接入的过程比想象中曲折。最新版的命令行客户端,怎么都登不进去,报"KDF 配置响应里没有合法的 KDF 类型"。折腾半天才明白:新版客户端要的是新一代的握手字段,而服务端还在用旧结构。最后是把客户端降到一个稳定的旧版本,才终于能登录、解锁、读写。
降级之后一切顺畅:专用账号建好了,账号密码存在机器上一个只读的凭据文件里;顺手发现密码库服务端的域名配置漏了端口号,导致除了网页以外的所有客户端都连不上——这也解释了为什么它一直只有网页能用。
(五)单一真相
最后落地的是一条简单的原则:脚本里不再出现任何明文凭据。一个统一的取凭据脚本,先问密码库,问不到再退回本地的环境文件兜底。改完在"什么都没有"的干净环境里逐个验证:备份、同步、猫砂盆的数据采集,全部跑通,凭据来源清一色是密码库。
顺手把那个假备份也一起治了:备份改成双轨——小而关键的配置每天上云,大而可重建的数据库留在本地和另一台服务器;全程加密,连加密口令都收进了密码库。日志加密口令特意沿用了旧值,因为以前那些归档还得靠它解开。
(六)几句教训
- "成功"两个字,值得你较真到底——退出码是零不代表服务器真的收了,别让"看起来成功"骗过告警。
- 明文密码出现在脚本里,往往是从"临时写死图省事"开始的,然后被遗忘很多年。每次接入新服务,都该问一句:这串东西,现在躺在哪里?
- 协议的版本号会咬人。老服务端配新客户端,失败得无声无息;锁版本、写进文档,比盲目升级更重要。
折腾完这些,机器的凭证终于有了一个像样的安身之处,也终于不会在夜里,对着一个空荡荡的网盘,说"备份成功"了。
最后更新于 2026-10-28 「部分内容存在时效性,如有失效请留言反馈」
除注明外为 袅残烟的冥想盆 原创文章,转载请注明出处。
本作品采用 知识共享署名-相同方式共享 4.0 国际许可协议 进行许可。