SSH-туннель QGIS и PostGIS: сохраните имя сервера для TLS
SSH-проброс даёт QGIS локальный порт, но базе данных для TLS по-прежнему нужно её настоящее имя. Используйте службу libpq с hostaddr и слушателем loopback.
Туннель поднимается, QGIS подключается, и вход обрывается ошибкой сертификата, в которой указан 127.0.0.1 вместо хоста базы данных. Следующий соблазнительный шаг — ослабить sslmode, что заглушает проверку и выбрасывает ту гарантию идентичности, ради которой всё и делалось. Настоящая проблема в том, что локальный порт и имя сервера хранятся в одном поле. Запись службы libpq разделяет их, поэтому сокет уходит на проброшенный порт, а TLS по-прежнему проверяет имя, напечатанное в сертификате.
К чему клиент думает, что подключается
При sslmode=verify-full libpq сравнивает сертификат, который представляет сервер, с запрошенным именем хоста. Если это имя — адрес loopback, сравнение не проходит, хотя сертификат действителен для настоящего хоста базы данных. SSH-проброс меняет то, какой сокет переносит байты, а не идентичность, которую клиент должен ожидать. Как только эти две идеи разделены, ошибка перестаёт выглядеть как сбой TLS.
Проброс — это и не авторизация. PostgreSQL по-прежнему применяет свои правила к соединению, которое устанавливает SSH-сервер, поэтому держите транспортный уровень и уровень базы данных раздельно, прежде чем что-то менять.
Привяжите проброс только к loopback
Слушатель должен существовать на машине QGIS и нигде больше. Явное указание 127.0.0.1 удерживает его в стороне от других интерфейсов, а пропущенный адрес привязки может открыть порт наружу в зависимости от настроек шлюза SSH-клиента.
ssh -N -L 127.0.0.1:15432:127.0.0.1:5432 [email protected]Назначение после второго двоеточия разрешается на стороне SSH-сервера, поэтому в этом примере предполагается, что PostgreSQL находится на том же хосте, что и sshd; базе данных на другой машине нужны этот адрес и её разрешения. Запустите сеанс с -N, чтобы не открывалась никакая оболочка, не трогайте проверку ключа хоста и убедитесь, что слушатель появился, прежде чем винить QGIS. Если порт уже занят, проброс завершается ошибкой при запуске, а не во время запроса.
Поместите имя и сокет в одну запись службы
Файл службы позволяет одному и тому же соединению нести имя для проверки и другое назначение сокета. Сохраните запись там, где libpq ищет службы, или направьте PGSERVICEFILE на неё.
[gis-via-ssh]
host=db.geo.example
hostaddr=127.0.0.1
port=15432
dbname=gisdb
user=gis_reader
sslmode=verify-full
gssencmode=disable
sslrootcert=/path/to/approved-root.crtЗдесь host сохраняет идентичность, используемую для проверок сертификата, а hostaddr отправляет пакеты на проброшенный порт loopback, и для работы такой схемы нужны оба. gssencmode=disable важно в сборках, которые иначе сначала согласовывали бы шифрование GSSAPI, потому что этот путь игнорирует только что заданные настройки TLS. Ссылайтесь на службу по имени из диалога подключения PostgreSQL в QGIS и передавайте пароль через обычный запрос, а не внутри общего файла. Имена и пути выше — заполнители; замените их своими утверждёнными значениями.
Что PostgreSQL ещё проверяет после туннеля
Сервер видит соединение с хоста SSH, в этой схеме — с loopback, и по порядку сопоставляет его с правилами аутентификации по хосту. Вашей роли в базе данных всё ещё нужно аутентифицироваться, а вход по SSH сам по себе не даёт идентичности в базе данных. Проверяйте, что считает сервер, а не что предположил клиент.
psql "service=gis-via-ssh" -c "select inet_server_addr(), current_user"Закройте сеанс проброса, когда работа закончена; локальная запись тогда перестаёт работать, и больше ничего не меняется. Один путь к базе данных — не VPN для всего клиента GIS, и именно отношение к нему как к VPN приводит к неверной диагностике следующего соединения.