使用 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 列表中的显式 <server name>
和 *.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:<server1>, DNS:<server2>, 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)具体步骤