mongodb x.509证书轮换需滚动替换文件、主动重载(db.rotatecertificates())、客户端重建连接池三者协同;该命令仅重读证书文件,不生成分发证书,且须严格匹配extensionvalue或dn字段,顺序为secondary→primary→secondary,并清理tlsclusterauthx509override。

证书过期不是改个配置重启就能解决的事,必须滚动替换文件 + 主动触发重载 + 客户端重建连接池,三者缺一不可。
db.rotateCertificates() 只是 reload 信号,不生成也不分发新证书
这个命令只让 mongod 重新读取 certificateKeyFile、clusterFile、CAFile 指向的文件内容,它不做任何证书签发、校验或分发。调用前你必须已把新证书原子写入对应路径,且权限正确(如 600),否则会加载失败或静默使用旧内容。
- 常见错误:脚本生成新证书后直接调用
db.rotateCertificates(),但文件还没落盘或权限不对,mongod 日志里只报Failed to load TLS certificate却无进一步提示 - 必须确保新证书的
subjectKeyIdentifier或自定义 OID 扩展值,与配置中net.tls.clusterAuthX509.extensionValue的值严格一致(区分大小写、空格、换行) - 如果用了
net.tls.clusterAuthX509.attributes做 DN 匹配,新证书的O、OU等字段必须完全匹配,否则 secondary 无法连 primary
副本集滚动轮换顺序不能乱:secondary → primary → secondary
先对所有 secondary 节点执行证书替换 + db.rotateCertificates(),等它们全部完成并稳定后再操作 primary;primary 切换完,再回头确认 secondary 是否仍能正常心跳。顺序反了会导致 primary 在轮换中拒绝来自旧证书 secondary 的连接,引发短暂脑裂或选举中断。
- 不要并发执行:即使脚本写了 for 循环,也要加 sleep 或健康检查等待上一个节点
rs.status().members[n].stateStr === "SECONDARY"再继续 - primary 切换后,立刻查
rs.status().myState和rs.status().members[n].health,确认所有成员状态恢复正常 - 若集群启用了
tlsClusterAuthX509Override(用于 DN 迁移过渡),记得在全部节点更新完毕后删掉该参数,否则旧证书仍可接入
Python 客户端不重建连接池 = 白换
PyMongo 默认复用 TLS 会话,哪怕服务端证书已换,只要 TCP 连接没断,就继续走旧 session key,直到超时或主动 close。这不是 bug,是 TLS 1.2+ 的标准行为。
- 必须显式调用
client.close()再新建MongoClient实例,或使用连接池自动刷新策略(如设置minPoolSize=0+maxIdleTimeMS=30000) - certifi 不是银弹:仅安装
certifi没用,必须传tlsCAFile=certifi.where();若用 PyInstaller 打包,还要确保certifi的 PEM 文件被正确嵌入资源路径 - 绝对别用
tlsAllowInvalidCertificates=True上线——它跳过有效期和域名检查,但不解决连接复用问题,且会让后续真实证书错误难以暴露
Vault 或自研脚本必须覆盖四个静默失败点
自动化工具最容易在以下环节无声失败,日志里几乎不报错,但连接就是断断续续:
- OpenSSL 生成证书时漏了
-addext "subjectAltName = DNS:rs0.example.com,IP:10.0.1.5",导致 TLS 握手直接被拒(mongod 不打日志,客户端报ssl.SSLError: certificate verify failed) - 新证书的
extensionValue与 mongod 配置不一致,尤其注意 base64 编码后是否含换行符、空格 - 滚动顺序未按 secondary → primary → secondary 执行,或某个 secondary 被跳过
-
clusterCAFile指向的 CA bundle 里还混着旧 CA,新成员加入时因验证链断裂而无法握手
真正麻烦的从来不是换证书这件事本身,而是旧连接池、旧 TLS session、旧 CA bundle 这三样东西藏得深、不报错、只在高峰流量时偶然失效。











