Skip to content

MongoDB SSL/TLS 配置

证书准备

证书类型

自签名证书

  • 自行生成,无需第三方 CA 认证
  • 适合开发和测试环境
  • 生产环境不推荐,因为无法验证服务器身份

CA 签名证书

  • 由受信任的证书颁发机构(CA)签发
  • 适合生产环境
  • 提供完整的身份验证

链式证书

  • 包含服务器证书、中间 CA 证书和根 CA 证书
  • 确保客户端可以验证服务器证书的完整信任链

生成自签名证书

1. 生成 CA 私钥和证书

bash
# 生成 CA 私钥
openssl genrsa -out ca.key 4096

# 生成 CA 证书签名请求(CSR)
openssl req -new -x509 -days 365 -key ca.key -out ca.crt -subj "/CN=MyMongoDBCA"

2. 生成服务器私钥和 CSR

bash
# 生成服务器私钥
openssl genrsa -out mongodb.key 4096

# 生成服务器 CSR
openssl req -new -key mongodb.key -out mongodb.csr -subj "/CN=mongodb.example.com" -addext "subjectAltName = DNS:mongodb.example.com,DNS:localhost,IP:127.0.0.1,IP:192.168.1.100"

3. 使用 CA 签名服务器证书

bash
# 使用 CA 签名服务器证书
openssl x509 -req -days 365 -in mongodb.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out mongodb.crt

4. 合并证书和私钥

bash
# 合并证书和私钥为 PEM 文件
cat mongodb.crt mongodb.key > mongodb.pem

# 设置权限
chmod 600 mongodb.pem ca.key

证书格式转换

PKCS#12 转 PEM

bash
openssl pkcs12 -in mongodb.p12 -out mongodb.pem -nodes

PFX 转 PEM

bash
openssl pkcs12 -in mongodb.pfx -out mongodb.pem -nodes

单节点 TLS 配置

配置文件设置

mongod.conf

yaml
net:
  port: 27017
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt
    allowInvalidHostnames: false
    allowInvalidCertificates: false
    disabledProtocols: TLS1_0,TLS1_1

security:
  authorization: enabled

命令行参数

bash
mongod --tlsMode requireTLS \
       --tlsCertificateKeyFile /etc/mongodb/mongodb.pem \
       --tlsCAFile /etc/mongodb/ca.crt \
       --tlsAllowInvalidHostnames false \
       --tlsAllowInvalidCertificates false \
       --tlsDisabledProtocols TLS1_0,TLS1_1

副本集 TLS 配置

配置文件示例

所有副本集成员的 mongod.conf

yaml
net:
  port: 27017
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt
    clusterFile: /etc/mongodb/mongodb.pem

security:
  keyFile: /etc/mongodb/keyfile
  authorization: enabled

replication:
  replSetName: rs0

副本集初始化

javascript
// 使用 TLS 连接到主节点
mongo --tls --tlsCertificateKeyFile /etc/mongodb/mongodb.pem --tlsCAFile /etc/mongodb/ca.crt --host mongodb.example.com:27017

// 初始化副本集
rs.initiate({
  _id: "rs0",
  members: [
    { _id: 0, host: "mongodb1.example.com:27017" },
    { _id: 1, host: "mongodb2.example.com:27017" },
    { _id: 2, host: "mongodb3.example.com:27017" }
  ]
})

分片集群 TLS 配置

配置文件示例

mongos 配置

yaml
net:
  port: 27017
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt

security:
  keyFile: /etc/mongodb/keyfile

sharding:
  configDB: configReplSet/config1.example.com:27019,config2.example.com:27019,config3.example.com:27019

分片配置(mongod 作为分片)

yaml
net:
  port: 27018
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt
    clusterFile: /etc/mongodb/mongodb.pem

security:
  keyFile: /etc/mongodb/keyfile
  authorization: enabled

sharding:
  clusterRole: shardsvr

replication:
  replSetName: shard1

配置服务器配置

yaml
net:
  port: 27019
  bindIp: 0.0.0.0
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongodb/mongodb.pem
    CAFile: /etc/mongodb/ca.crt
    clusterFile: /etc/mongodb/mongodb.pem

security:
  keyFile: /etc/mongodb/keyfile
  authorization: enabled

sharding:
  clusterRole: configsvr

replication:
  replSetName: configReplSet

客户端 TLS 连接

MongoDB Shell 连接

使用用户名密码认证

