0

我对使用 SSL 连接到另一个 postgres 数据库的 sqlalchemy 和 pg8000 的文档和示例感到困惑。不需要私钥或任何东西。我正在尝试以require模式连接 SSL。这是通过 SQL 客户端 (Datagrip) 连接到数据库的 SSL 设置的屏幕截图:

数据夹

如您所见,用于输入密钥文件位置或密码的文本框都是空白的;我刚刚选择了模式为Require.

现在在我的代码中,以下内容曾经工作但突然停止工作。

DATABASE_DB_URL=postgresql+pg8000://user:password@12.345.6.789:5432/database?ssl=True

db = records_client.Database(DATABASE_DB_URL)

# Returns error: 
TypeError: connect() got an unexpected keyword argument 'ssl'

这是完整的堆栈跟踪

Traceback (most recent call last):
  File "C:/Users/user/Documents/django-app/test2.py", line 44, in <module>
    db = records_client.Database(DATABASE_DB_URL) #, connect_args={'ssl_context':True})
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\records.py", line 245, in __init__
    self.db = self._engine.connect()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\base.py", line 3166, in connect
    return self._connection_cls(self, close_with_result=close_with_result)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\base.py", line 96, in __init__
    else engine.raw_connection()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\base.py", line 3245, in raw_connection
    return self._wrap_pool_connect(self.pool.connect, _connection)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\base.py", line 3212, in _wrap_pool_connect
    return fn()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 301, in connect
    return _ConnectionFairy._checkout(self)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 761, in _checkout
    fairy = _ConnectionRecord.checkout(pool)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 419, in checkout
    rec = pool._do_get()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\impl.py", line 145, in _do_get
    self._dec_overflow()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\util\langhelpers.py", line 72, in __exit__
    with_traceback=exc_tb,
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\util\compat.py", line 211, in raise_
    raise exception
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\impl.py", line 142, in _do_get
    return self._create_connection()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 247, in _create_connection
    return _ConnectionRecord(self)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 362, in __init__
    self.__connect()
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 605, in __connect
    pool.logger.debug("Error on connect(): %s", e)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\util\langhelpers.py", line 72, in __exit__
    with_traceback=exc_tb,
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\util\compat.py", line 211, in raise_
    raise exception
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\pool\base.py", line 599, in __connect
    connection = pool._invoke_creator(self)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\create.py", line 578, in connect
    return dialect.connect(*cargs, **cparams)
  File "C:\Users\user\Documents\django-app\venv-dev\lib\site-packages\sqlalchemy\engine\default.py", line 584, in connect
    return self.dbapi.connect(*cargs, **cparams)
TypeError: connect() got an unexpected keyword argument 'ssl'

Process finished with exit code 1

所以我想在 Python 调用中添加 SSL 参数,而不是像这样的环境变量:

DATABASE_DB_URL=postgresql+pg8000://user:password@12.345.6.789:5432/database?

db = records_client.Database(DATABASE_DB_URL, connect_args={'ssl_context':True})

# Returns error: ssl.SSLCertVerificationError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed: IP address mismatch, certificate is not valid for '98.765.4.321'. (_ssl.c:1091)

我很确定错误中的 IP 地址被列入白名单以连接到数据库。

我一直在尝试寻找正确语法和用法的示例,但我感到困惑。传递给连接调用的正确参数是什么?

4

1 回答 1

2

下面的示例代码适用于我,使用自签名证书。

请注意,这ssl.CERT_REQUIRED是 的默认值ssl.create_default_context,但如果上下文是通过SSLContext()直接调用创建的,则需要设置它。

根据文档,传递ssl_context=True将使用 的结果create_default_context(),因此除了加载非标准证书路径之外,此代码与您已经在执行的操作之间似乎没有任何区别。这SSLCertVerificationError意味着您的代码是正确的,但客户端计算机和证书的组合不正确。您可能需要检查pg_hba.conf服务器上的文件。

import ssl

import sqlalchemy as sa


ssl_context = ssl.create_default_context()
ssl_context.verify_mode = ssl.CERT_REQUIRED
# Probably necessary because I was using a self-signed cert.
ssl_context.load_verify_locations(CERTIFICATE_PATH)



engine = sa.create_engine('postgresql+pg8000://ssluser:ssluser@hostname/test',
                          connect_args={'ssl_context': ssl_context})
                          


q = """\
SELECT ssl, version, cipher
FROM pg_stat_ssl
WHERE pid IN (SELECT pid
              FROM pg_stat_activity
              WHERE usename = 'ssluser')
"""

with engine.connect() as conn:
    with conn.begin():
        res = conn.execute(sa.text(q))
        for row in res:
            print(row)
        print()

输出:

(True, 'TLSv1.2', 'ECDHE-RSA-AES256-GCM-SHA384')

为了完整起见,psycopg2 安全连接如下所示:

engine = sa.create_engine('postgresql+psycopg2://ssluser:ssluser@host/test?sslmode=require')
于 2021-05-21T18:56:59.270 回答