**如何配置 ReplicaSet 以支持 TLS/SSL?

我们将在本地环境中部署一个 3 节点 ReplicaSet,并使用自签名证书。请勿在生产环境中使用自签名证书。

**如何将客户端连接到此 ReplicaSet? 我们将连接 Mongo Shell。

关于 TLS/SSL、PKI(公钥基础设施)证书和证书颁发机构的描述超出了本文档的范围。

Section 18.1: 如何配置 ReplicaSet 以支持 TLS/SSL?

创建根证书 根证书(又名 CA 文件)将用于签署和识别证书。要生成根证书,请运行以下命令。

openssl req -nodes -out ca.pem -new -x509 -keyout ca.key

请妥善保管根证书及其密钥,它们都将用于签署您的证书。根证书也可能被客户使用。

生成证书请求和私钥

生成证书签名请求(又称 CSR)时,请在通用名称(又称 CN)字段中输入节点的准确主机名(或 IP)。其他字段的值必须完全相同。您可能需要修改 /etc/hosts 文件。

下面的命令将生成 CSR 文件和 RSA 私钥(4096 位)。

openssl req -nodes -newkey rsa:4096 -sha256 -keyout mongodb_node_1.key -out mongodb_node_1.csr
openssl req -nodes -newkey rsa:4096 -sha256 -keyout mongodb_node_2.key -out mongodb_node_2.csr
openssl req -nodes -newkey rsa:4096 -sha256 -keyout mongodb_node_3.key -out mongodb_node_3.csr

您必须为 ReplicaSet 的每个节点生成一个 CSR。请记住,不同节点的通用名称是不一样的。不要将多个 CSR 建立在同一个私钥的基础上。

现在您必须有 3 个 CSR 和 3 个私钥。

mongodb_node_1.key - mongodb_node_2.key - mongodb_node_3.key
mongodb_node_1.csr - mongodb_node_2.csr - mongodb_node_3.csr

签署证书请求

运行下面的命令,使用之前生成的 CA 文件 (ca.pem) 及其私钥 (ca.key) 签署每个证书请求。

openssl x509 -req -in mongodb_node_1.csr -CA ca.pem -CAkey ca.key -set_serial 00 -out
mongodb_node_1.crt
openssl x509 -req -in mongodb_node_2.csr -CA ca.pem -CAkey ca.key -set_serial 00 -out
mongodb_node_2.crt
openssl x509 -req -in mongodb_node_3.csr -CA ca.pem -CAkey ca.key -set_serial 00 -out
mongodb_node_3.crt

**您必须签署每份 CSR。

现在你必须有 3 个 CSR、3 个私钥和 3 个自签名证书。MongoDB 将只使用私钥和证书。

mongodb_node_1.key - mongodb_node_2.key - mongodb_node_3.key
mongodb_node_1.csr - mongodb_node_2.csr - mongodb_node_3.csr
mongodb_node_1.crt - mongodb_node_2.crt - mongodb_node_3.crt

每个证书对应一个节点。请仔细记住您为每个 CSR 提供的 CN/主机名。

将每个节点证书与其密钥在一起

运行以下命令,将每个节点证书及其密钥连接到一个文件中(MongoDB 要求)。

cat mongodb_node_1.key mongodb_node_1.crt > mongodb_node_1.pem
cat mongodb_node_2.key mongodb_node_2.crt > mongodb_node_2.pem
cat mongodb_node_3.key mongodb_node_3.crt > mongodb_node_3.pem

现在您必须有 3 个 PEM 文件。

mongodb_node_1.pem - mongodb_node_2.pem - mongodb_node_3.pem

部署副本集

我们假设你的 pem 文件位于当前文件夹以及 data/data1、data/data2 和 data/data3 中。

运行以下命令,部署监听端口为 27017、27018 和 27019 的 3 节点 ReplicaSet。

mongod --dbpath data/data_1 --replSet rs0 --port 27017 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_1.pem
mongod --dbpath data/data_2 --replSet rs0 --port 27018 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_2.pem
mongod --dbpath data/data_3 --replSet rs0 --port 27019 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_3.pem

现在,您已在本地环境中部署了一个 3 节点 ReplicaSet,其所有事务都已加密。如果不使用 TLS,则无法连接到此 ReplicaSet。

为相互 SSL / 相互信任部署 ReplicaSet

要强制客户提供客户证书(相互 SSL),必须在运行实例时添加 CA 文件。

mongod --dbpath data/data_1 --replSet rs0 --port 27017 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_1.pem --sslCAFile ca.pem
mongod --dbpath data/data_2 --replSet rs0 --port 27018 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_2.pem --sslCAFile ca.pem
mongod --dbpath data/data_3 --replSet rs0 --port 27019 --sslMode requireSSL --sslPEMKeyFile
mongodb_node_3.pem --sslCAFile ca.pem

现在,您已在本地环境中部署了一个 3 节点 ReplicaSet,其所有事务均已加密。

如果不使用 TLS 或不提供 CA 信任的客户端证书,就无法连接到该 ReplicaSet。

Section 18.2: 如何将客户端(Mongo Shell)连接到 ReplicaSet?

无相互 SSL 在本示例中,我们可能会使用在 "如何配置 ReplicaSet 以支持 TLS/SSL?我们假设 CA 文件位于当前文件夹中。

我们将假设 3 个节点分别运行在 mongo1:27017、mongo2:27018 和 mongo3:27019。(您可能需要修改 /etc/hosts 文件)。

从 MongoDB 3.2.6 开始,如果 CA 文件已在操作系统信任存储中注册,则无需提供 CA 文件即可连接到 ReplicaSet。

mongo --ssl --host rs0/mongo1:27017,mongo2:27018,mongo3:27019

否则,您必须提供 CA 文件。

mongo --ssl --sslCAFile ca.pem --host rs0/mongo1:27017,mongo2:27018,mongo3:27019

您现在已连接到 ReplicaSet,Mongo Shell 和 ReplicaSet 之间的所有事务都已加密。

使用相互 SSL

如果 ReplicaSet 要求提供客户证书,你必须提供由 ReplicaSet 部署使用的 CA 签发的证书。生成客户端证书的步骤与生成服务器证书的步骤几乎相同。

事实上,您只需在创建 CSR 时修改 Common Name 字段。您需要提供所有 ReplicaSet 主机名,而不是在 Common Name 字段中提供 1 个节点主机名,中间用逗号隔开。

openssl req -nodes -newkey rsa:4096 -sha256 -keyout mongodb_client.key -out1,
            "stateStr" : "PRIMARY",
            ...........................
        },
        {
            "_id" : 1,
            "name" : "<hostname>:27018",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            ...........................
        },
        {
            "_id" : 2,
            "name" : "<hostname>:27019",
            "health" : 1,
            "state" : 2,
            "stateStr" : "SECONDARY",
            ...........................
        }
    ],
    "ok" : 1
}