Уровни доступа к базам данных — постоянный спор между DBA и разработчиками: Разработчики хотят быть SUPERUSER всегда и везде, DBA не хотят разгребать проблемы которые дают эти привилегии в неумелых руках.
Рассматривать мы будем исключительно боевое окружение так как тестовые и сервера разработки как водится — “проходной двор”.
Обзор будет состоять из 3 частей:
- Доступ к серверу;
- Доступ к объектам;
- Доступ к данным;
Сегодня мы рассмотрим вопросы доступа к серверу баз данных PostgreSQL
Доступ к серверу PostgreSQL
Первый уровень доступа к базе данных вызывает много споров и холивара из-за механизма pg_hba.conf. Основным камнем преткновения является то, что после изменения этого файла требуется послать сигнал серверу (HUP), что бы он его перечитал. Не будем рассуждать на тему хорошо это или плохо, примем как данность: оно так есть и с этим надо работать.
Для начала требуется понять, а кто или что, собственно может соединяться с нашей базой данных:
- Администратор — с правами суперпользователя и прочими регалиями. Да, управлять сервером нам надо;
- Пользователи приложений — с правами на базу данных этого приложения. Да, приложения должны работать;
- Реплики — с правами на репликацию. Да, реплика тоже нужна;
Вы спросите, а как же разработчики? Да никак, какой сакральный смысл им иметь постоянный доступ в боевую базу данных да еще и наверно с правами суперпользователей? Тем более, у них же есть доступ к базе от пользователя приложения.
Теперь определим откуда могут производиться подключения к базе данных:
- С серверов приложений пользователями приложений;
- С серверов реплик пользователем репликации;
Можно еще добавить сюда сервера бекапов, но только для пользователя реплики, ибо делать pg_dump удаленно — моветон.
Администратор соединятся удаленно не может в принципе. Отсюда первое правило pg_hba.conf:
host all postgres 127.0.0.1/32 password
Пароль в основном как защита от дурака, так как на сервере работают службы мониторинга которые в теории могут удаленно выполнить команду shell. А пароль знаю не только я — значит знают все. Так же я не использую Unix Socket так как PostgreSQL у меня работает в контейнере и с корневой машины сокет доступен через файловую систему, а значит правила local распространяется как на контейнер так и на корневую машину.
Далее определяемся с группами внешних серверов, здесь несколько вариантов:
Netmask
Сервера приложений и сервера реплик (баз данных) выделены в отдельные сегменты приватной сети (например: 10.1.0.0/16 и 10.2.0.0/16 соответственно) и соединения осуществляются по приватным адресам, тогда запись для пользователей приложений и реплик будет выглядеть так:
host all postgres 127.0.0.1/32 password
host all +project 10.1.0.0/16 password
host replication replica 10.2.0.0/16 password
DNS
Можно сделать записи в /etc/hosts для серверов приложений и серверов реплик. Только следует иметь ввиду что резолвится будет только первая запись с соответствующим IP адресом:
/etc/hosts
1.1.1.1 server01.production
4.3.2.1 server02.production
2.3.4.5 server03.database
5.6.7.8 server04.database
pg_hba.conf
host all postgres 127.0.0.1/32 password
host all +project .production password
host replication replica .database password
Коннектор
У меня же стоит коннектор pgbouncer и пользователи приложений соединяются через порт 6432, а реплики через родной 5432, а в firewall настроен доступ к этим портам для соответствующих групп серверов. Парольная авторизация для пользователей приложений не нужна, так как пароль проверяет pgbouncer. В итоге pg_hba.conf имеет вид:
host all postgres 127.0.0.1/32 password
host all +project 127.0.0.1/32 trust
host replication replica 10.0.0.0/8 password
Теперь разберем подробнее, что за пользователь +project и база данных replication.
Начнем с простого:
- базы данных replication конечно нет, но это ключевое слово, которое говорит о том, что требуется просто сопоставить пользователя с хостом, а база данных ему не важна. И действительно, репликация оперирует всем экземпляром PostgreSQL и отдельные базы данных ему не важны (в логической репликации работают совсем другие механизмы).
- +project — роль пользователей приложений, то есть, если все пользователи приложений принадлежат этой роли, для этого создается роль project:
CREATE ROLE projects
NOINHERIT
NOREPLICATION
LOGIN
PASSWORD 'any password';
А все остальные пользователи создаются с участием этой роли:
CREATE ROLE {{ project role }}
NOINHERIT
NOREPLICATION
LOGIN
PASSWORD '{{ some password }}'
IN ROLE projects;
Наследовать привилегии от роли projects или нет (NOINHERIT) — дело вкуса, я так не делаю, так как это может внести некоторую путаницу.
Остальные привилегии сильно зависят от задачи и архитектуры, поэтому тут не рассматриваются дабы не распыляться по контексту.
В некоторых случаях можно временно предоставить определенные права пользователю, например CREATEDB, на момент инициализации приложения и разворачивании базовой схемы данных. Но после этого данное право следует отключить, если оно не требуется функционально в процессе работы (CREATEDB — это не только CREATE DATABASE, но еще и DROP DATABASE).
На этом можно закончить настройку pg_hba.conf. При этом мы сделали его достаточно универсальным, что бы не метять его настройки с течением времени, а только в исключительных случаях.
А вот доступ к определенным базам данных определяется на уровне объектов PostgreSQL. И это мы рассмотрим в следующем обзоре.
Резюме
Понятно, что такое использование pg_hba.conf не является «таблеткой» от всех болезней, но для типовых случаем подойдет более чем;