Postgres - Python несколько SSL-соединений

У меня проблемы с установлением двух одновременных подключений к базам данных Postgres (одно к главному, одно к подчиненному) с использованием psycopg2 и SSL. Отдельно работают оба соединения, т. Е.

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

работает и так же

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

Но присоединяясь к обоим

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 () первое соединение (как показано здесь, но без ssl изменить базу данных (postgresql) в python, используя psycopg2 динамически ), а также безуспешно пробовал различные варианты psycopg.extensions изоляция_level.

Заранее спасибо!

4 голоса | спросил Raphael 28 52014vEurope/Moscow11bEurope/MoscowFri, 28 Nov 2014 18:08:38 +0300 2014, 18:08:38

1 ответ


0

Я считаю, что я отследил проблему до libq ... библиотеки PostgreSQL C.

Я тоже заметил, что не могу использовать разные сертификаты клиента ssl для двух разных соединений. Первое соединение всегда успешно, в то время как второе соединение всегда терпит неудачу с SSL error: certificate verify failed

В журнале сервера я получаю could not accept SSL connection: tlsv1 alert unknown ca

Это говорит мне, что 2-е соединение, возможно, пытается использовать 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

Я подумал, что есть проблема с psycopg2 ... возможно, он кэшировал ssl-сертификат клиента ....

Я продолжил работу и создал отладочную версию psycopg2 и установил ее .. Я снова попробовал свой код и получил тонны отладочной информации. Вот отладочная информация, которую я получил. (Я только публикую соответствующую информацию)

[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 для 2-го соединения является правильным, потому что соединение успешно, если выполняется первым.

Проверяя источник psycopg2, он просто вызывает PQconnectdb из библиотеки libq C ... и вызывает его с правильным параметры. Вы можете проверить документы на PQconnectdb на http://www.postgresql.org/docs/9.4 /static/libpq-connect.html#LIBPQ-PQCONNECTDB

Это говорит о том, что psycopg2 правильно вызывает PQconnectdb с правильными параметрами и PQconnectdb просто не использует правильный сертификат при втором подключении.

Более того, я также провел тестирование с другими программами. Я тестировал Navicat для PostgreSQL (Mac-версия) - та же проблема. Первое соединение успешно, второе соединение не может проверить сертификат. Когда я перезапускаю Navicat, это происходит снова ... первое соединение успешно, а второе соединение не удается, независимо от того, в каком порядке я пытаюсь.

То же самое происходит с PgAdmin (последняя версия в настоящее время 1.20). Первое соединение успешно, а второе - сбой.

Я подозреваю, что любое программное обеспечение или модуль, который подключается к PostgreSQL, будет страдать от тех же проблем, пока он использует libq для подключения. На самом деле я даже тестировал PHP и получил тот же результат

[email protected]:~# 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
[email protected]:~# 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
[email protected]:~# 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/

Пока это не сработало, я смог придумать решение, которое работает для меня ... На данный момент решение состоит в том, чтобы просто использовать одинаковые сертификаты для обоих серверов. Если вы можете сделать это, это работает для обоих подключений, и вы можете иметь 2 отдельных подключения к 2 отдельным серверам ... (при условии, что оба подключения могут подключаться с использованием одного и того же сертификата клиента)

Для меня я просто использовал один и тот же ssl-сертификат сервера, закрытый ключ и корневой сертификат для обоих серверов ... Я просто использовал подстановочный знак для общего имени и сам подписал сертификат (но вы можете использовать коммерческий подстановочный сертификат если хотите) Затем я сгенерировал сертификат клиента и использовал этот единственный сертификат для обоих соединений.

Возможно, это не тот ответ, который вы искали, но, похоже, это единственный способ получить 2 подключения к 2 различным серверам по протоколу SSL с использованием проверки подлинности с помощью сертификата клиента. И это верно независимо от того, какой язык программирования или программное обеспечение вы используете.

Итак, ваш код теперь выглядит примерно так:

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, которыйработы

[email protected]:~# 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
ответил Ray Perea 4 J000000Saturday15 2015, 13:48:14

Похожие вопросы

Популярные теги

security × 330linux × 316macos × 2827 × 268performance × 244command-line × 241sql-server × 235joomla-3.x × 222java × 189c++ × 186windows × 180cisco × 168bash × 158c# × 142gmail × 139arduino-uno × 139javascript × 134ssh × 133seo × 132mysql × 132