使用 PyMongo 和 x509 SSL 证书连接到 MongoDB 数据库时出现 ServerSelectionTimeoutError

Posted

技术标签:

【中文标题】使用 PyMongo 和 x509 SSL 证书连接到 MongoDB 数据库时出现 ServerSelectionTimeoutError【英文标题】:ServerSelectionTimeoutError When connecting to MongoDB Database with PyMongo and x509 SSL Certificate 【发布时间】:2019-01-20 16:25:13 【问题描述】:

我正在尝试连接到另一台服务器上的 MongoDB 数据库。唯一的问题是连接到服务器需要专门的 Kerberos 版本。为了克服这个问题,我使用 SSH 隧道为 Pymongo 打开一个本地端口以与数据库交互,我们专门为这种可能性设计了安全证书作为预防措施。我知道隧道运行正常,因为 Mongo Shell 和 Robo 3T 都能够连接到数据库并显示数据。但是,对于 PyMongo 3.7.1 版,我收到以下错误:

ServerSelectionTimeoutError: hostname '127.0.0.1' doesn't match either of '<redacted server1>', '<redacted server1 wildcard domain>', '127.0.0.1'

在我们不得不将 MongoDB 移动到域中的另一个服务器位置的情况下,证书是使用 x509 证书的 DNS 列表中的显式 &lt;server name&gt;*.server_domain.com 设置的。我们还为域外需要使用 SSH 隧道访问数据库的少数用户添加了127.0.0.1

使用 PyMongo,我们得到以下错误:

from pymongo import MongoClient
client = MongoClient('127.0.0.1', 27017, ssl_ca_certs='/Users/<user>/ssl_cert_location/mongodb.pem')
db = client['admin']
db.authenticate('<username>', '<password>')

---------------------------------------------------------------------------
ServerSelectionTimeoutError               Traceback (most recent call last)
<ipython-input-26-ca905a055830> in <module>()
----> 1 db.authenticate('<username>', '<password>')

/Users/<user>/anaconda2/lib/python2.7/site-packages/pymongo/database.pyc in authenticate(self, name, password, source, mechanism, **kwargs)
   1272             self.name,
   1273             credentials,
-> 1274             connect=True)
   1275
   1276         return True

/Users/<user>/anaconda2/lib/python2.7/site-packages/pymongo/mongo_client.pyc in _cache_credentials(self, source, credentials, connect)
    607         if connect:
    608             server = self._get_topology().select_server(
--> 609                 writable_preferred_server_selector)
    610
    611             # get_socket() logs out of the database if logged in with old