bash
mongo --tls \
      --tlsCAFile /etc/mongodb/ca.crt \
      --host mongodb.example.com:27017 \
      -u admin -p password \
      --authenticationDatabase admin

使用 X.509 证书认证

bash
mongo --tls \
      --tlsCertificateKeyFile /etc/mongodb/client.pem \
      --tlsCAFile /etc/mongodb/ca.crt \
      --host mongodb.example.com:27017 \
      --authenticationMechanism MONGODB-X509 \
      --authenticationDatabase '$external'

MongoDB Compass 连接

  1. 打开 MongoDB Compass
  2. 选择 "Connect"
  3. 填写连接信息:
    • Hostname: mongodb.example.com
    • Port: 27017
  4. 选择 "SSL/TLS" 选项卡
  5. 选择 "Require TLS"
  6. 上传 CA 证书和客户端证书(如果需要)
  7. 点击 "Connect"

驱动连接示例

Python (pymongo)

python
from pymongo import MongoClient

client = MongoClient(
    "mongodb://admin:password@mongodb.example.com:27017/admin",
    tls=True,
    tlsCAFile="/etc/mongodb/ca.crt",
    tlsCertificateKeyFile="/etc/mongodb/client.pem"
)

Node.js (mongodb)

javascript
const { MongoClient } = require('mongodb');

const uri = "mongodb://admin:password@mongodb.example.com:27017/admin";

const client = new MongoClient(uri, {
  tls: true,
  tlsCAFile: "/etc/mongodb/ca.crt",
  tlsCertificateKeyFile: "/etc/mongodb/client.pem"
});

Java (MongoDB Java Driver)

java
import com.mongodb.client.MongoClients;
import com.mongodb.client.MongoClient;
import com.mongodb.MongoClientSettings;
import com.mongodb.connection.netty.NettyStreamFactoryFactory;

MongoClientSettings settings = MongoClientSettings.builder()
    .applyConnectionString(new ConnectionString("mongodb://admin:password@mongodb.example.com:27017/admin"))
    .applyToSslSettings(builder -> {
        builder.enabled(true);
        builder.invalidHostNameAllowed(false);
    })
    .build();

MongoClient client = MongoClients.create(settings);

X.509 认证

配置步骤

  1. 创建 X.509 用户
javascript
use admin
db.getSiblingDB("$external").createUser({
  user: "CN=client.example.com",
  roles: [ { role: "root", db: "admin" } ]
})
  1. 生成客户端证书
bash
# 生成客户端私钥
openssl genrsa -out client.key 4096

# 生成客户端 CSR
openssl req -new -key client.key -out client.csr -subj "/CN=client.example.com"

# 使用 CA 签名客户端证书
openssl x509 -req -days 365 -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt

# 合并为 PEM 文件
cat client.crt client.key > client.pem
  1. 使用 X.509 证书连接
bash
mongo --tls \
      --tlsCertificateKeyFile /etc/mongodb/client.pem \
      --tlsCAFile /etc/mongodb/ca.crt \
      --host mongodb.example.com:27017 \
      --authenticationMechanism MONGODB-X509 \
      --authenticationDatabase '$external'

TLS 配置最佳实践

1. 证书管理

  • 使用受信任的 CA:生产环境使用受信任的第三方 CA 签发的证书
  • 定期轮换证书:证书有效期建议设置为 1 年,到期前及时轮换
  • 安全存储证书:证书和私钥文件权限设置为 600,仅允许所有者访问
  • 建立证书吊销机制:当证书泄露或过期时,及时吊销

2. TLS 协议和加密套件

  • 禁用旧版协议:禁用 TLS 1.0 和 TLS 1.1,只启用 TLS 1.2 和 TLS 1.3
  • 使用强加密套件:配置 MongoDB 使用强加密套件,如 AES-256-GCM
  • 定期更新加密套件:根据安全建议更新加密套件配置

3. 配置验证

  • 验证主机名:设置 allowInvalidHostnames: false,验证证书中的主机名
  • 验证证书有效性:设置 allowInvalidCertificates: false,验证证书的有效性
  • 使用完整的证书链:确保配置了完整的 CA 证书链

4. 监控和审计

  • 监控 TLS 连接:监控 TLS 连接的建立和断开
  • 审计 TLS 配置更改:记录 TLS 配置的更改
  • 定期检查 TLS 配置:使用工具如 ssllabs.com 检查 TLS 配置的安全性

5. 集群配置

  • 所有组件启用 TLS:副本集成员之间、分片集群组件之间都启用 TLS
  • 使用相同的 CA:所有节点使用相同的 CA 证书
  • 配置集群文件:使用 clusterFile 参数配置集群内部通信的证书

TLS 故障排查

常见错误

1. 证书验证失败

错误信息

SSL handshake failed: SSL peer certificate validation failed: self signed certificate

解决方案

  • 确保客户端信任服务器的 CA 证书
  • 检查证书是否过期
  • 检查证书中的主机名是否与实际主机名匹配

2. 协议版本不匹配

错误信息

SSL handshake failed: SSL protocol error: unsupported protocol

解决方案

  • 检查 MongoDB 版本支持的 TLS 协议版本
  • 确保客户端和服务器使用兼容的 TLS 版本
  • 更新 MongoDB 版本或客户端驱动

3. 加密套件不匹配

错误信息

SSL handshake failed: no shared cipher

解决方案

  • 检查客户端和服务器支持的加密套件
  • 配置兼容的加密套件
  • 更新 MongoDB 版本或客户端驱动

4. 私钥权限问题

错误信息

SSL error: Unable to load private key file

解决方案

  • 检查私钥文件的权限(应为 600)
  • 确保 MongoDB 进程可以读取私钥文件
  • 检查私钥文件的路径是否正确

故障排查步骤

  1. 检查 MongoDB 日志:查看 mongod 或 mongos 日志,获取详细的错误信息
  2. 验证证书:使用 openssl 验证证书的有效性
    bash
    openssl x509 -in mongodb.crt -text -noout
  3. 测试 TLS 连接:使用 openssl s_client 测试 TLS 连接
    bash
    openssl s_client -connect mongodb.example.com:27017 -CAfile ca.crt
  4. 检查配置文件:验证 TLS 配置参数是否正确
  5. 检查防火墙设置:确保 MongoDB 端口已开放

TLS 性能影响

性能开销

  • CPU 开销:TLS 加密和解密会增加 CPU 使用率(约 5-10%)
  • 网络开销:TLS 握手会增加连接建立时间
  • 内存开销:维护 TLS 会话会增加内存使用

性能优化

  • 使用硬件加速:使用支持 AES-NI 的 CPU 加速 TLS 加密
  • 启用会话恢复:减少 TLS 握手开销
  • 使用连接池:减少连接建立次数
  • 优化加密套件:选择性能较好的加密套件

常见问题(FAQ)

Q1: MongoDB 支持 TLS 1.3 吗?

A1: 是的,MongoDB 4.2+ 支持 TLS 1.3。建议在生产环境中使用 TLS 1.3,因为它提供了更好的性能和安全性。

Q2: 如何在副本集环境中轮换 TLS 证书?

A2: 轮换副本集 TLS 证书的步骤:

  1. 生成新的证书
  2. 将新证书部署到所有副本集成员
  3. 逐个重启副本集成员(先从副本节点开始,最后重启主节点)
  4. 验证 TLS 连接正常

Q3: 自签名证书和 CA 签名证书有什么区别?

A3:

  • 自签名证书:由自己生成,没有第三方 CA 认证,适合开发和测试环境
  • CA 签名证书:由受信任的证书颁发机构签发,提供完整的身份验证,适合生产环境

Q4: 如何测试 MongoDB 的 TLS 配置是否正确?

A4: 可以使用以下方法测试:

  1. 使用 openssl s_client 测试 TLS 连接
  2. 使用 MongoDB Shell 连接并执行命令
  3. 检查 MongoDB 日志中是否有 TLS 相关错误
  4. 使用 SSL 扫描工具(如 ssllabs.com)检查 TLS 配置

Q5: 客户端连接 MongoDB 需要证书吗?

A5: 这取决于 MongoDB 的配置:

  • 如果 MongoDB 配置了 mode: requireTLS,客户端必须使用 TLS 连接
  • 如果 MongoDB 配置了客户端证书验证,客户端需要提供有效的证书
  • 否则,客户端可以选择是否使用 TLS 连接

Q6: 如何在分片集群中配置 TLS?

A6: 在分片集群中,需要为所有组件配置 TLS:

  • mongos 路由
  • 分片(mongod)
  • 配置服务器(mongod) 所有组件之间的通信都应该使用 TLS 加密,确保整个集群的安全性。