В какой-то момент при локальной разработке (да, в общем-то и при тестировании на иных стендах) задумываешься о том, как бы избавиться от довольно монотонных действий. Одним из них является ввод пароля в рамках процесса аутентификации в PostgreSQL. В этой статье я расскажу как слегка автоматизировать данный процесс.
Данная статья является легким переосмыслением того, что я написал на медиуме. Ибо думать я продолжаю на русском
TL;DR исходники к вашим услугам.
В рамках любых взаимодействий мы сталкиваемся с такими сущностями как авторизация и аутентификация. Повторять в 100500 раз что есть что я не буду (но мне не лень такую длинную ремарку напечатать, ага). В рамках PostgreSQL первое обеспечивается через Roles, а второе через Privileges.
Если покопаться в документации PostgreSQL, то можно обнаружить, что эта БД поддерживает довольно много типов авторизации. Однако, нас интересует что-то, что могло бы заменить связку логина и пароля. И в этот момент авторизация на основе сертификатов приходит нагугл ум. В общем-то, при корректной настройке, мы не только избавляемся от необходимости ввода пароля для нашего пользователя, но и повышаем уровень защищенности (подделка сертификата немножко сложнее угадывания любимого пароля, который у меня - "qwerty").
Давайте подумаем над тем, чего мы хотим достичь. Но думать просто так скучно, поэтому запишем наши требования в формате пользовательских историй!
Начинаем готовить наш коктейль. Нам понадобятся:
С учетом ингридиентов для нашего коктейля, давайте подумаем над сетевым взаимодействием элементов. Для начала, конечно же, определим их:
1-2 - TLS канал, и сервер, и клиент проверяют сертификаты противоположной стороны. Это соединение mTLS
3-4 - Стандартная request / response последовательность, выполняемая в рамках канала, установленного в шаге 1-2.
5-6 - TLS канал, проверка сертификата осуществляется только на стороне клиента (браузера). Данное соединение является просто TLS, т.к. валидация сертификата выполняется только одной из сторон.
7-8 - Аналогично шагу 3-4, но исполняется в рамках канала, установленного в шаге 5-6.
Теперь мы видим, какие типы сертификатов нам понадобятся:
Поехали генерировать сертификаты. Мы же программисты, поэтому, пишем скрипт и необходимый конфиг.
Для начала, определяем какие-то общие переменные:
Теперь можно сгенерировать корневой сертификат для целей mTLS:
Генерируем сертификат для PostgreSQL сервиса и подписываем его ранее полученным:
И генерируем по сертификату для каждого из пользователей:
Генерация сертификатов для HTTPS соединения точно такая же, за исключением того, что пользовательские сертификаты генерировать не нужно.
Немного посмотрим на конфигурацию. Конфигурационные файлы в данном случае имеют ini-подобную структуру, т.е. имеются разделы, а в них ключи и значения. При этом, значения могут ссылаться на какой-то из разделов. Например:
В данном случае, значение ключа basicConstraints ссылается на раздел mtls_root_basic_constraints в котором указано, что мы генерируем Certificate Authority (не смог вменяемый перевод вспомнить), который не может выдавать промежуточные сертификаты.
Применяемую секцию из конфигурационного файла мы передаем как значение параметра -extensions: -extensions v3_mtls_root.
Итак, все сертификаты сгенерированы. Пора конфигурировать PostgreSQL. Начнем с файла pg_hba.conf. Этот файл является частью системы аутентификации.
Наши требования довольно очевидны:
Далее нам необходимо сконфигурировать параметры запуска сервиса, переменные окружения, пробросить порт и тома. Собственно, эта часть docker-compose.yml может выглядеть так:
Аналогичную конфигурацию, а именно: переменных окружения, проброса порта и томов мы проводим для нашего pgAdmin:
Собственно, из основного - пробрасываем пользовательские сертификаты и корневой сертификат mTLS. Так же пробрасываем серверный HTTPS сертификат. Ну и раз мы все локации сертификатов знаем, можем сразу же пробросить файл с настройками серверов (servers.json):
Итого, что мы имеем на выходе:
habr.com
Данная статья является легким переосмыслением того, что я написал на медиуме. Ибо думать я продолжаю на русском
TL;DR исходники к вашим услугам.
В рамках любых взаимодействий мы сталкиваемся с такими сущностями как авторизация и аутентификация. Повторять в 100500 раз что есть что я не буду (но мне не лень такую длинную ремарку напечатать, ага). В рамках PostgreSQL первое обеспечивается через Roles, а второе через Privileges.
Если покопаться в документации PostgreSQL, то можно обнаружить, что эта БД поддерживает довольно много типов авторизации. Однако, нас интересует что-то, что могло бы заменить связку логина и пароля. И в этот момент авторизация на основе сертификатов приходит на
Давайте подумаем над тем, чего мы хотим достичь. Но думать просто так скучно, поэтому запишем наши требования в формате пользовательских историй!
- Как пользователь, я хочу иметь доступный инстанс PostgreSQL.
- Как пользователь, я хочу иметь возможность залогиниться туда и выполнять доступные мне команды.
- Как пользователь, я ленив и не хочу вводить пароль (так и быть, согласен поставить флаг "Запомнить пароль" в соответствующем диалоге pgAdmin).
- Как пользователь, я хочу чтобы все взаимодействие было обмазано сертификатами.
Начинаем готовить наш коктейль. Нам понадобятся:
- Docker-compose.
- OpenSSL.
- Любимый текстовый редактор, или IDE.
С учетом ингридиентов для нашего коктейля, давайте подумаем над сетевым взаимодействием элементов. Для начала, конечно же, определим их:
- Сервис PostgreSQL
- Сервис pgAdmin
- Любимый браузер

