AIt杂货铺头像
关注
AI开发牧安 ·第23期 手滑删了生产库,L2 的配置一把没了,机械狗成了趴窝狗。封面图

AI开发牧安 ·第23期 手滑删了生产库,L2 的配置一把没了,机械狗成了趴窝狗。

记录牧安平台从 0 到 1 的开发过程,一个待业在家的网安老兵边做边想。

图片

这一期说点丢人的事情——不是平台挂,是自己把生产库删了

2026-08-31,在云盒上用 WinSCP 维护华为云的 L2环境(线上demo),手一滑在 /opt/Shepherd_l2 目录下误删了几个文件,然后就爽了。

「区域配置信息都丢了」

「agent 注册信息也没了」

一查代码,根因很钝:区域(regions 表)和 agent 注册(agents 表)都在同一个 safety-net.db 里。丢了这个 SQLite 文件,进程下一个请求发现路径没了,当场给你重建一个空库——所以 UI 表现为"全部配置凭空消失",但服务不崩、进程还活着。


这一期把这次事故从头到尾捋一遍:怎么没的、为什么没救回来、我又怎么把同类事故系统性堵死。做 MSS 的人自己把客户平台的配置库删了还没备份,这事我必须写下来,事故是因,改进才是果。

一、事故概述:一次误删,放大成不可逆

本质就一句话:safety-net.db 单文件被删,库内全部业务数据清空

数据类别

存储表

是否受影响

机构信息

customers

是(同文件,推断一并清空)

区域信息

regions是(用户已确认)

agent 注册信息

agents是(已确认),含 agent_token/agent_token_secret 等凭据

用户/告警/扫描

users

/agent_alerts/agent_scans 等

是(同文件)

代码没坏,丢的是数据。云上数据恢复很繁琐——估计我是搞不定了。

所以这篇的重点是根因复盘 + 防再发,不是数据找回。

二、为什么删完"全空"且难救

这里有个机制上的坑,值得所有用 SQLite 的人注意。(版本功能定完了会改成对接其它数据库)

放大原因 1 · 连接机制把损失坐实了。db.get_connection()(db.py:40)每次请求都 sqlite3.connect(DB_FILE) 新建连接。文件被 rm 后,下一个请求发现路径不存在 → SQLite 当场新建一个空的 safety-net.db(只有表结构、没数据)。UI 显示"全空",但进程不崩;旧数据的 inode 在连接关闭后立刻释放,能抢救的窗口极短。

放大原因 2 · 无进程内存兜底。 核心配置不在进程内存常驻,删文件即意味着数据没法经 /proc/<pid>/fd 长期存活恢复。

合起来:误删 → 空库顶上 → UI 全空 → 旧数据瞬间释放。等我发现,已经没救了。

深层是系统性缺陷:

图片

三、已落地的改进:把"同类事故"系统性堵死

先说方案:

当机构、区域、agent注册、日志外发等信息在web填写之后 落库的同时 也落到后台的一个文件中(要加密存储)当数据库文件损坏 可以在后台手动导这个文件进去恢复这些信息

再往下的内容让硅基自己看吧,碳基看起来有点费脑子。

3.1 核心配置加密备份 Vault(防再发主方案)

  • 新增 vault.py

    :AES-256-GCM 加密;密钥优先级 SHEPHERD_VAULT_KEY 环境变量 → 兜底 backup_vault/vault.key(0600,首次自动生成);原子写(临时文件→fsync→os.replace)。

  • 新增 restore_vault.py

    :CLI(--mode upsert|replace)+ 可复用的 do_restore()。解密 → 按原主键 upsert 回 customers/regions/agents/user_customers → 修正 sqlite_sequence → 还原日志外发配置。

  • 落库即快照

    create/update/delete_customercreate/update/delete_region 六个函数 commit 后自动 snapshot_vault();agent 注册/状态/删除 handler、日志外发配置落盘处同步触发;并加 5 分钟定时快照线程兜底防漏钩。

  • 手动恢复入口

    :CLI python3 restore_vault.py;管理端点 POST /api/admin/vault/restore(admin 鉴权 + 审计)。

  • 失败不阻断主业务

    :vault 快照/初始化任何异常均静默告警,绝不抛入业务请求。

3.2 顺手根治了路径不一致

Shepherd_l2_app.py 40+ 处 sqlite3.connect('safety-net.db') 全部统一为 sqlite3.connect(db.DB_FILE)split-brain 隐患消除

3.3 验证结果(独立临时目录,未污染真实库)

验证项

结果

写入机构/区域/agent/日志外发 → 快照生成且可独立解密,四类齐全

模拟 rm safety-net.db 重建空表 → 恢复后 PK/FK/自增计数一致

篡改 vault 任一字节 → 恢复报 InvalidTag(GCM 认证失败),拒绝写入

四个改动文件 py_compile

四、三层防护,删库也不怕了

这次改造的目标不是"别误删"(那是流程的事),而是"就算删了,也能秒回"。最终形成三层保护:

手段

防什么

实时可恢复

Vault 加密快照,落库即拍(含 5 分钟兜底线程)

文件损坏、误删、配置丢失

历史可回滚

待补的每日 sqlite3 .dump cron(0 4 * * * gzip 留档)

大表历史版本、误改回退

冗余防整机

密钥 + 一份 .vault.enc 离线备份到其他机器/密码管理器

整机没了(同盘只能防文件损坏)

Vault 管敏感配置实时可恢复,cron 管大表历史回滚,离线密钥管整机丢失——三道互补,没有单点了。

图片

五、还得人工兜底的:运维规范

改进里有一项工具救不了,只能靠制度:

  • 禁止 WinSCP / 直连生产机删除文件;
  • 变更前"停服 → 确认 → 操作 → 校验";
  • 引入变更复核(双人)。

删文件前没停服、没二次确认,这是流程问题。再好的备份,也挡不住一个在生产机上随手 rm 的人。这条得靠规矩拴住。

其余待办:上云部署(sftp 推 vault 相关文件 + pip install cryptography + 重启自动生成密钥并开始快照)、每日 dump cron、密钥离线备份、上云后做一次 rm → restore 恢复演练。

六、说句实话

根因链条很清楚:无备份(主因)叠加"每次请求新建连接、删库即空库顶上"的机制,把一次可恢复的误删,放大成了不可逆的丢失。

给自己这次的改进打个及格:数据虽放弃找回,同类事故已经被系统性堵住——落库即加密快照 + 手动恢复 + 路径统一 + 待补的每日 dump,三层保护成型。唯一还得靠人兜底的,是运维那点规矩。

转载自 CSDN-专业IT技术社区

原文链接:https://blog.csdn.net/yzn00/article/details/165961107

文章来源转载

评论

赞0

评论列表

微信小程序
QQ小程序

关于作者

点赞数:0
关注数:0
粉丝:0
文章:0
关注标签:0
加入于:--