Чего у меня не отнять, дак это мастерства заголовка...
В какой-то момент при локальной разработке (да, в общем-то и при тестировании на иных стендах) задумываешься о том, как бы избавиться от довольно монотонных действий. Одним из них является ввод пароля в рамках процесса аутентификации в PostgreSQL. В этой статье я расскажу как слегка автоматизировать данный процесс.
Данная статья является легким переосмыслением того, что я написал на медиуме. Ибо думать я продолжаю на русском (:
TL;DR исходники к вашим услугам.
В рамках любых взаимодействий мы сталкиваемся с такими сущностями как авторизация и аутентификация. Повторять в 100500 раз что есть что я не буду (но мне не лень такую длинную ремарку напечатать, ага). В рамках PostgreSQL первое обеспечивается через Roles, а второе через Privileges.
Если покопаться в документации PostgreSQL, то можно обнаружить, что эта БД поддерживает довольно много типов авторизации. Однако, нас интересует что-то, что могло бы заменить связку логина и пароля. И в этот момент авторизация на основе сертификатов приходит на гугл ум. В общем-то, при корректной настройке, мы не только избавляемся от необходимости ввода пароля для нашего пользователя, но и повышаем уровень защищенности (подделка сертификата немножко сложнее угадывания любимого пароля, который у меня - "qwerty").
Давайте подумаем над тем, чего мы хотим достичь. Но думать просто так скучно, поэтому запишем наши требования в формате пользовательских историй!
Как пользователь, я хочу иметь доступный инстанс 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)
Эмпирическим путем было установлено, что Apple Keychain не поддерживает корневые сертификаты с размером ключа больше чем 8192 бита (что очевидно следует из текста ошибки "Error: -67762"), так что, ограничимся этой размерностью.
Поехали генерировать сертификаты. Мы же программисты, поэтому, пишем скрипт и необходимый конфиг.
Для начала, определяем какие-то общие переменные:
Теперь можно сгенерировать корневой сертификат для целей 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 соединение с браузером
Хочется думать, что данный контент оказался вам полезен. Всегда готов ответить вам по DEFAULT_EMAIL - не стесняйтесь.
Комментарии (10)
ptr128
31.03.2024 12:10Но почему не GSSAPI?
Delfik Автор
31.03.2024 12:10У автора лапки, macOS и в домашней сети не оказалось нужной инфраструктуры.
ptr128
31.03.2024 12:10Поднять хотя бы Samba DC можно и в контейнере. Зато это будет масштабируемо.
LDAP с Kerberos можно запускать даже в той же вируталке, что и PostgreSQL. Раньше так и делал.
Delfik Автор
31.03.2024 12:10Зато это будет масштабируемо.
Оставив за скобками момент, что я в первых же строчках писал про локальную разработку, в какой момент у сертификатов пропало масштабирование?
LDAP с Kerberos можно запускать даже в той же вируталке, что и PostgreSQL. Раньше так и делал.
Где-то я пропустил в тексте, что запускаю это все на виртуалке. Как обнаружу - дам более развернутый комментарий.
В любом случае, получаем дополнительный сервис, а хочется побриться бритвой Оккама.
Ну и просто вопрос. А GSSAPI точно удовлетворяет требованию 4? Я его, конечно, сформулировал в слишком фривольной манере, но подразумевалось что непосредственный канал связи с сервером БД должен быть mTLS.
ptr128
31.03.2024 12:10+1в какой момент у сертификатов пропало масштабирование?
Как только появляются реальные пользователи, которым все равно необходимо будет получать билетики, механизм сертификатов для них окажется пятой ногой. Ведь механизм сертификатов потребует разработки целой инфраструктуры. Ведь в целях безопасности, эти сертификаты все равно нужно будет выдавать пользователям всего на несколько часов, так же, как и билетики. Последние выдаются, обычно, на 8-12 часов.
Но главная проблема масштабирования - доверительность по отношению ко всем сервисам, а не только к KDC. Билетики выдаются пользователям всегда на конкретный сервис, тогда как сертификаты пользователей к сервисам не привязаны. Когда у Вас лишь один сервис (PostgreSQL) - это значения не имеет. Но когда у Вас сотни сервисов - это уже дыра в безопасности.
Где-то я пропустил в тексте, что запускаю это все на виртуалке
Вы пропустили слова даже и раньше. Я указал, что Kerberos я использовал еще до появления в природе докера. Лет 25 назад.
В любом случае, получаем дополнительный сервис
В подавляющем большинстве случаев, как только решение будет масштабировано за пределы локального хоста, Kerberos будет доступен. Более того, в моей практике, Kerberos всегда был доступен, пусть даже и через VPN. То, что из-за бюрократии не всегда оперативно добавлялись SPN для сервисов моего локального хоста - это уже другой вопрос.
подразумевалось что непосредственный канал связи с сервером БД должен быть mTLS.
Kerberos иначе и не умеет. Разница в том, как я указал выше, что сертификат (билетик) клиенту выдается KDC на конкретный сервис, а не на всё скопом.
atshaman
31.03.2024 12:10П.0 - я как пользователь _не хочу_ трогать pgAdmin даже ОЧЕНЬ длинной палкой. Можно? Ну позя-зя-зя?!
sshikov
Ну если честно, то это далеко не очевидно. У вас же много пользователей, правда? Представим что в какой-то момент вы их всех решили тоже аутентифицировать по сертификатам. Бац - и у вас в компании появился свой Удостоверяющий Центр (это перевод CA, если что). И у вас вместо записанных там и сям на бумажке паролей - валяющиеся там и сям на дисках пользовательские сертификаты. Много. В непонятном состоянии. Непонятно когда протухнут.
А уж тихая и незаметная утечка корневого сертификата, которым можно подписать пользовательский, точно такой же, под которым у вас ходит в базу DBA... это вообще.
Ну я надеюсь вы поняли. Перевод на сертификаты - это куча дополнительного высокоуровневого гемора на голову админов. В каком-то смысле уровень защищенности может и растет, но схема усложняется, в ней появляются новые неочевидные дыры в безопасности. Станет ли в итоге лучше - совсем не факт. А вот сложнее для всех - станет точно.
Вы ведь не забыли себе в календарь записать, что нужно перевыпустить сертификат через годик, да? :)
Delfik Автор
Я в самом начале упомянул
намеренно, чтобы сгладить некоторые углы, которые вы подсветили =)
Пользователей то много, да. Но вот если всем нужен доступ до прода, то, кажется, это больше про характеристику компании / процесса разработки будет, нежели про проблематику валяющихся пользовательских сертификатов.
Опять же, если будет утечка корневого сертификата да еще из абстрактного УЦ с СКЗИ класса защиты КС3, то это будет новость интереснее свежей новости про
xz
.Без шуток - да.
Ну и говоря про проблематику ротации сертификатов, есть же уже действующие решения. Vault + agent / импортозамещенный вариант под названием SecMan
Опять же, если хочется говорить про применимость к prod environment, там можно и скомбинировать полную взаимную проверку сертификатов с проверкой пароля. Добавим конфигурацию проверки по IP (все та же строчка в
pg_hba.conf
). Плюсом кажется сетевая инфраструктура организации должна быть настроена правильным образом ;)sshikov
Да не то слово.
Я знаю про vault, мы как раз в процессе внедрения. Поэтому и решил позадавать вопросы в том числе.
stvoid
Для локальной разработки вам хватит файла .pgpass