我正在尝试连接到另一台服务器上的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'
。这对我来说意义为零,因为它显然确实匹配,并且使用此x509 SSL证书连接到数据库时,Mongo Shell和Robo 3T都具有零资格。
使用来自Domain外部的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主机名之一的确切主机名。
任何人都可以为我提供有关此错误的任何帮助,我将不胜感激。预先感谢。
答案 0 :(得分:0)
这是驱动程序中的一些代码。 您的证书已解析,并尝试从 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 hostanme,而驱动程序将字符串“ 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