这是一个老问题,然而我也遇到了同样的问题,花了很多时间才解决。有些要点在文档中相当重要,但却隐藏得很深。
我试着概述一下,而不是简单地从MongoDB文档中复制粘贴。
通常情况下,MongoDB中的x.509证书提供以下功能:
- 生成用于加密连接的密钥
- 确保连接建立在正确的主机上(即声明的主机名与实际主机名匹配)
- 对客户端进行身份验证(而不是使用用户名+密码或密钥文件)
作为起点,应该参考这些教程。
TLS/SSL设置在这个配置文件部分中定义:
net:
tls:
certificateKeyFile: server.pem
CAFile: server-ca.crt
clusterFile: member.pem
clusterCAFile: cluster-ca.crt
它们对应于命令行选项
--tlsCertificateKeyFile server.pem
--tlsCAFile server-ca.crt
--tlsClusterFile member.pem
--tlsClusterCAFile cluster-ca.crt
所有其他与TLS/SSL相关的参数都有很好的文档记录,通常不会引起任何混淆或误解。
第一步
当客户端尝试建立一个启用了TLS/SSL的连接时,mongod/mongos
服务器会呈现一个服务器证书。客户端使用CA验证此证书。
一个客户端可以是普通客户端(例如Mongo shell mongosh
)或者是内部副本集/分片集群成员
服务器证书始终相同,mongod/mongos
不区分客户端类型
服务器证书由参数定义
net.tls.certificateKeyFile
或--tlsCertificateKeyFile
普通客户端可以通过以下方式验证服务器证书:
选项--tls --tlsCAFile server-ca.cer
选项--tls --tlsUseSystemCA
连接字符串参数tls=true&tlsCAFile=server-ca.cer
--tlsUseSystemCA
只能作为选项存在,不能在连接字符串中定义。类似于:
mongosh --tlsUseSystemCA "mongodb://localhost/?tls=true"
内部副本集/分片集群成员通过参数验证服务器证书
net.tls.CAFile
或--tlsCAFile
如果未指定net.tls.CAFile
或--tlsCAFile
,并且您未使用x.509身份验证,则将使用系统范围的CA证书存储。如果使用x.509身份验证,则需要net.tls.CAFile
或--tlsCAFile
。
第二步
客户端向 mongod/mongos
服务器提供一个客户端证书。客户端证书可用于对用户进行身份验证。在这种情况下,您不需要提供密码/密钥文件。
- 对于普通客户端,可以通过创建用户来启用 x.509 身份验证,例如:
db.getSiblingDB("$external").runCommand({createUser: "CN=myName,OU=myOrgUnit,O=myOrg,..."})
- 对于副本集/分片集群成员,可以通过参数
security.clusterAuthMode: x509
来启用 x.509 身份验证
普通客户端(例如 mongosh
)可以通过以下参数提供客户端证书的示例:
mongosh --tls --tlsCertificateKeyFile client.pem
(无 x.509 认证)
mongosh --tls --authenticationDatabase $external --authenticationMechanism MONGODB-X509 --tlsCertificateKeyFile client.pem
(使用 x.509 认证)
mongosh "mongodb://username:secret@localhost/?tls=true&authSource=admin&tlsCertificateKeyFile=client.pem"
(无 x.509 认证)
mongosh "mongodb://localhost/?tls=true&authSource=$exernal&tlsCertificateKeyFile=client.pem&authMechanism=MONGODB-X509"
(使用 x.509 认证)
内部副本集/分片集群成员通过参数 net.tls.clusterFile
或 --tlsClusterFile
提供成员证书
monogd/mongos
服务器使用由参数net.tls.clusterCAFile
或--tlsClusterCAFile
定义的Root-CA来验证客户端/成员证书。
- 客户端可以是普通客户端(例如Mongo shell
mongosh
)或内部副本集/分片集群成员。
- Root-CA始终相同,
mongos/mongod
不区分客户端证书和成员证书。
- 如果未定义
net.tls.clusterCAFile
或--tlsClusterCAFile
,则使用net.tls.CAFile/--tlsCAFile
进行验证。
注意事项:
一些Mongo文档只是提到“客户端”证书/连接。请注意,这意味着普通客户端(例如`mongosh`)以及内部副本集/分片集群成员客户端。在本答案中,我使用术语“客户端证书”和“成员证书”以便更好地理解。
服务器证书和成员证书的主题名称中必须具有相同的`O`、`OU`和`DC`。
客户端证书和成员证书的主题名称中必须具有不同的`O`、`OU`和`DC`。
参数对`certificateKeyFile/CAFile`和`clusterFile/clusterCAFile`不用于区分普通客户端和副本集/分片集群成员的连接。它们用于区分客户端和服务器证书,即传入和传出的连接。在我看来,这些名称完全误导人。
您可以使用一个公共的根CA,由`net.tls.CAFile`定义。
您还可以为客户端、成员和服务器使用相同的证书。这个公共证书甚至可以用于副本集/分片集群成员的x.509身份验证。该证书仅提供加密连接和x.509成员身份验证。当然,您不能将其用于普通客户端的x.509身份验证。
选项`tlsAllowInvalidCertificates`对x509身份验证没有影响。对于x509身份验证,证书必须有效。无效的证书仅用于加密连接。
测试用例:
openssl verify -CAfile server-ca.crt server.pem
openssl verify -CAfile cluster-ca.crt member.pem
openssl verify -CAfile cluster-ca.crt client.pem
# Verify server certificate:
openssl s_server -cert server.pem
# open another terminal
openssl s_client -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q
# Verify server and client certificate:
openssl s_server -cert server.pem -CAfile cluster-ca.crt -Verify 0
# open another terminal
openssl s_client -cert member.pem -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q
openssl s_client -cert client.pem -CAfile server-ca.crt -quiet -no_ign_eof -status <<< Q
可视化
如果您只使用一个CA证书
common-ca.crt
: