必须用OpenSSL生成含完整SAN的证书,因mkcert和Let’s Encrypt证书不满足MongoDB副本集对DNS名称和IP地址全覆盖的SAN要求;mongod启动时若漏配net.tls.certificateKeyFile、net.tls.CAFile或net.tls.mode任一字段,将静默失败或拒绝TLS连接。

必须用 OpenSSL 生成含完整 SAN 的证书,不能直接用 mkcert 或 Let’s Encrypt 证书;mongod 启动时若漏配 net.tls.certificateKeyFile、net.tls.CAFile、net.tls.mode 中任一字段,会静默失败或拒绝 TLS 连接。
证书必须包含所有节点的 DNS 和 IP 地址(SAN)
副本集每个节点访问入口不止一个:比如 node1.example.com、192.168.1.10、127.0.0.1。OpenSSL 默认 CSR 不带 SAN,直接签发会导致客户端报 SSL peer certificate validation failed。
正确做法是显式加 -addext(OpenSSL 1.1.1+)或用配置文件指定:
- 生成 CSR 时加:
openssl req -new -key node1.key -out node1.csr -addext "subjectAltName = DNS:node1.example.com,IP:192.168.1.10,IP:127.0.0.1" - 或写
sans.cnf文件,用-extfile sans.cnf -extensions req_ext引入 - 签发时必须确保
keyUsage = digitalSignature, keyEncipherment且extendedKeyUsage = serverAuth - 用
openssl x509 -in node1.pem -text -noout | grep -A1 "Subject Alternative Name"检查是否生效
mongod 配置必须填满三个 net.tls 字段
net.tls.mode: requireTLS 只是开关,真正起效靠另外两个字段。缺一不可,否则日志无明确报错,但连接会被拒绝或降级为明文。
-
net.tls.certificateKeyFile:必须是 PEM 格式,且私钥不能加密(即文件里不能有DEK-Info行),否则启动报Failed to load certificate file: bad password -
net.tls.CAFile:即使只做单向 TLS(服务端认证),也建议填上自建 CA 的ca.crt,否则 mongosh 等新驱动默认校验失败 -
net.tls.allowConnectionsWithoutCertificates: true:设为true才允许不带客户端证书的连接;设false则强制双向认证,但副本集内部通信也会被拦——除非你同时配了net.tls.clusterFile
副本集成员间通信也要显式启用 TLS
即使所有节点都开了 requireTLS,心跳和 oplog 同步默认仍走明文。不配 net.tls.clusterFile,从节点会卡在 STARTUP2,日志反复刷 no SSL certificate provided 或 connection refused,但主节点状态仍是 PRIMARY。
-
net.tls.clusterFile必须指向一个单独的 PEM 文件,内容是该节点自己的私钥 + 证书(可复用certificateKeyFile,但 MongoDB 官方建议隔离) - 该文件权限必须是
600,否则启动失败 - 所有节点的
clusterFile必须由同一 CA 签发,否则集群无法完成认证握手 - 如果用 x.509 做内部认证,需提前在
$external数据库创建用户,例如:db.getSiblingDB("$external").createUser({user: "CN=node1.example.com", roles: [{role:"clusterAdmin", db:"admin"}]})
客户端连接必须显式声明 tls 参数
mongosh 不会自动探测服务端是否启用了 TLS,不加参数就按普通 TCP 连,连上立刻断开,错误通常是 connection ended 或 SSL handshake failed。
- 命令行:
mongosh --tls --tlsCAFile /path/to/ca.crt "mongodb://node1.example.com:27017/?replicaSet=rs0" - Node.js:
MongoClient('mongodb://node1.example.com:27017/', { tls: true, tlsCAFile: '/path/to/ca.crt' }) - Python PyMongo:
MongoClient('mongodb://node1.example.com:27017/', tls=True, tlsCAFile='/path/to/ca.crt') - 注意:旧版驱动用
ssl=True,新版统一用tls=True;混用会导致连接成功但数据明文传输
最容易被忽略的是时间同步——所有副本集节点系统时间差不能超过 5 分钟,否则 TLS 握手直接失败,错误信息可能只显示 generic SSL handshake failed,实际是证书有效期校验不过。


















