使用 TLS 将 pymongo 客户端连接到 mongodb 服务器

Posted

技术标签:

【中文标题】使用 TLS 将 pymongo 客户端连接到 mongodb 服务器【英文标题】:Connecting pymongo client to mongodb server with TLS 【发布时间】:2021-08-13 20:19:28 【问题描述】:

我在 Google Cloud 上有 2 个实例:

实例 A实例 B - 都具有静态外部 IP 地址。

实例 A 运行社区版 MongoDB 服务器 v4.4.6。

我已生成自签名证书以启用 TLS 我已在我的云网络中设置防火墙规则,以允许来自实例 B的 IP 地址的流量到 MongoDB 端口

因此,我成功地使用 Instance B 中的 mongo shell(v4.4.6) 连接到 Instance A 上运行的 mongo 服务器。这是我使用的命令 -

mongo --tls --tlsCertificateKeyFile client.pem --tlsCAFile ca.pem <instance_a_ip>:<port>/admin -u <userName> -p

我想使用 Instance B 中的 pymongo(v3.11.4) 客户端连接到 Instance A 中的 MongoDB 服务器,我已经尝试使用这在交互式 python shell 中 -

client = MongoClient("mongodb://<instance_a_ip>:<port>/admin", tls=True, tlsCertificateKeyFile='./client.pem', tlsCAFile='./ca.pem', username='<userName>', password='<userPassword>')

但是,我无法连接,这是我收到的错误 -

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/collection.py", line 1319, in find_one
    for result in cursor.limit(-1):
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/cursor.py", line 1207, in next
    if len(self.__data) or self._refresh():
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/cursor.py", line 1100, in _refresh
    self.__session = self.__collection.database.client._ensure_session()
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1816, in _ensure_session
    return self.__start_session(True, causal_consistency=False)
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1766, in __start_session
    server_session = self._get_server_session()
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/mongo_client.py", line 1802, in _get_server_session
    return self._topology.get_server_session()
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/topology.py", line 496, in get_server_session
    self._select_servers_loop(
  File "/home/varun/test-env/lib/python3.8/site-packages/pymongo/topology.py", line 215, in _select_servers_loop
    raise ServerSelectionTimeoutError(
pymongo.errors.ServerSelectionTimeoutError: <instance_a_ip>:<port>: ("Invalid DNS pattern b'127.0.0.1'.",), Timeout: 30s, Topology Description: <TopologyDescription id: 60ad03827b267af40c2edf4b, topology_type: Single, servers: [<ServerDescription ('<instance_a_ip>', <port>) server_type: Unknown, rtt: None, error=AutoReconnect('<instance_a_ip>:<port>: ("Invalid DNS pattern b\'127.0.0.1\'.",)')>]>

我是 MongoDB 新手,不知道该怎么做,非常感谢您的帮助。

【问题讨论】:

您的设置中的什么解析为 127.0.0.1? 我也不是 100% 确定,因为当我使用 mongo shell 时,我能够很好地连接到 mongo 服务器。我怀疑这与 pymongo 有关吗? 您可以修补驱动程序以重新引发处理 AutoReconnect 的异常,这将为您提供原始问题的堆栈跟踪。 通过为 mongodb 安装 Nodejs 客户端来解决问题。它为我提供了一个更好的例外,我可以追溯到我的代码。 【参考方案1】:

通过安装适用于 MongoDB 的 Nodejs 客户端来调试问题。 Node 客户端在失败时提供了更好的消息 -

[Error [ERR_TLS_CERT_ALTNAME_INVALID]: Hostname/IP does not match certificate's altnames: IP: 34.126.133.72 is not in the cert's list

感谢这个有意义的错误,我通读了我在创建自签名证书时使用的 OpenSSL 配置文件。纠正了我在配置文件中犯的错误 -

导致错误的原始配置文件

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
DNS.1 = 127.0.0.1
DNS.2 = <instance_a_ip>

经过调整的配置文件现在可以与所有 MongoDB 客户端一起使用

[ v3_req ]
subjectAltName = @alt_names

[ alt_names ]
IP.1 = 127.0.0.1
IP.2 = <instance_a_ip>

【讨论】:

【参考方案2】:

您的证书是自签名的,在创建 MongoClient 时添加此选项。

tlsInsecure=True

代码会是这样的

client = MongoClient(
    ["<instance_a_ip>:<port>"], 
    tls=True, 
    tlsInsecure=True, 
    tlsCertificateKeyFile='./client.pem', 
    tlsCAFile='./ca.pem', 
    username='<userName>', 
    password='<userPassword>'
)

【讨论】:

以上是关于使用 TLS 将 pymongo 客户端连接到 mongodb 服务器的主要内容,如果未能解决你的问题,请参考以下文章

将 pyspark 连接到 SQL Server 时出错

无法使用 pymongo 2.2 连接到 MongoDB 2.0.5 数据库

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

Pymongo 无法连接到数据库:pymongo.errors.ServerSelectionTimeoutError: connection closed

python如何通过pymongo连接到mongodb?

C中的OpenSSL-例程:ssl3_get_record:尝试使用TLS1_2连接到服务器时版本号错误