Postgres - python multiple SSL connections
我在使用psycopg2和SSL建立两个并发的Postgres数据库连接(一个到主数据库,一个到从数据库)时遇到了麻烦。分别,两个连接工作,即:
1 2 3 | import psycopg2 dsnMaster='dbname=... sslcert=path/to/master/cert' psycopg2.connect(dsnMaster, connection_factory=None, async=False) |
有效,
也有效
1 2 3 | import psycopg2 dsnSlave='dbname=... sslcert=path/to/slave/cert' psycopg2.connect(dsnSlave, connection_factory=None, async=False |
但同时加入两个
1 2 3 4 5 | 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) |
对于第二个连接总是失败,
。似乎psycopg使用先前连接中的证书。
我尝试.close()第一个连接(如此处所示,但没有使用psycopg2动态地在python中更改ssl更改数据库(postgresql)),并且还尝试了各种psycopg.extensions隔离级别选项,但未成功。
预先感谢!
我相信我已经将问题归结为libq ... PostgreSQL C库。
我也注意到我不能为2个不同的连接使用不同的ssl客户端证书。第一个连接总是成功,而第二个连接总是失败,
在服务器日志上,我得到
这告诉我第二个连接可能正在尝试从第一个连接使用ssl证书,而不是使用被告知要使用的ssl证书。
考虑此代码
1 2 3 | import psycopg2 conn1 = psycopg2.connect('host=server1... sslcert=path/to/cert1') conn2 = psycopg2.connect('host=server2... sslcert=path/to/cert2') |
连接2似乎正在使用cert1而不是cert2
我发现psycopg2存在问题...也许正在缓存客户端ssl证书...。
我继续构建了psycopg2的调试版本并安装了它。这是我得到的调试信息。 (我只发布相关信息)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | [98940] psyco_connect: dsn = 'dbname=testdb user=testdb host=server1 sslrootcert=root1.crt sslkey=cert1.key sslcert=cert1.crt sslmode=verify-full', async = 0 [98940] connection_setup: init connection object at 0x103093048, async 0, refcnt = 1 [98940] con_connect: connecting in SYNC mode [98940] conn_connect: new postgresql connection at 0x10047ff90 [98940] conn_connect: server standard_conforming_strings parameter: on [98940] conn_connect: server requires E'' quotes: NO [98940] conn_connect: using protocol 3 [98940] conn_connect: client encoding: UTF8 [98940] clear_encoding_name: UTF8 -> UTF8 [98940] conn_connect: DateStyle ISO, MDY [98940] connection_setup: good connection object at 0x103093048, refcnt = 1 # ... Got a good 1st connection here # ... (Tons more lines of output before the 2nd connection) [98940] psyco_connect: dsn = 'dbname=testdb user=testdb host=server2 sslrootcert=root2.crt sslkey=cert2.key sslcert=cert2.crt sslmode=verify-full', async = 0 [98940] connection_setup: init connection object at 0x103093170, async 0, refcnt = 1 [98940] con_connect: connecting in SYNC mode [98940] conn_connect: new postgresql connection at 0x100682d30 [98940] conn_connect: PQconnectdb(dbname=testdb user=testdb host=server2 sslrootcert=root2.crt sslkey=cert2.key sslcert=cert2.crt sslmode=verify-full) returned BAD [98940] connection_init: FAILED [98940] conn_close: PQfinish called [98940] connection_dealloc: deleted connection object at 0x103093170, refcnt = 0 |
如果我切换2个连接,则结果相同...第一个连接成功,但第二个连接失败。因此,第二个连接的dsn是正确的,因为如果先执行该连接就会成功。
检出psycopg2的源代码,它只是从libq C库中调用
您可以在
http://www.postgresql.org/docs/9.4/static/libpq-connect.html#LIBPQ-PQCONNECTDB
这告诉我psycopg2使用正确的参数正确调用了
此外,我还对其他程序进行了一些测试。我针对PostgreSQL(Mac版)测试了Navicat-相同的问题。第一个连接成功,第二个连接未能验证证书。重新启动Navicat时,它再次发生...无论我按什么顺序尝试,第一个连接成功,第二个连接失败。
PgAdmin也发生了同样的事情(当前最新版本为1.20)。第一个连接成功,第二个连接失败。
我怀疑,只要使用libq进行连接,连接到PostgreSQL的任何软件或模块都会遭受相同的问题。实际上,我什至测试了PHP,并得到了相同的结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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一起提交错误报告。不知道这是否是提交此类错误报告的正确位置
http://www.postgresql.org/support/submitbug/
在此之前,我能够提出一个对我有效的解决方案...目前的解决方案是对两个服务器使用相同的证书。如果可以执行此操作,则它适用于两个连接,并且您可以将两个单独的连接连接到两个单独的服务器...(只要两个连接都可以使用相同的客户端证书进行连接)
对我来说,我只是对两个服务器使用了相同的服务器ssl证书,私钥和根证书...我只是使用通配符作为通用名称,然后自己对证书进行了签名(但是您可以使用商业通配符证书然后,我生成了一个客户端证书,并将这单个证书用于两个连接。
这可能不是您要找的答案,但这似乎是您使用客户端证书身份验证通过SSL与2个不同服务器建立2个连接的唯一方法。无论您使用哪种编程语言或软件,都是如此。
因此,您的代码现在变为:
1 2 3 4 5 6 7 8 | 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中有效的实际代码
1 2 3 4 5 6 7 8 9 10 | 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 |