Postgres python多个SSL连接

2024-10-03 13:18:45 发布

您现在位置:Python中文网/ 问答频道 /正文

我在使用psycopg2和SSL建立两个并发Postgres数据库连接(一个到master,一个到slave)时遇到问题。两种连接分别工作,即:

import psycopg2
dsnMaster='dbname=... sslcert=path/to/master/cert'
psycopg2.connect(dsnMaster, connection_factory=None, async=False)

工作也一样

^{pr2}$

但同时也是

import psycopg2
dsnMaster='dbname=... sslcert=path/to/master/cert'
psycopg2.connect(dsnMaster, connection_factory=None, async=False)
dsnSlave='dbname=... sslcert=path/to/slave/cert'
psycopg2.connect(dsnSlave, connection_factory=None, async=False)

第二次连接总是失败,出现SSL error: block type is not 01 . psycopg似乎使用上一个连接中的证书。在

我尝试过.close()第一个连接(如这里所示,但是没有sslchange database (postgresql) in python using psycopg2 dynamically),还尝试了心理延伸隔离级别选项,没有成功。在

提前谢谢!在


Tags: topathmasternonefalsesslasynccert
1条回答
网友
1楼 · 发布于 2024-10-03 13:18:45

我相信我已经把问题归结到了libq。。。PostgreSQL C库。在

我也注意到我不能为两个不同的连接使用不同的ssl客户端证书。第一个连接总是成功的,而第二个连接总是失败的SSL error: certificate verify failed

在服务器日志上我得到could not accept SSL connection: tlsv1 alert unknown ca

这告诉我第二个连接可能试图使用第一个连接的ssl证书,而不是使用它被告知要使用的ssl证书。在

考虑一下这个代码

import psycopg2
conn1 = psycopg2.connect('host=server1... sslcert=path/to/cert1')
conn2 = psycopg2.connect('host=server2... sslcert=path/to/cert2')

连接2似乎正在使用cert1而不是cert2

我觉得心理医生有问题。。。可能是在缓存客户机ssl证书。。。。在

我继续构建了一个psycopg2的调试版本并安装了它。。我再次尝试我的代码,得到了大量的调试信息。这是我得到的调试信息。(我只发布相关信息)

^{pr2}$

如果我切换两个连接,结果是一样的。。。第一次连接成功,但第二次连接失败。因此,第二个连接的dsn是正确的,因为如果先执行连接,则连接成功。在

检查psycopg2的源代码,它只是从libqc库调用PQconnectdb。。。它用正确的参数调用它。 您可以在PQconnectdb上查看文档 http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-PQCONNECTDB

这说明psycopg2使用正确的参数正确调用PQconnectdb,而{}只是没有在第二个连接上使用正确的证书。在

更重要的是,我也用其他程序做了一些测试。我测试了Navicat for PostgreSQL(Mac版本)-同样的问题。第一次连接成功,第二次连接验证证书失败。当我重新启动Navicat时,它又发生了。。。不管我尝试什么顺序,第一个连接成功,第二个连接失败。在

PgAdmin也会发生同样的情况(最新版本是1.20)。第一次连接成功,第二次连接失败。在

我怀疑,只要使用libq连接,任何连接到PostgreSQL的软件或模块都会遇到同样的问题。事实上,我甚至测试了PHP,得到了相同的结果

root@test:~# php -a
Interactive mode enabled

php > // Test with server 1 first
php > $conn = pg_connect('host=server1 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt');
php > $conn2 = pg_connect('host=server2 user=testdb dbname=testdb sslcert=cert2.crt sslmode=verify-full sslkey=cert2.key sslrootcert=root2.crt');
PHP Warning:  pg_connect(): Unable to connect to PostgreSQL server: SSL error: certificate verify failed in php shell code on line 1
php > quit
root@test:~# php -a
Interactive mode enabled

php > // Test with server 2 first
php > $conn2 = pg_connect('host=server2 user=testdb dbname=testdb sslcert=cert2.crt sslmode=verify-full sslkey=cert2.key sslrootcert=root2.crt');
php > $conn = pg_connect('host=server1 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt');
PHP Warning:  pg_connect(): Unable to connect to PostgreSQL server: SSL error: certificate verify failed in php shell code on line 1
php > quit
root@test:~# php -a
Interactive mode enabled

php > // Test using the same certificate
php > $conn = pg_connect('host=server1 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt');
php > $conn2 = pg_connect('host=server2 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt');
php > // No problems. Both connect just fine now

我的建议是用PostgreSQL提交一个bug报告。不确定这是否是提交此类错误报告的正确位置 http://www.postgresql.org/support/submitbug/

在这项工作成功之前,我能想出一个对我有用的解决方案。。。目前的解决方案是简单地为两台服务器使用相同的证书。如果你能做到这一点,它适用于两个连接,你可以有两个独立的连接到两个独立的服务器。。。(只要两个连接都可以使用同一个客户端证书连接)

对我来说,我只是对两台服务器使用相同的服务器ssl证书、私钥和根证书。。。我只是使用了一个通配符作为通用名,并亲自签署了证书(但是如果您愿意,您可以使用商业通配符证书),然后,我生成了一个客户端证书,并将该证书用于两个连接。在

这可能不是您要寻找的答案,但这似乎是唯一的方法,您可以使用客户端证书身份验证通过SSL与2个不同的服务器建立2个连接。不管你用什么编程语言或软件,这都是真的。在

所以,你的代码现在变成了:

import psycopg2
dsnMaster='dbname=... sslcert=path/to/master/cert'
psycopg2.connect(dsnMaster, connection_factory=None, async=False)

# Here, the dsnSlave simply uses the same cert as the master
# Other connection details like the host and dbname can be different
dsnSlave='dbname=... sslcert=path/to/master/cert'
psycopg2.connect(dsnSlave, connection_factory=None, async=False)

这是我用python编写的实际代码

root@test:~# python3
Python 3.4.0 (default, Jun 19 2015, 14:20:21) 
[GCC 4.8.2] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import psycopg2
>>> dsn1 = 'host=server1 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt'
>>> conn1 = psycopg2.connect(dsn1)
>>> dsn2 = 'host=server2 user=testdb dbname=testdb sslcert=cert1.crt sslmode=verify-full sslkey=cert1.key sslrootcert=root1.crt'
>>> conn2 = psycopg2.connect(dsn2)
>>> # YAY, no issues and both connections work

相关问题 更多 >