1-2 - TLS канал, и сервер, и клиент проверяют сертификаты противоположной стороны. Это соединение mTLS
3-4 - Стандартная request / response последовательность, выполняемая в рамках канала, установленного в шаге 1-2.
5-6 - TLS канал, проверка сертификата осуществляется только на стороне клиента (браузера). Данное соединение является просто TLS, т.к. валидация сертификата выполняется только одной из сторон.
7-8 - Аналогично шагу 3-4, но исполняется в рамках канала, установленного в шаге 5-6.
Теперь мы видим, какие типы сертификатов нам понадобятся:
- Корневой сертификат (1) для подписания сертификатов связанных с mTLS соединением
- Сертификат для PostgreSQL сервиса, подписанный корневым сертификатом (1)
- Сертификаты для каждого из пользователей, кто будет логиниться. Каждый сертификат должен быть подписан сертификатом (1)
- Корневой сертификат (2) для подписания сертификатов, связанных с HTTPS соединением
- HTTPS сертификат, подписанный корневым сертификатом (2)
Поехали генерировать сертификаты. Мы же программисты, поэтому, пишем скрипт и необходимый конфиг.
Для начала, определяем какие-то общие переменные:
Теперь можно сгенерировать корневой сертификат для целей mTLS:
Генерируем сертификат для PostgreSQL сервиса и подписываем его ранее полученным:
И генерируем по сертификату для каждого из пользователей:
Генерация сертификатов для HTTPS соединения точно такая же, за исключением того, что пользовательские сертификаты генерировать не нужно.
Немного посмотрим на конфигурацию. Конфигурационные файлы в данном случае имеют ini-подобную структуру, т.е. имеются разделы, а в них ключи и значения. При этом, значения могут ссылаться на какой-то из разделов. Например:
В данном случае, значение ключа basicConstraints ссылается на раздел mtls_root_basic_constraints в котором указано, что мы генерируем Certificate Authority (не смог вменяемый перевод вспомнить), который не может выдавать промежуточные сертификаты.
Применяемую секцию из конфигурационного файла мы передаем как значение параметра -extensions: -extensions v3_mtls_root.
Итак, все сертификаты сгенерированы. Пора конфигурировать PostgreSQL. Начнем с файла pg_hba.conf. Этот файл является частью системы аутентификации.
Наши требования довольно очевидны:
- Разрешаем любое локальное подключение изнутри контейнера
- Любое SSL соединение должно проходить полную валидацию пользовательского сертификата
- Иные соединения запрещены
Далее нам необходимо сконфигурировать параметры запуска сервиса, переменные окружения, пробросить порт и тома. Собственно, эта часть docker-compose.yml может выглядеть так:
Аналогичную конфигурацию, а именно: переменных окружения, проброса порта и томов мы проводим для нашего pgAdmin:
Собственно, из основного - пробрасываем пользовательские сертификаты и корневой сертификат mTLS. Так же пробрасываем серверный HTTPS сертификат. Ну и раз мы все локации сертификатов знаем, можем сразу же пробросить файл с настройками серверов (servers.json):
Итого, что мы имеем на выходе:
- Сконфигурированный PostgreSQL проводящий валидацию на основе CN сертификата.
- Сконфигурированный pgAdmin, который умеет устанавливать mTLS соединение с PostgreSQL и TLS соединение с браузером

PostgreSQL + pgAdmin + mTLS + certificate-based authentication + docker-compose в одном флаконе
Чего у меня не отнять, дак это мастерства заголовка... В какой-то момент при локальной разработке (да, в общем-то и при тестировании на иных стендах) задумываешься о том, как бы избавиться...
