Как готовить базу данных postgres API приложения для prod режима
Допустим у вас есть база postgres и у вас есть автоматические тесты. Для автоматических тестов вам нужна отдельная база с пользователей к этой базе. Сколько баз и пользователей сделать ? Тут есть масса тонкостей. Покажу вам лучшие практики.
Для нашего случая с двумя основными базами (db — продакшн, db_test — тестовая) и, возможно, третьей (postgres или шаблонной) — рекомендуемое количество пользователей (ролей) в PostgreSQL зависит от среды (development vs production) и принципа least privilege (минимальных необходимых прав).
Минимальное количество пользователей
Всего 3–5 ролей (не считая системных вроде postgres).
- 1 суперпользователь/админ (например, admin или стандартный postgres) — для инициализации, миграций, бэкапов. Не используйте его в приложении!
- 1 пользователь для продакшн-базы (user_prod или user) — только для db. Права: CONNECT, USAGE/CREATE на схему public (для миграций), DML на таблицы (SELECT/INSERT/UPDATE/DELETE). 1 пользователь для тестовой базы (test_user или user_test) — только для db_test. Те же права, но отдельно.
- Опционально: отдельная роль для миграций (DDL — CREATE/ALTER/DROP) — если используете ОРМ Alembic/Flyway. Она может быть временной или с повышенными правами только на время деплоя. Опционально: read-only роль — для мониторинга/отчётов.
Это минимум для безопасности: каждый пользователь имеет доступ только к своей базе.
Лучшие практики (best practices)
Принцип least privilege — основной в PostgreSQL (рекомендации AWS, Crunchy Data, официальной документации):
- Никогда не подключайте приложение под суперпользователем.
- REVOKE CONNECT FROM PUBLIC на всех базах, затем GRANT CONNECT только нужным пользователям.
- Отдельные пользователи для прод и тест — чтобы утечка пароля из теста не затронула прод.
- В продакшн: приложение имеет только DML-права (не DDL, не DROP).
Разделение сред:
- Development: Можно 1–2 пользователя (даже с CREATEDB для удобства разработчиков). Локально — часто один пользователь на всё.
- Test/Staging: Как прод, но с отдельным пользователем. Тестовая база — копия прод (анонимизированная).
- Production: Строго отдельные пользователи, разные пароли. Нет CREATEDB/CREATEROLE.
Дополнительные роли:
- Group roles (без LOGIN) для группировки прав: например, app_readwrite — с USAGE + DML, затем GRANT этой роли пользователям.
- Для миграций: отдельный пользователь с DDL-правами (или временно повышайте права админом).
- Явные правила для каждой комбинации база + пользователь.
- Reject для запрещённых (перекрёстных) подключений.
- scram-sha-256 (не md5).
Другие рекомендации:
- Пароли: сильные, храните в секретах (Docker secrets, .env не в git).
- Мониторинг: pgAudit для логов доступа.
- Миграции: ALTER DEFAULT PRIVILEGES — чтобы новые таблицы автоматически получали права.
- Не используйте schema public в прод без ограничений (или создайте отдельную schema).
Вы можете пойти простым путём. Создать простого пользователя user. У этого пользователя не должно быть суперадминских прав на все базы данных, а доступ только к одной базе. Этого пользователя можно использовать и для миграций тоже. Проследите чтобы пользователей не мог переключаться с одной базы в другую. Один пользователь должен пользоваться только одной базой данных! Не удаляёте суперадмина postgres и не переименовывайте его! Если ваша база открыта наружу и видна в сети, то отрежьте пользователя postgres от всех баз и системных тоже. Вы должны сделать такие настройки чтобы вы могли легко подключаться под postgres локально в контейнере. Также в контейнере вы у вас должна быть возможность перемещаться из одной базы в другую. У вас не должно быть возможности подключаться под postgres по ip к любой базе.
Используйте запреты для postgres в pg_hba.conf.
# pg_hba.conf
# Запрещаем суперпользователю postgres подключаться к прод- и тестовой базам с внешних IP
host db postgres 0.0.0.0/0 reject
host db postgres ::/0 reject
-- для простых пользователей используйте REVOKE CONNECT и GRANT CONNECT
REVOKE CONNECT ON DATABASE "db" FROM PUBLIC;
GRANT CONNECT ON DATABASE "db" TO "user";
Лучше добавлять права через CONNECT, чем постоянно менять права в pg_hba.conf. Помните, что CONNECT не работает для суперпользователей таких как postgres!