不能直接替换keyfile并批量重启,因mongodb内部认证是“全有或全无”,密钥不匹配会导致mongos、shard、config server间握手失败,rs.status()大量显示unreachable,sh.status()卡在“waiting for config server”;必须用yaml格式多密钥文件配合严格分层滚动升级(config→shard→mongos),逐节点降级替换并验证状态后,再清理旧密钥并二次滚动重启。

为什么不能直接替换Keyfile再重启所有节点
直接覆盖所有节点的keyFile并批量重启,会导致集群瞬间失联:mongos、shard、config server之间因密钥不匹配而拒绝握手,rs.status()大量显示UNREACHABLE,sh.status()卡在“waiting for config server”状态。MongoDB内部身份验证是“全有或全无”,没有中间态兼容窗口——除非密钥文件本身支持多密钥共存。
必须用YAML格式密钥文件启用滚动升级
MongoDB 4.2+ 支持在keyFile中写入多个密钥(YAML序列),这是实现无缝轮换的唯一基础。旧密钥和新密钥必须同时存在,且顺序无关,只要至少一个匹配即可完成认证。错误做法包括:
- 用
echo "newkey" > keyfile覆盖——丢失旧密钥,节点立即掉线 - 生成单密钥文件后强行改名复用——权限或长度不合规,
mongod启动报错:key file does not have permissions restricted - 不同节点密钥文件内容不一致(哪怕只差一个空格)——部分节点能连,部分不能,集群分裂
正确生成方式(确保6–1024字节、base64安全、权限600):
openssl rand -base64 756 > /data/mongodb/keyfile chmod 600 /data/mongodb/keyfile chown mongod:mongod /data/mongodb/keyfile
滚动更新顺序:config server → shard副本集 → mongos
顺序错乱会引发配置元数据不一致或路由表错乱。必须严格按角色分层推进,且每个角色内执行“secondary→primary→secondary”降级再轮换:
-
Config server副本集(CSRS):先对两个secondary执行
db.shutdownServer()→ 替换keyFile→ 重启;等新primary选出并稳定(rs.status().myState === 1)→ 对原primary执行rs.stepDown()→ 关机 → 替换 → 重启 - 每个shard副本集:同上流程逐个处理,**不要跨shard并行**;任一shard未完成前,禁止动下一个
-
mongos实例:逐个执行
db.shutdownServer()→ 替换keyFile→ 重启;注意:至少保留2个mongos在线,否则客户端连接中断
每步完成后,必须验证:sh.status()无ERROR,rs.status().members[n].stateStr全为PRIMARY或SECONDARY,且lastHeartbeat时间戳持续更新。
最后一步:清理旧密钥,不是简单删掉
所有节点都已接受新密钥后,不能直接删掉旧密钥字符串——要保留YAML结构,仅移除旧项。例如原文件是:
["old-secret-key-abc123", "new-secret-key-xyz789"]
清理后应为:
["new-secret-key-xyz789"]
然后**再次逐角色滚动重启一次**(config→shard→mongos),这次只带新密钥。跳过这步,旧密钥残留会延长攻击面,且后续无法真正完成密钥生命周期闭环。最容易被忽略的是:mongos重启后,客户端连接池仍可能缓存旧认证上下文,建议配合应用层主动重连或短时抖动容忍。