/Users/<user>/anaconda2/lib/python2.7/site-packages/pymongo/topology.pyc in select_server(self, selector, server_selection_timeout, address)
    222         return random.choice(self.select_servers(selector,
    223                                                  server_selection_timeout,
--> 224                                                  address))
    225
    226     def select_server_by_address(self, address,

/Users/<user>/anaconda2/lib/python2.7/site-packages/pymongo/topology.pyc in select_servers(self, selector, server_selection_timeout, address)
    181         with self._lock:
    182             server_descriptions = self._select_servers_loop(
--> 183                 selector, server_timeout, address)
    184
    185             return [self.get_server_by_address(sd.address)

/Users/<user>/anaconda2/lib/python2.7/site-packages/pymongo/topology.pyc in _select_servers_loop(self, selector, timeout, address)
    197             if timeout == 0 or now > end_time:
    198                 raise ServerSelectionTimeoutError(
--> 199                     self._error_message(selector))
    200
    201             self._ensure_opened()

ServerSelectionTimeoutError: hostname '127.0.0.1' doesn't match either of '<redacted server1>', '<redacted server1 wildcard domain>', '127.0.0.1'

这个错误最重要的部分是hostname '127.0.0.1' doesn't match '127.0.0.1'。这对我来说是零意义,因为它显然是匹配的,而且 Mongo Shell 和 Robo 3T 都使用这个 x509 SSL 证书连接到数据库零疑虑。

使用域外的 Mongo shell,似乎没有问题:

$  pkinit -f <user>
     <user> PIN:  *****************

$  /usr/local/ossh/bin/ssh -4K -nNT -L 27017:127.0.0.1:<mongo_port> <user>@<server1>

$ ./mongo --host 127.0.0.1 --port 27017 --ssl --sslCAFile ~/ssl_cert_location/mongodb6.pem

    MongoDB shell version v4.0.1
    connecting to: mongodb://127.0.0.1:27017/
    MongoDB server version: 3.6.5
    WARNING: shell and server versions do not match
  MongoDB Enterprise > use admin
    switched to db admin

因此,隧道正常运行,MongoDB 的 SSL x509 证书没有任何问题。所以这就引出了为什么 Pymongo 不能处理给定的 x509 证书的问题?我没有在主机名列表中使用任何前导或尾随点,这似乎是所有线程在搜索此错误时所关注的内容。我明确给出了作为 x509 证书中备用 DNS 主机名之一列出的确切主机名。

如果有人能就这个错误给我任何帮助,我将不胜感激。提前致谢。

【问题讨论】:

我现在也有同样的问题。前一天它运行良好,但现在突然它不是来自 pymongo,而是任何其他方式。你设法解决了这个问题吗? 【参考方案1】:

这是驱动程序的一些代码。 您的证书已被解析,它会尝试从 subjectAltName 部分加载 DNS 名称 https://github.com/mongodb/mongo-python-driver/blob/749c1a2f0bde87a6e6d8df9366e4c90666efd189/pymongo/ssl_match_hostname.py#L103-L113

请注意,驱动程序区分 subjectAltName 中的“DNS”和“IP 地址”键控条目。 我想您已经在证书中添加了“127.0.0.1”作为 DNS 主机名,而驱动程序将字符串“127.0.0.1”视为 IP 地址 因此没有匹配项。

这就是代码失败并出现令人困惑的错误的原因。匹配失败不在于直接价值 - 它在于以下事实 一个是 IP 地址,另一个是主机名。

混淆发生得稍早一些,变量host_ip被分配给指定的主机名是否可以被解析为 IP 地址与否。 https://github.com/mongodb/mongo-python-driver/blob/749c1a2f0bde87a6e6d8df9366e4c90666efd189/pymongo/ssl_match_hostname.py#L98-L102 在主机名“127.0.0.1”的情况下,我想它被正确解析并分配给host_ip variable

现在这个检查将失败 https://github.com/mongodb/mongo-python-driver/blob/749c1a2f0bde87a6e6d8df9366e4c90666efd189/pymongo/ssl_match_hostname.py#L107 并且它与证书的 DNS 主机名部分中的“127.0.0.1”不匹配。

修复

您的证书的 subjectAltName 字段可能看起来像这样:subjectAltName = DNS:&lt;server1&gt;, DNS:&lt;server2&gt;, IP:127.0.0.1

【讨论】:

好评论,但请查看此链接:jira.mongodb.org/browse/SERVER-37793?filter=-2。一切从这里开始。所以 SAN 解析是一个已知的错误,正在修复中。 链接需要登录才能查看 抱歉,关键是,使用 IP 地址通过 SSL 和 SAN 尝试通过 mongo shell 访问 mongoDB 是不可能的:[alt_names] IP.1 = 99.999.99.001。它必须用作 DNS.1 = 99.999.99.001。 MongoDB 支持:目前支持在 SAN 中使用 CN 或 DNS 名称验证主机名。此票证用于实现对 SAN 中 IP 地址类型的支持。这仍然是一个悬而未决的问题,通过 IP 建立连接的唯一方法是使用上述 DNS。 它运行了好几天,但突然收到错误消息:“pymongo.errors.ServerSelectionTimeoutError: hostname '10.132.35.142' doesn't match any of '10.132.35.142', '132.52.152.23' '",这是 mongoDB 目前正在调查的问题

以上是关于使用 PyMongo 和 x509 SSL 证书连接到 MongoDB 数据库时出现 ServerSelectionTimeoutError的主要内容,如果未能解决你的问题,请参考以下文章

iOS适配HTTPS,创建一个自签名的SSL证书(x509)具体步骤

[转]如何创建一个自签名的SSL证书(X509)

openssl、x509、crt、cer、key、csr、ssl、tls都是啥意思?

mbedtls的ssl x509协议API

kubectl - 由未知权威签署的错误 x509 证书

https://registry.gitlab.com/v2/: x509: 未知权威签署的证书