База данных
Этот документ описывает базовые требования к PostgreSQL для работы SmartCPD, поддерживаемые модели доступа и принципы организации схем и ролей.
Базовые требования#
- Поддерживаемая СУБД: PostgreSQL.
- Поддерживаемая версия:
14+.
Это не означает, что SmartCPD гарантированно не будет работать на более старых версиях PostgreSQL, но разработка и тестирование выполняются только на поддерживаемых LTS и не End-of-Life версиях.
- Мультиплексоры и connection pooler-решения типа
pgbouncerв текущей версии SmartCPD не поддерживаются. - PostgreSQL не входит в состав поставки SmartCPD. Подготовка, установка, отказоустойчивость, эксплуатация, мониторинг, backup и restore базы данных находятся в зоне ответственности Заказчика.
Отказоустойчивость БД#
Требования к отказоустойчивой схеме PostgreSQL и поведение SmartCPD при недоступности БД описаны в разделе База данных.
При недоступности БД SmartCPD продолжает обслуживать вызовы, но деградирует по ряду функций, завязанных на доступ к данным. В первую очередь это влияет на:
- административные интерфейсы;
- возможность управления и настройки;
- авторизацию при использовании API;
- потерю статистических данных (
cdr).
Со стороны SmartCPD поддерживается только единый внешний DB endpoint. Если инфраструктура Заказчика использует primary/replica или иную HA-схему PostgreSQL, переключение между экземплярами должно быть скрыто за этим endpoint.
Поддерживаемые модели доступа#
SmartCPD поддерживает две модели организации доступов к PostgreSQL:
per-schema- простая настройка и администрирование;
- простое сопровождение миграций;
- меньшее разграничение доступа между внутренними сервисами SmartCPD.
per-service- более сложная настройка
- необходимость контроля изменений схемы при миграциях;
- более удобный аудит;
- более точный контроль владения и доступа к объектам БД.
Обе модели поддерживаются. Выбор конкретной модели зависит от требований к разграничению прав, сопровождению и правилам эксплуатации базы данных на стороне Заказчика.
Возможен переход от одной к другой в процессе эксплуатации.
per-schema#
В этой модели используется один пользователь на каждую схему БД или на группу близких по назначению сущностей.
Это базовый вариант для типовой установки.
Требуемые роли:
smartcpd- основной пользователь сервисов SmartCPD для схемыpublic;grafana- пользователь сервисаgrafanaдля схемыgrafana.
Итого: 2 роли и 2 пароля.
Плюсы:
- минимальное количество пользователей;
- простое разграничение доступа;
- простая настройка и администрирование;
- простые миграции: если новая роль не появляется, дополнительные действия обычно не требуются.
Когда использовать:
- не требуется максимально подробное разграничение доступов между внутренними сервисами SmartCPD;
- не требуется детальный аудит межсервисного доступа к объектам БД;
- важнее простота сопровождения, чем максимальная изоляция ролей.
Ограничения:
- один пользователь SmartCPD используется сразу несколькими сервисами;
- возможности аудита ограничены;
- владение и доступ к объектам БД контролируются менее детально.
per-service#
В этой модели отдельный логин используется для каждого сервиса SmartCPD.
Это более строгий вариант организации доступов.
Требуемые роли:
smartcpd- пользователь по умолчанию для портала и базового доступа кpublic;grafana- пользователь сервисаgrafanaдля схемыgrafana;billing- пользователь сервисаbilling;amd- пользователь сервисаamd;markup- пользователь сервисаmarkup;analyzer- пользователь сервисаanalyzer;grafana_ds- datasource-пользовательgrafanaдля чтения продуктовых данных SmartCPD.
Итого: 7 ролей и 7 паролей.
Плюсы:
- более точное разграничение прав;
- более удобный аудит действий сервисов;
- более понятный контроль ownership и доступа к объектам БД;
- более прозрачная схема межсервисного взаимодействия через роли и grants.
Когда использовать:
- требуется детальное разграничение доступов между сервисами;
- важен аудит действий отдельных сервисов;
- нужно отдельно контролировать ownership и grants по объектам БД.
Ограничения:
- настройка и сопровождение сложнее, чем в
per-schema; - при изменении схемы и ролевой модели нужно контролировать влияние миграций на права и ownership;
- эксплуатационная модель требует большей дисциплины при сопровождении БД.
Организация схем и ролей#
Граница ответственности#
Управление БД SmartCPD ограничивается ролевой моделью, схемами, базовыми правами доступа и общей организацией DB-контура в соответствии с выбранной моделью доступа.
Контроль прикладного содержимого и его структуры выполняют сами сервисы SmartCPD. Это относится к таблицам, миграциям и дальнейшему изменению объектов, которыми сервисы владеют в рамках своей логики работы.
Разделение схем#
В PostgreSQL используется разделение схем по назначению.
publicиспользуется для данных и объектов, которыми управляют сервисы SmartCPD;- отдельные схемы используются для third-party компонентов и внешних по смыслу подсистем. Существующие схемы:
grafana- хранит настройки и исторические данный сервисаgrafana
Такое разделение нужно, чтобы:
- не смешивать прикладные сущности SmartCPD с внешними и служебными объектами;
- упрощать контроль ownership и grants;
- сохранять понятную структуру БД при сопровождении и расширении решения.
Дальнейшее расширение структуры#
В дальнейшем структура БД может расширяться по тому же принципу:
- прикладные объекты SmartCPD остаются в
public; - для third-party компонентов и внешних по смыслу подсистем используются отдельные схемы и отдельные роли.
Скрипты поставки#
В поставку SmartCPD входят SQL-скрипты для подготовки PostgreSQL и восстановления ролевой модели.
Использование скриптов поставки не является обязательным. Если подготовка PostgreSQL выполняется вручную, роли, схемы и grants должны быть приведены в соответствие с выбранной моделью доступа и таблицами доступов, приведенными ниже в этом документе.
В поставке они располагаются в каталоге:
db/postgresОсновные скрипты:
db/postgres/sql/00-create-db-once.sqlсоздает БД. Скрипт используется однократно при первоначальной подготовке PostgreSQL.db/postgres/sql/10-users-required.sqlсоздает обязательные роли и применяет базовые права для минимальной модели.db/postgres/sql/20-users-optional.sqlдобавляет роли и межсервисные grants для моделиper-service.db/postgres/sql/90-restore-single-user-ownership.sqlвозвращает владение объектами вpublicк схеме с единым владельцем.db/postgres/sql/91-restore-billing-user-ownership.sqlвосстанавливает ownership объектов, относящихся кbilling.db/postgres/sql/92-restore-markup-user-ownership.sqlвосстанавливает ownership объектов, относящихся кmarkup.
Повторный запуск 10-users-required.sql и 20-users-optional.sql является штатным сценарием. Скрипт 20-users-optional.sql всегда выполняется только после 10-users-required.sql, в том числе при обновлениях. Эти скрипты используются для обновления паролей, восстановления grants и приведения ролевой модели к ожидаемому состоянию при обновлениях и миграциях.
Назначение и именование скриптов сохраняются от релиза к релизу, что позволяет использовать их в автоматизации, например через CI/CD, Ansible или аналогичные средства. Перед обновлением рекомендуется ознакомиться с примечаниями релиза и выполнить скрипты, соответствующие выбранной модели доступа.
Использование в IDE#
SQL-скрипты можно запускать из IDE, например DBeaver, DataGrip или pgAdmin.
При таком использовании:
- значения
DB_*параметров нужно подставлять явно перед выполнением скрипта; - обычно для этого либо заменяют плейсхолдеры в тексте скрипта на конкретные значения, либо используют механизм SQL-переменных самой IDE, если он поддерживается;
- подключение должно выполняться под ролью с достаточными правами для выбранного сценария;
- для
00-create-db-once.sqlподключение выполняется к служебной БДpostgres; - для остальных скриптов подключение выполняется к целевой БД SmartCPD.
Это удобно, когда нужно подготовить БД вручную, проверить результат выполнения или точечно повторить отдельный скрипт.
Использование в CLI#
Для запуска из командной строки используется psql с передачей переменных через -v.
Пример для создания БД:
psql -v ON_ERROR_STOP=1 -d postgres \
-v DB_NAME=smartcpd \
-f db/postgres/sql/00-create-db-once.sqlПример для применения обязательных ролей:
psql -v ON_ERROR_STOP=1 -d smartcpd \
-v DB_PORTAL_USER=smartcpd \
-v DB_PORTAL_PASSWORD=... \
-v DB_GRAFANA_USER=grafana \
-v DB_GRAFANA_PASSWORD=... \
-f db/postgres/sql/10-users-required.sqlПример для модели per-service (строго после применения обязательных ролей):
psql -v ON_ERROR_STOP=1 -d smartcpd \
-v DB_PORTAL_USER=smartcpd \
-v DB_BILLING_USER=billing \
-v DB_BILLING_PASSWORD=... \
-v DB_AMD_USER=amd \
-v DB_AMD_PASSWORD=... \
-v DB_MARKUP_USER=markup \
-v DB_MARKUP_PASSWORD=... \
-v DB_ANALYZER_USER=analyzer \
-v DB_ANALYZER_PASSWORD=... \
-v DB_GRAFANA_DS_USER=grafana_ds \
-v DB_GRAFANA_DS_PASSWORD=... \
-f db/postgres/sql/20-users-optional.sqlНабор передаваемых переменных зависит от конкретного скрипта. Перед запуском рекомендуется открыть соответствующий SQL-файл и проверить список ожидаемых
DB_*параметров.
Восстановление прав без суперпользователя#
Если у оператора нет прав на CREATE ROLE, ALTER OWNER и другие административные действия, можно использовать генераторы из db/postgres/utils:
db/postgres/utils/generate-ownership-restore.sqlгенерирует командыALTER ... OWNER TO ...;db/postgres/utils/generate-permissions-restore.sqlгенерирует командыGRANTиALTER DEFAULT PRIVILEGES;db/postgres/utils/list-object-owner.sqlпоказывает текущих владельцев объектов вpublic.
Оба генератора возвращают набор команд, сгруппированных по роли, от имени которой их нужно выполнить, и в порядке, в котором эти команды должны применяться. Это позволяет поэтапно восстанавливать grants и ownership даже в ограниченном контуре доступа.
Таблица доступов#
per-schema#
В модели per-schema владение объектами организуется на уровне схем.
| Схема | Владелец всех сущностей |
|---|---|
public | smartcpd |
grafana | grafana |
per-service#
В модели per-service для сервисов SmartCPD используются отдельные роли.
| Роль | Назначение | Базовые права | Дополнительные межсервисные права |
|---|---|---|---|
portal | Пользователь по умолчанию | USAGE/CREATE на public, search_path=public | Нет |
grafana | Сервис Grafana | Владелец схемы grafana, USAGE/CREATE на grafana, search_path=grafana | Нет |
billing | Сервис биллинга | CONNECT, USAGE на public, CREATE на public, search_path=public | Выдает SELECT для smartcpd, grafana_ds, analyzer; выдает SELECT/INSERT/UPDATE для amd |
amd | Сервис AMD | CONNECT, USAGE на public, search_path=public | Использует таблицы и sequence, созданные billing |
markup | Сервис markup | CONNECT, USAGE на public, CREATE на public, search_path=public | Выдает SELECT для grafana_ds и analyzer на свои таблицы в public |
analyzer | Сервис analyzer | CONNECT, USAGE на public, search_path=public | Получает SELECT на данные billing и markup в public |
grafana_ds | Datasource-пользователь Grafana | CONNECT, USAGE на public, search_path=public | Получает SELECT на данные smartcpd, billing и markup в public |
Часть таблиц SmartCPD является партиционированными, и их дочерние таблицы могут создаваться автоматически в процессе работы или миграций. Чтобы не требовать ручного вмешательства при каждом таком изменении, важно, чтобы новые сущности наследовали grants, уже заданные для соответствующих ролей и схем.