Сценарии администрирования#

Администрирование компонента Pangolin (PSQL) продукта Platform V Pangolin SE (PSQ) (далее – Pangolin) осуществляется средствами, которые описаны в этом разделе.

Реализация АРМ администратора#

Для администрирования системы используется утилита psql. Эта утилита представляет собой терминальный клиент для передачи запросов к СУБД и отображения результатов.

psql [параметр...] [имя_бд [имя_пользователя]]

Примечание:

Решение по обеспечению безопасности АРМ администратора должно исходить из окружения конечной АС.

Получение информации об используемой версии#

В данном разделе приведены примеры команд для получения используемой версии Pangolin. Примеры команд одинаковы для любой из используемых ОС.

Для клиентской части#

Чтобы получить название и версию клиентской части Pangolin, запустите любую команду с ключом --product_version, например:

Команда:

pg_ctl --product_version

Результат выполнения команды:

Platform V Pangolin 5.2.0

где:

  • Platform V Pangolin SE — наименование продукта;

  • 5.2.0 — версия продукта.

Чтобы получить название и версию PostgreSQL, запустите любую команду с ключом --version, например:

Команда:

pg_ctl --version

Результат выполнения команды:

pg_ctl (PostgreSQL) 13.4

Для серверной части#

Для получения названия и версии продукта серверной части подключитесь к серверу Pangolin, чтобы:

  • узнать версию Pangolin:

    Команда:

    SELECT product_version();
    

    Результат выполнения команды:

        product_version
    ---------------------------
    Platform V Pangolin SE 5.1.0
    (1 row)
    
  • узнать версию PostgreSQL:

    Команда:

    SELECT version();
    

    Результат выполнения команды:

                                                    version
    ---------------------------------------------------------------------------------------------------------
    PostgreSQL 13.4 on x86_64-pc-linux-gnu, compiled by gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-44), 64-bit
    (1 row)
    

    Примечание:

    Вывод может отличаться от приведенного в примере.

Получение информации о сборке продукта#

Чтобы получить информацию о сборке Pangolin, запустите любую команду с ключом --product_build_info, например:

Команда:

pg_ctl --product_build_info

Результат выполнения команды:

build 54 (22:27:09 05.02.2022) commit cbb7a012923abe4143bc029c6ae7fe31be636ee5

где:

  • 54 — порядковый номер сборки продукта;

  • 22:27:09 05.02.2022 — время и дата сборки продукта;

  • cbb7a012923abe4143bc029c6ae7fe31be636ee5 — хеш-сумма исходных кодов продукта (идентификатор коммита в git репозитории продукта).

Пример вывода информации о сборке продукта для psql:

Команда:

SELECT product_build_info();

Результат выполнения команды:

build 54 (22:27:09 05.02.2022) commit cbb7a012923abe4143bc029c6ae7fe31be636ee5

Примечание:

Вывод может отличаться, но будет сохранена структура и формат.

Получение хеш-суммы внутренней версии компонента продукта#

Для PostgreSQL можно получить хеш-сумму с помощью параметра --product_component_hash, например:

Команда:

pg_ctl --product_component_hash

Результат выполнения команды:

ae6aec146801794bb9d95c3821ca039bff6ea7d4

Интерфейс администратора безопасности Pangolin#

Интерфейс администратора безопасности включает в себя следующие функции:

  • Действия с политиками:

    • pm_get_policies - вывод списка политик;

    • pm_get_policy_grants - вывод списка разрешений (правил) в составе политики;

    • pm_make_policy - создание политики;

    • pm_grant_to_policy - внесение в политику разрешения на действия над объектом;

    • pm_revoke_from_policy - исключение из политики разрешения на действия над объектом;

    • pm_suspend_object - приостановка действия политики защиты;

    • pm_resume_object - возобновление действия политики защиты;

    • pm_remove_policy - удаление политики защиты.

  • Действия с пользователями:

    • pm_get_assigned_policies - вывод списка политик, назначенных пользователю;

    • pm_assign_policy_to_user - назначение политики пользователю;

    • pm_unassign_policy_from_user - изъятие политики у пользователя.

  • Действия над объектами:

    • pm_get_protected_objects - вывод списка объектов, находящихся под защитой;

    • pm_protect_object - помещение объекта БД под защиту;

    • pm_unprotect_object - снятие защиты с объекта БД;

    • pm_get_object_access_path - получение информации об эффективных действующих для указанных объекте и роли ограничениях защиты и разрешениях на доступ к объекту под защитой.

  • Действия для администраторов безопасности:

    • pm_create_security_admin - создание учетной записи администратора безопасности;

    • pm_set_security_admin_password - изменение пароля учетной записи администратора безопасности;

    • pm_grant_security_admin - назначение пользователя администратором безопасности;

    • pm_revoke_security_admin - снятие с пользователя политики администратора безопасности;

    • pm_unblock_security_admin - разблокировка заблокированной учетной записи администратора безопасности.

Интерфейс управления парольными политиками: PL/pgSQL API#

Все запросы к базе выполняются через SPI интерфейс (то есть не через внутренний API Pangolin), так как вероятность изменения SQL интерфейса меньше.

Настройки механизма хранятся в файле postgresql.conf. Данный файл также содержит значения по умолчанию для настроек парольной политики. Настройки парольной политики хранятся в таблице pg_pp_policy.

При включенной защите от привилегированных пользователей, в режиме защищенного конфигурирования, параметры парольных политик конфигурируются администратором безопасности в хранилище секретов — HashiCorp Vault, в случае отсутствия KMS-hosts (использования эмулятора) для хранения параметров используются локальные конфигурационные файлы.

Параметры парольной политики хранятся в файле в зависимости от типа конфигурации сервера, если тип конфигурации:

  • standalone — в файле $PGDATA/postgresql.conf;

  • cluster — в файле /etc/pangolin-manager/postgres.yml.

Подробнее о параметрах файла postgresql.conf в разделе «Параметры в postgresql.conf» данного документа.

Внимание!

При подключении через Pangolin Pooler с включенной сквозной аутентификацией ограниченно действуют парольные политики в части времени действия пароля и количества подключений. Проверка происходит только при первом подключении. Это связано с тем, что при подключении под Pangolin Pooler создается токен подключения. После получения данного токена следующее переподключение произойдет через server_lifetime.

Сценарии работы с механизмом#

Большинство операций выполняется соответствующими функциями PL/pgSQL (см. «Список PL/SQL функций продукта», раздел «Парольные политики»):

  • создание парольной политики;

  • активация парольной политики;

  • деактивация парольной политики;

  • отображение парольных политик, примененных к роли;

  • отображение всех активных политик;

  • разблокировка роли.

Включение механизма (password_policies_enable)#

Параметр password_policies_enable включает (on) или выключает (off) механизм.

Статистика и история по паролю ведется в любом состоянии механизма.

Использование значений настроек парольной политики из файла postgresql.conf (password_policy.deny_default)#

Параметр password_policy.deny_default включает (on) или выключает (off) использование значений для настроек парольной политики из файла postgresql.conf.

Примечание:

Если выключить параметр password_policy.deny_default:

password_policy.deny_default=off

то для всех политик должны быть заданы все обязательные настройки (см. подраздел «Обязательные настройки парольной политики» данного документа).

Управление шифрованием пароля (password_policy.psql_encrypt_password)#

Параметр password_policy.psql_encrypt_password управляет шифрованием пароля при передаче от фронтенда (psql) к базе с помощью команды psql \password .

В случае, если шифрование отключено, пароль передается хешем. Если при этом включены проверки пароля (сам механизм и один из способов проверки пароля), парольными политиками будет вызвана ошибка.

Задание значений по умолчанию для настроек парольной политики#

Все настройки для парольной политики имеют аналог в файле postgresql.conf. Это необходимо для возможности задания значения по умолчанию для настроек парольной политики.

Подробное описание настроек приведено в разделе «Использование значений настроек парольной политики из файла postgresql.conf» данного документа.

Создать новую политику#

Примечание:

Для созданной парольной политики необходимо перечислить параметры с новыми значениями и указать связанные с ними параметры.

Если связанные параметры с основным не будут указаны, то новая политика не применится.

Для создания новой политики последовательно выполните функции:

  1. Создания парольной политики.

    Примечание:

    Если какая-либо настройка политики не задана, то ее значение берется из конфигурационного файла.

  2. Активации парольной политики.

Функции создания и активации парольной политики описаны в «Документация на публичные API», раздел «Функции для работы с парольными политиками».

Разблокировать роль#

Выполняется соответствующей SQL-функцией (см. «Документация на публичные API», раздел «Функции для работы с парольными политиками»).

Активировать или деактивировать политику#

Выполняется соответствующими SQL-функциями:

  • активация парольной политики;

  • деактивация парольной политики.

Подробнее о функциях см. «Документация на публичные API», раздел «Функции для работы с парольными политиками»

Изменить настройки политики#

Выполняется соответствующей SQL-функцией (см. «Документация на публичные API», раздел «Функции для работы с парольными политиками»).

При изменении параметров учитывайте зависимости между ними и изменяемую функциональность (см. ниже подраздел «Обязательные настройки парольной политики»). Нельзя изменить параметр roloid.

Сменить политику для роли#

Роли связаны с политиками по идентификатору роли. Изменить политику для роли можно следующими способами:

  • удалить старую политику и создать новую политику;

  • включить роль в другую роль с нужной политикой.

Подробнее о функциях см. «Документация на публичные API», раздел «Функции для работы с парольными политиками»

Обязательные настройки парольной политики#

Функциональность

Обязательный параметр

Зависимые параметры

Хранение паролей

Один из: reusetime или inhistory

-

Изменение пароля

minage

-

Синтаксическая проверка пароля

checksyntax

minlength, alphanumeric, minalphachars, minspecialchars, minuppercase, minlowercase, maxrptchars

Использование пакета cracklib

illegalvalues

-

Проверка пароля библиотекой zxcvbn

usepasswordstrengthestimator

passwordstrengthestimatorscore

Пользовательская PSQL функция проверки пароля

customfunction

-

Аутентификация

maxage, graceloginlimit, gracelogintimelimit, lockout, lockoutduration, maxfailure, failurecountinterval, tracklogin, maxinactivity

-

Пользовательская функция проверки пароля#

Пользователь может создать PL/pgSQL функцию проверки пароля. Ниже описаны требования к пользовательской функции.

Требование

Описание

Применимо к механизмам

Создание или изменение роли

Не применимо к механизмам

Аутентификация по паролю

Требования к вызову

Пользовательская функция проверки пароля должна вызываться из PSQL: SELECT func(params)

Прототип

boolean functionName (name user_name, text password,integer password_type)

Входные атрибуты

user_name – имя пользователя; password – пароль; password_type – тип пароля: 0 – незашифрованный, 1 – зашифрованный методом md5, 2 – зашифрованный методом scram-sha-256

Требование к возвращаемому значению

true — проверка пройдена; false — не пройдена

Примечание:

Зашифрованный пароль приходит, если Pangolin подключен к сторонней системе аутентификации.

Параметры для управления транспортными паролями#

Параметр

Описание

password_policy_params.is_temp_tuz_password

Определяет тип пароля (транспортный или нет) для указанных ТУЗ. По умолчанию — true

password_policy_params.transport_password_life_time

Определяет время жизни транспортного пароля. По умолчанию — 0

password_policy_params.transport_password_mark_automatic

При значении true пароль становится транспортным автоматически при смене другим пользователем. При значении false пароль отмечается транспортным вручную. По умолчанию — false

Разблокирование и восстановление работы кластера#

  1. Определите, на каком хосте был последний активный лидер. Это можно проверить по логам Pangolin Manager:

    host1$ sudo journalctl --since "5 hours ago" -u pangolin-manager | grep "i am " | tail -1
    Aug 04 22:38:17 <Адрес сервера> python3[14026]: 2020-08-04 22:38:17,824 INFO: no action. i am the leader with the lock
    host2$ sudo journalctl --since "5 hours ago" -u pangolin-manager | grep "i am " | tail -1
    Aug 04 22:38:07 <Адрес сервера> python3[21032]: 2020-08-04 22:38:07,814 INFO: no action. i am a secondary and i am following a leader
    

    В данном случае лидер был на хосте «host1».

  2. Остановите Pangolin Manager на хосте последнего лидера:

    host1$ sudo systemctl stop pangolin-manager
    
  3. Запустите PostgreSQL в single user режиме:

    host1$ postgres --single
    

    Если postgres не запускается даже на предположительном лидере и выводит ошибку:

    2020-08-04 23:08:34 MSK [20019]: [1-1] app=,user=,db=,client= LOG: database system was shut down in recovery at 2020-08-04 23:08:30 MSK
    2020-08-04 23:08:34 MSK [20019]: [2-1] app=,user=,db=,client= WARNING: recovery command file "recovery.conf" specified neither primary_conninfo nor restore_command
    2020-08-04 23:08:34 MSK [20019]: [3-1] app=,user=,db=,client= HINT: The database server will regularly poll the pg_wal subdirectory to check for files placed there.
    2020-08-04 23:08:34 MSK [20019]: [4-1] app=,user=,db=,client= FATAL: standby mode is not supported by single-user servers
    

    Уберите файл recovery.conf из $PGDATA и снова выполните запуск:

    host1$ mv $PGDATA/recovery.conf{,.back}
    host1$ postgres --single
    
  4. В single user режиме выполните SQL команды от лица пользователя postgres. Для выхода нажмите Ctrl/Cmd-D. Разблокируйте роль postgres:

    select unblock_role('postgres')
    

    Если при попытке разблокировать пользователя postgres выходит ошибка:

    backend> select unblock_role('postgres')
         1: unblock_role        (typeid = 16, len = 1, typmod = -1, byval = t)
        ----
    2022-07-05 11:58:17 MSK [19233]: [2-1] app=[unknown],user=postgres,db=postgres,client=[tty] ERROR:  Cant find role with Oid 10 in password policy cache
    2022-07-05 11:58:17 MSK [19233]: [3-1] app=[unknown],user=postgres,db=postgres,client=[tty] STATEMENT:  select unblock_role('postgres')
    

    Выполните команду для разблокировки пользователя postgres:

    backend> update pg_pp_policy set lockout='f' WHERE roloid = to_regrole('postgres');
    backend>
    
  5. Запустите службу Pangolin Manager.:

    host1$ sudo systemctl start pangolin-manager
    
  6. Убедитесь, что кластер вернулся в стабильное состояние. В таблице вывода в столбце Role должен быть указан Leader:

    host1$ list
    + Cluster: clustername (6857170778029161231) ----------------------------------------+--------------+---------+----+-----------+
    |                 Member                |                    Host                    |     Role     |  State  | TL | Lag in MB |
    +---------------------------------------+--------------------------------------------+--------------+---------+----+-----------+
    | <Адрес сервера>                       | <Адрес сервера>:5433                       | Sync Standby | running |  4 |         0 |
    | <Адрес сервера>                       | <Адрес сервера>:5433                       |    Leader    | running |  4 |           |
    +---------------------------------------+--------------------------------------------+--------------+---------+----+-----------+
    
  7. Стандартным образом разблокируйте остальных администраторов БД.

Справочник журнальных сообщений#

Сообщение

Расшифровка

Решение

User blocked: too many login fails

Пользователь заблокирован из-за превышения счетчика неудачных аутентификаций

Пользователь будет разблокирован, когда пройдет lockoutduration с момента последней неудачной аутентификации. Пользователь может быть разблокирован с помощью команд unblock_role и unblock_role_by_id

Password was expired

Пользователь заблокирован из-за просроченного пароля

Сменить пароль пользователя

Role blocked cause long inactivity

Пользователь заблокирован из-за долгой неактивности

Пользователь может быть разблокирован с помощью команд unblock_role и unblock_role_by_id

Password will expire in <интервал>

Предупреждение об оставшемся времени до обязательной смены пароля

Password was expired. <число> grace logins left

Время жизни пароля превышено. Осталось <число> входов, после которых пользователь будет заблокирован

Password was expired. Grace period ends in <интервал>

Время жизни пароля превышено. Осталось <интервал>, после истечения которого пользователь будет заблокирован

Параметры в postgresql.conf#

В данном разделе более подробно описаны параметры файла postgresql.conf.

password_policy.policy_enable (Состояние по умолчанию для парольной политики)#

Признак включенной парольной политики:

  • on – политика включена;

  • off – политика выключена.

Тип

POSIX шаблон

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

on/off

on

policyenable

password_policy.deny_default#

Запрет использования значений для настроек политик, указанных в файле postgresql.conf:

  • on – включить использование значений настроенных политик, указанных в файле postgresql.conf;

  • off – выключить использование значений настроенных политик, указанных в файле postgresql.conf.

Тип

POSIX шаблон

Значение по умолчанию

boolean

on/off

off

Настройка хранения паролей#

password_policy.reuse_time#

Время в секундах, в течение которого старый пароль сохраняется и попытка сменить пароль на совпадающий со старым заканчивается ошибкой.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

365 days

reusetime

password_policy.in_history#

Максимальное количество сохраненных старых паролей. При достижении максимума добавление еще одного старого пароля приводит к удалению наиболее старого (по pg_pp_history.createtime) из них.

Примечание:

Если задан параметр password_policy.reuse_time, то параметр password_policy.in_history не используется.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

4

0 – Проверка на совпадение пароля с ранее использованным не проводится (при условии reuse_time = 0)

inhistory

Время жизни пароля#

password_policy.max_age#

Время жизни пароля в секундах, после которого пароль считается истекшим.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

0

0 – Проверка максимального времени жизни пароля не производится

maxage

password_policy.min_age#

Время в секундах, которое должно пройти между двумя изменениями пароля.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

0

0 – Проверка максимального времени жизни пароля не производится

minage

password_policy.grace_login_limit#

Максимальное количество аутентификаций, доступных роли после истечения времени жизни пароля.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

0

graceloginlimit

password_policy.grace_login_time_limit#

Время в секундах после окончания действия пароля, в течение которого он продолжает работать. Если вычисленное значение graceloginlimit=0, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

3 days

0 – аутентификация не доступна по истечении времени жизни пароля

gracelogintimelimit

password_policy.expire_warning#

Время в секундах до окончания действия пароля, в течение которого пользователю будет отображаться предупреждение.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

7 days

0 – не выводит предупреждение

expirewarning

Поведение при неудачной аутентификации#

password_policy.lockout#

Блокировка аккаунта в результате достижения максимума попыток входа с неверным паролем:

  • on – включить блокировку;

  • off – выключить блокировку.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

on/off

lockout

on

lockout

password_policy.max_failure#

Максимальное количество введенных подряд неверных паролей, при достижении которого вызывается блокировка пароля.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Аналог в таблице pg_pp_policy

integer

[1-1000]

1 - 1000

6

maxfailure

password_policy.failure_count_interval#

Время в секундах, после которого обнуляется количество неверных вводов пароля.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

>= 0

0

0 – счетчик не обнуляется

failurecountinterval

password_policy.lockout_duration#

Время в секундах, на которое блокируется аккаунт в результате достижения максимума попыток входа с неверным паролем.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

24 hours

0 – блокировка пользователя по количеству неудачных аутентификаций бессрочна

lockoutduration

Синтаксические проверки пароля#

password_policy.check_syntax#

Признак включенных правил синтаксической проверки пароля:

  • on – включить механизм;

  • off – выключить механизм.

Тип

POSIX шаблон

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

on/off

on

checksyntax

password_policy.alpha_numeric#

Минимальное количество цифр в пароле. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

3

0 – не проверять

alphanumeric

password_policy.min_length#

Минимальная длина пароля. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

16

0 – не проверять

minlength

password_policy.min_alpha_chars#

Минимальное количество букв в пароле. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

0

0 – не проверять

minalphachars

password_policy.min_special_chars#

Минимальное количество символов в пароле, не являющихся буквой или цифрой. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

0

0 – не проверять

minspecialchars

password_policy.min_uppercase#

Минимальное количество прописных букв. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

1

0 – не проверять

minuppercase

password_policy.min_lowercase#

Минимальное количество строчных букв. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

0

0 – не проверять

minlowercase

password_policy.max_rpt_chars#

Максимальное количество повторяющихся символов. Если вычисленное значение checksyntax=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

integer

[0-1000]

0 - 1000

0

0 – не проверять

maxrptchars

Проверка максимального времени неактивности пользователя#

password_policy.track_login#

Запоминать ли время последней аутентификации:

  • on – запоминать;

  • off – не запоминать.

Тип

POSIX шаблон

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

[0-1000]

off

tracklogin

password_policy.max_inactivity#

Время в секундах после последней аутентификации, после которого роль будет заблокирована.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Специальные значения параметров

Аналог в таблице pg_pp_policy

string

\d+ s

не отрицательное

0

0 – функциональность отключена

maxinactivity

Использование библиотеки zxcvbn#

password_policy.use_password_strength_estimator#

Включить или выключить использование библиотеки zxcvbn для проверки пароля:

  • on – включить механизм;

  • off – выключить механизм.

Тип

POSIX шаблон

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

on/off

on

usepasswordstrengthestimator

password_policy.password_strength_estimator_score#

Минимальная оценка сложности пароля, допустимая в системе. Если вычисленное значение usepasswordstrengthestimator=false, то параметр не учитывается.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

Аналог в таблице pg_pp_policy

integer

[0-4]

0 - 4

3

passwordstrengthestimatorscore

Использование пользовательской функции проверки пароля#

password_policy.custom_function#

Название пользовательской PL/pgSQL функции проверки пароля.

Тип

POSIX шаблон

Аналог в таблице pg_pp_policy

string

[\w\d]+

customfunction

Использование библиотеки cracklib#

password_policy.illegal_values#

Использовать библиотеку cracklib для проверки пароля по списку часто используемых:

  • on – включить проверку;

  • off – выключить проверку.

Тип

POSIX шаблон

Значение по умолчанию

Аналог в таблице pg_pp_policy

boolean

on/off

on

illegalvalues

Настройка кэширования#

password_policy.pp_cache_dump_interval#

Интервал сохранения данных кэша из памяти на диск (при наличии изменений).

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

integer

\d+

1 - до максимального значения int в системе

10

password_policy.pp_cache_init_size#

Размер изначально инициализированного кэша парольных политик в пользователях.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

integer

\d+

1 - до максимального значения int в системе

10

password_policy.pp_cache_soft_max_size#

Предполагаемый максимальный размер кэша парольных политик в пользователях. Используется для оптимизации работы кэша, не задает жестких ограничений.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

integer

\d+

1 - до максимального значения int в системе

60

password_policy.pp_cache_max_size#

Ограничение сверху на размер кэша парольных политик в пользователях. В случае превышения, аутентификации новых пользователей будут заканчиваться ошибкой.

Тип

POSIX шаблон

Ограничение значения

Значение по умолчанию

integer

\d+

1 - до максимального значения int в системе

1000

psql_encrypt_password#

Шифрование пароля при передаче от фронтенда (psql) к базе:

  • on – включить шифрование;

  • off – выключить шифрование.

Пароль передается в захешированном виде, при этом парольные политики вызовут ошибку, если включены проверки пароля.

Тип

POSIX шаблон

boolean

on/off

password_policy.deduplicate_ssl_no_ssl_fail_auth_attepmts#

Включение механизма дедупликации повторных попыток подключения psql.

Тип

POSIX шаблон

Значение по умолчанию

boolean

on/off

on

password_policy.allow_hashed_password#

Разрешить задание пароля в виде хеша.

Тип

POSIX шаблон

Значение по умолчанию

boolean

on/off

off

Авторизация и аутентификация#

Pangolin поддерживает несколько типов авторизации и аутентификации пользователей и сервисов.

В данном разделе более подробно рассмотрены варианты сквозной и двухфакторной авторизации.

Сквозная аутентификация Pangolin Pooler — Pangolin#

В Pangolin Pooler и Pangolin реализован механизм сквозной аутентификации. Программа Pangolin Pooler выступает в режиме проксирования данных аутентификации от клиента к Pangolin и обратно, аутентификация пользователя выполняется только на Pangolin.

Количество итераций обмена данными аутентификации для конкретного пользователя зависит от установленных в файле pg_hba.conf методов аутентификации. Обмен данными аутентификации между Pangolin Pooler и Pangolin выполняется по отдельным сетевым каналам. Количество сетевых каналов зависит от количества баз данных, к которым выполняется подключение пользователей.

Конфигурирование сквозной аутентификации в Pangolin Pooler#

Настроить сквозную аутентификацию в Pangolin Pooler можно с помощью конфигурационных параметров, описанных в данном разделе.

Параметры аутентификации:

  • auth_proxy (string) — параметр включает/выключает режим сквозной аутентификации:

    • off — режим сквозной аутентификации выключен, выполняется локальная аутентификация пользователя (значение по умолчанию);

    • on — режим сквозной аутентификации включен, выполняется аутентификация пользователя только на Pangolin;

  • auth_failure_threshold (integer) — параметр задает максимальное число НЕ аутентифицированного N раз подряд клиента с идентичными параметрами (тип соединения, адрес клиента, база данных и имя пользователя), при котором будет взведен таймер не активности аутентификации для этого клиента. Значение по умолчанию 0 (выключено);

  • auth_inactivity_period (integer) — параметр определяет период не активности аутентификации (в секундах). Это время, в течение которого ранее НЕ аутентифицированному более N раз подряд клиенту при подключении с идентичными параметрами (тип соединения, адрес клиента, база данных и имя пользователя), Pangolin Pooler откажет в обслуживании. Значение по умолчанию 0 (выключено);

  • auth_lost_size (integer) — параметр задает максимальное число кэшируемых записей о последних аутентификациях пользователей. Значение по умолчанию 10. Информацию о последних аутентификациях пользователей можно получить с помощью команды show last (см. подробнее в подразделе «Команды вывода информации» текущего раздела);

  • log_audit (integer) — включает/выключает аудит. Значение по умолчанию - 0 (выключено).

Примечание:

Увеличение значения auth_failure_threshold потенциально увеличит количество обработок отказов в подключении и соответствующих записей в логах, при обычных условиях эксплуатации это не должно приводить к отказу Pangolin Pooler.

Увеличение auth_inactivity_period позволяет избежать увеличения обработок отказов в подключении на указанное время.

Одной единицей подключения (клиентом) считается соединение с определенным набором (сочетанием) параметров: логин/пароль пользователя, имя БД для подключения, IP-адрес клиента, тип соединения. Клиент считается ранее пытавшимся подключиться, по этому же сочетанию, только без передачи пароля. Блокировка пользователя происходит по этим учетным данным подключения, то есть любое изменение данного сочетания будет считаться попыткой соединения нового пользователя.

Параметры подключений:

  • auth_port (integer) — номер порта, к которому нужно подключиться для выполнения аутентификации пользователей. Параметр раздела базы данных [databases];

  • auth_pool_size (integer) — параметр задает максимальное количество соединений для выполнения аутентификации пользователей. Значение по умолчанию 1. Параметр раздела базы данных [databases].

Примечание:

Общее количество соединений не должно превышать значения authentication_max_workers, раздел «Конфигурирование сквозной аутентификации в Pangolin».

Пример конфигурации (содержит параметры, связанные со сквозной аутентификацией):

[databases]
* =м host=<ip_address> port=5433 auth_port=5434

[pgbouncer]
 listen_addr = *
 listen_port = 6544
; включена сквозная аутентификация
 auth_proxy = on
; включен audit
 log_audit = 1
; выставлено время выполнения аутентификации
 client_login_timeout = 10
; выставлен порог, по превышению которого пользователь временно блокируется
 auth_failure_threshold = 3
; выставлен период неактивности аутентификации
 auth_inactivity_period = 30
; выставлен размер кешируемых записей о последних аутентификациях пользователей
 auth_last_size = 20

; пользователи, прописанные в userlist, будут выполнять аутентификацию, используя данный метод
 auth_type = scram-sha-256
; в файле userlist содержатся пользователи, выполняющие действия администратора или мониторинг
 auth_file = ./userlist.txt
 admin_users = pgbouncer
 stats_users = stat

Внимание!

Сквозная аутентификация не работает для пользователей, которые указаны в секции [users] конфигурационного файла Pangolin Pooler.

Раздел [users] содержит пары ключ=значение, где в качестве ключа принимается имя пользователя, а в качестве значения — переопределяемые для него параметры конфигурации (в формате строк подключения libpq):

  • pool_mode – задает режим пула для всех подключений данного пользователя;

  • max_user_connections – задает максимум подключений для пользователя.

Пользователь, для которого переопределен один или оба параметра:

  • должен быть указан в параметре stats_users или admin_users;

  • должен присутствовать в списке userlist.txt (параметр auth_file) в виде "имя_пользователя" "хеш_пароля_пользователя".

Пример конфигурации (содержит параметры, связанные с использованием секции [users] файла /etc/pangolin-pooler/pangolin-pooler.ini):

[pgbouncer]
; в файле userlist содержатся пользователи, выполняющие действия администратора или мониторинг
auth_file = ./userlist.txt
admin_users = pgbouncer
stats_users = user1
[users]
; раздел содержит имя пользователя и переопределяемые для него параметры конфигурации
user1 = pool_mode=session max_user_connections=1

Пользователю user1 при таких настройках будут применены персональные параметры pool_mode и max_user_connections, а аутентификация в базе данных будет выполняться только после аутентификации его в Pangolin Pooler.

Конфигурирование сквозной аутентификации в Pangolin#

Настроить сквозную аутентификацию в Pangolin можно с помощью конфигурационных параметров, описанных в данном разделе.

Параметры аутентификации:

  • authentication_proxy (integer) — параметр включает/выключает режим сквозной аутентификации:

    • 0 — режим сквозной аутентификации выключен, не позволяет выполнять аутентификацию пользователей конкретной БД в отдельном потоке (значение по умолчанию);

    • 1 — режим сквозной аутентификации включен, позволяет выполнять аутентификацию пользователей конкретной БД в отдельном потоке;

  • authentication_max_workers (integer) - параметр определяет максимальное число одновременных подключений для выполнения аутентификации пользователей. Значение по умолчанию 16. При значении, равном 0, сквозная аутентификация выполняться не будет.

Примечание:

Параметр authentication_max_workers можно задать только при запуске сервера.

  • auth_handshake_timeout (integer) — параметр определяет максимальное время, за которое должно произойти подтверждение аутентификации (в секундах). Значение по умолчанию 10 сек. Если потенциальный клиент не сможет выполнить подтверждение аутентификации (рукопожатие) за это время, сервер закроет соединение;

  • auth_activity_period (integer) — параметр определяет период активности аутентификации (в секундах). Значение по умолчанию 60 сек. Это время, в течение которого ранее аутентифицированный клиент при подключении с идентичными параметрами (тип соединения, адрес клиента, база данных и имя пользователя), выполнит аутентификацию по token.

    Значение передается на Pangolin Pooler и используется для проведения более быстрой аутентификации. Возможные значения:

    • -1 — не используется период активности аутентификации;

    • 0 — период активности аутентификации не имеет ограничений по времени;

    • > 0 — имеет ограничение по времени.

Примечание:

  • не рекомендуется выставлять значение auth_activity_period = 0, так как его нельзя сбросить в Pangolin Pooler без перезагрузки;

  • выставляемого значения должно хватить, чтобы запустить пул соединений между Pangolin Pooler и Pangolin.

Параметры подключений:

authentication_port (integer) — TCP-порт, открываемый сервером для выполнения аутентификации пользователей (по умолчанию порт — 5433).

Примечание:

Параметр authentication_port (integer) можно задать только при запуске сервера.

Пример конфигурации (содержит параметры связанные со сквозной аутентификацией):

port = 5433

authentication_port = 5434
authentication_timeout 60 # sec
auth_activity_period = 60 # sec

Команды вывода информации#

Для получения информации о статусе или результатах работы механизма сквозной аутентификации были добавлены следующие команды:

  • SHOW AUTHSERVERS — показывает информацию о соединениях с сервером аутентификации.

  • SHOW AUTHPOOLS — показывает информацию по пулам аутентификации.

    Примечание:

    Новый пул аутентификации создается для каждой базы данных.

  • SHOW AUTHUSERS — показывает информацию о пользователях.

  • SHOW LAST — показывает информацию об аутентификации последних N пользователей.

    Примечание:

    auth_last_size — по умолчанию команда показывает 10 последних пользователей.

    При превышении этого значения первые записи удаляются, а новые добавляются в конец. Ошибка аутентификации указана в логах Pangolin или Pangolin Pooler. В каком логе и в какое время - зависит от значений параметров place и connect_time\auth_time.

  • SHOW LOCKED_USERS — показывает информацию о заблокированных пользователях.

    Команда показывает временно заблокированных пользователей. Это пользователи с идентичными параметрами: тип соединения, адрес клиента, база данных и имя пользователя, которые не смогли аутентифицироваться N раз подряд (N определяет конфигурационный параметр auth_failure_threshold). Длительность блокировки пользователя определяется конфигурационным параметром auth_inactivity_period.

Подробное описание команд приведено в документе «Список PL/SQL функций продукта», раздел «Сквозная аутентификация».

В утилите psql имелся механизм запоминания ранее выполненных запросов. Этот механизм позволял просмотреть историю ранее выполненных команд и повторно вызвать ранее выполненные запросы.

История запросов хранилась в открытом виде в файле ~/.psql_history. При выполнении запросов, содержащих пароли это могло представлять угрозу безопасности, так как пароли хранились так же в незашифрованном виде.

В связи с новой функциональностью изменяется поведение утилиты psql по сравнению с имеющимся:

  • создание и чтение файла ~/.psql_history не производится;

  • влияние переменной окружения PSQL_HISTORY на работу утилиты psql отсутствует;

  • установка переменной HISTFILE в утилите psql не дает эффекта.

Реализованная функциональность не приводит к удалению или очищению ранее созданных файлов истории запросов. После обновления продукта рекомендуется (если необходимо) удалить ранее созданные файлы истории, выполнив команду:

rm -f ~/.psql_history

Двухфакторная аутентификация#

Двухфакторная аутентификация представляет собой технологию, обеспечивающую идентификацию пользователей при помощи запроса аутентификационных данных двух разных типов, что обеспечивает двухслойную, а значит, более эффективную защиту БД от несанкционированного проникновения.

Пользователь может подключаться к БД:

  • непосредственно (или напрямую) к Pangolin;

  • через Pangolin Pooler к Pangolin, используя сквозную аутентификацию;

  • через Pangolin Pooler к Pangolin, используя базовые механизмы аутентификации.

Сертификат безопасности клиента должен содержать поле CN, содержащее логин клиента и, опционально, поле SubjectAltName, содержащее один или несколько IP-адресов (возможен вариант указания подсети) и (или) DNS-имен клиента.

Для подключения непосредственно к Pangolin, в файле pg_hba.conf необходимо указать метод аутентификации: 2f-scram-sha-256, 2f-md5, 2f-password или 2f-ldap.

Для подключения через Pangolin Pooler к Pangolin, используя сквозную аутентификацию, необходимо:

  • в конфигурационных файлах Pangolin:

    • в файле pg_hba.conf необходимо указать метод аутентификации: 2f-scram-sha-256, 2f-md5, 2f-password или 2f-ldap;

    • в файле postgresql.conf указать:

      • authentication_proxy = on;

      • authentication_port = {AUTHPORT};

  • в конфигурационном файле Pangolin Pooler указать:

    • auth_port={AUTHPORT};

    • auth_proxy = on;

    • auth_type = scram-sha-256 или md5.

Для подключения через Pangolin Pooler к Pangolin, используя базовые механизмы аутентификации, необходимо в конфигурационном файле Pangolin Pooler указать:

  • в конфигурационных файлах Pangolin:

    • в файле pg_hba.conf необходимо указать метод аутентификации: 2f-scram-sha-256, 2f-md5, 2f-password или 2f-ldap;

    • в файле postgresql.conf указать authentication_proxy = off;

  • в конфигурационном файле Pangolin Pooler указать:

    • auth_proxy = off;

    • auth_type = 2f-scram-sha-256 (2f-md5, 2f-plain);

  • Аутентификация LDAP не поддерживается Pangolin Pooler, поэтому 2f-ldap так же не поддерживается.

Внимание!

Необходимо учитывать, что разрешенными по умолчанию механизмами двухфаторной аутентификации являются 2f-scram-sha-256 и 2f-ldap.

При необходимости использования методов аутентификации 2f-md5 и 2f-password, нужно добавить эти методы в параметр enabled_extra_auth_methods в конфигурационном файле postgresql.conf.

Например:

enabled_extra_auth_methods = '2f-md5,2f-password'

Настройка Pangolin для двухфакторной аутентификации#

Для выполнения двухфакторной аутентификации клиентов требуется:

  • в файле postgresql.conf - включить SSL режим и прописать сертификаты:

    ssl = on
    ssl_ca_file = './root.crt'
    ssl_cert_file = './server.crt'
    ssl_key_file = './server.key'
    
  • в файле pg_hba.conf указать:

    • тип сети - hostssl;

    • тип аутентификации: 2f-md5 или 2f-scram-sha-256;

    # TYPE  DATABASE        USER            ADDRESS                 METHOD
    hostssl    test           test1             127.0.0.1/32        2f-md5
    hostssl    test           test1             hostname            2f-scarm-sha-256
    

Настройка Pangolin Pooler для двухфакторной аутентификации#

Для выполнения двухфакторной аутентификации клиентов требуется в файле конфигурации pangolin-pooler.ini (имя файла конфигурации может быть другим) указать:

  • параметры подключения SSL/TLS;

  • тип аутентификации: 2f-scram-sha-256 или 2f-md5;

Ниже приведен пример конфигурации, когда защищенное соединение выполняется между клиентом и Pangolin Pooler, а между Pangolin Pooler и Pangolin используется обычное соединение.

[pgbouncer]
auth_type = 2f-scram-sha-256

; TLS settings
client_tls_protocols = all
client_tls_sslmode = verify-full
client_tls_ca_file = ./root.crt
client_tls_cert_file = ./server.crt
client_tls_key_file = ./server.key

Настройка сквозной двухфакторной аутентификации#

Все специальные настройки были описаны ранее — необходимо только включить сквозную аутентификацию на Pangolin Pooler с Pangolin.

В файле pangolin-pooler.ini:

[pgbouncer]
 auth_proxy = on
 auth_type = scram-sha-256

 client_tls_sslmode = verify-ca
 client_tls_key_file = ./server.key
 client_tls_cert_file = ./server.crt
 client_tls_ca_file = ./root.crt

 server_tls_sslmode = verify-full
 server_tls_key_file = ./pgbouncer.key
 server_tls_cert_file = ./pgbouncer.crt
 server_tls_ca_file = ./root.crt
 server_tls_ciphers = normal

[databases]
* = host=localhost port=5432 auth_port=5433  auth_port=5444 auth_pool_size=1

В файле postgresql.conf:

port = 5432
authentication_port = 5433
authentication_timeout = 60 # sec
auth_activity_period = 10 # sec

ssl = on
ssl_key_file = ./server.key
ssl_cert_file = ./server.crt
ssl_ca_file = ./root.crt

Управление протоколом LDAPS#

В Pangolin реализована возможность настроить шифрование запросов от сервера Postgres к AD (Active Directory). Для этого нужно настроить протокол LDAPS, использующий LDAP поверх SSL с использованием шифрования TLS. Далее приведены шаги для включения TLS соединения с LDAP.

  1. Набор имеющихся корневых AD сертификатов скопируйте на сервер, где будет производиться установка (в случае кластера - и на мастер, и на реплику). Примером директории может быть: etc/pki/ca-trust/source/anchors.

  2. Выполните команду sudo update-ca-trust для обновления списка доверенных сертификатов.

  3. В файле конфигурации etc/openldap/ldap.conf укажите путь к сертификатам в параметре TLS_CACERTDIR. Также добавьте набор шифров, используемых сервером AD: TLS_CIPHER_SUITE TLSv1.2:!NULL.

  4. Отредактируйте раздел hba_rules конфигурационного файла инсталлятора custom_file_template.yml. В нем пропишите параметры подключения к серверу:

    ldapserver="{{ ldap_server }}" ldapport=3268 ldapbasedn="" ldapprefix="cn=" ldapsuffix=" OU=NPA OU=PAM OU=ALL DC=MustBeFilled dc=ru ldap_tls=1
    
  5. Запустите установку/обновление Pangolin. Ниже приведен пример строки pg_hba.conf при включенном ldaptls:

    host all +all-sa-pam-group 0.0.0.0/0 ldap ldaptls=1 ldapserver=X.XX.ru ldapport=389 ldapprefix="cn=" ldapsuffix=", OU=NPA, OU=PAM, OU=ALL, OU=XX, DC=X, dc=ru
    

Генерация сертификатов#

Для включения SSL между компонентами кластера необходимо подготовить сертификаты и пароль для сервиса статистики haproxy.

Подготовка сертификатов не выполняется инсталлятором Pangolin. Ожидается, что на хосте уже есть сертификаты, которые будут переданы на вход инсталлятору. Инсталлятор сам разместит их в нужных директориях и выдаст права для служебных пользователей (например, etcd).

  • Серверный сертификат (необходимо создать для каждого хоста в кластере):

    1. Сгенерируйте ключ:

      openssl genrsa -out server.key 2048
      
    2. Создайте файл конфигурации для создания запроса на подпись сертификата vim server.conf:

      [req]
      req_extensions = v3_req
      distinguished_name = req_distinguished_name
      [req_distinguished_name]
      [ v3_req ]
      basicConstraints = CA:FALSE
      keyUsage = nonRepudiation, digitalSignature, keyEncipherment
      subjectAltName = @alt_names
      [ ssl_client ]
      extendedKeyUsage = clientAuth, serverAuth
      basicConstraints = CA:FALSE
      subjectKeyIdentifier=hash
      authorityKeyIdentifier=keyid,issuer
      subjectAltName = @alt_names
      [ v3_ca ]
      basicConstraints = CA:TRUE
      keyUsage = nonRepudiation, digitalSignature, keyEncipherment
      subjectAltName = @alt_names
      authorityKeyIdentifier=keyid:always,issuer
      [alt_names]
      DNS.1 = <host> ## hostname with domain
      IP.1 = <IP-адрес> ## host ip address
      
    3. Экспортируйте файл конфигурации:

      CONFIG=`echo $PWD/server.conf`
      
    4. Создайте запрос на подпись сертификата. В CN необходимо указать полный hostname:

      openssl req -new -key server.key -out server.csr -subj "/CN=<host>" -config ${CONFIG}
      
  • Клиентский сертификат:

    1. Сгенерируйте ключ:

      openssl genrsa -out postgres.key 2048
      
    2. Создайте файл конфигурации для создания запроса на подпись сертификата vim client.conf:

      [req]
      req_extensions = v3_req
      distinguished_name = req_distinguished_name
      [req_distinguished_name]
      [ v3_req ]
      basicConstraints = CA:FALSE
      keyUsage = nonRepudiation, digitalSignature, keyEncipherment
      [ ssl_client ]
      extendedKeyUsage = clientAuth
      basicConstraints = CA:FALSE
      subjectKeyIdentifier=hash
      authorityKeyIdentifier=keyid,issuer
      [ v3_ca ]
      basicConstraints = CA:TRUE
      keyUsage = nonRepudiation, digitalSignature, keyEncipherment
      authorityKeyIdentifier=keyid:always,issuer
      
    3. Экспортируйте файл конфигурации:

      CONFIG=`echo $PWD/client.conf`
      
    4. Создайте запрос на подпись сертификата. В CN необходимо указать имя клиента/компонента (postgres, patroni, patronietcd, pgbouncer, haproxy):

      openssl req -new -key postgres.key -out postgres.csr -subj "/CN=postgres" -config ${CONFIG}
      

    Примечание:

    При создании клиентских сертификатов, в поле subjectAltName можно указать IP-адрес или(и) DNS-имя машины (список машин), на которой(ых) будет использоваться сертификат. Также в этом поле можно указать адрес подсети.

Сгенерированные запросы на подпись сертификатов (файлы в формате *.csr) необходимо подписать удостоверяющем центре.

Полученные сертификаты необходимо перевести в формат PEM (например, командой openssl x509 -inform DER -outform PEM -in ./certificate.cer -out ./certificate.crt), расположить в одинаковых директориях на каждом хосте и выдать права - 600 для ключей и 644 для сертификатов, владелец — УЗ ОС postgres.

Наименование сертификатов, с которыми будет работать инсталлятор:

Назначение

Наименование сертификата

Наименование ключа

Сертификат сервера

server.crt

server.key

Сертификат пользователя postgres

postgres.crt

postgres.key

Сертификат пользователя Pangolin Pooler

pgbouncer.crt

pgbouncer.key

Сертификат пользователя patronietcd

patronietcd.crt

patronietcd.key

Сертификат пользователя patroni

patroni.crt

patroni.key

Сертификат HAproxy (сервер статистики)

haproxy.crt

Поскольку в PostgreSQL можно указать только один корневой сертификат, а в нашем случае их два (один — УЦ непосредственно выпустивший сертификат, второй — УЦ выпустивший сертификат для УЦ и имеющий признак CA), необходимо объединить сертификаты корневого и промежуточного УЦ в один:

cat root.crt intermediate.crt > rootCA.crt

Все корневые сертификаты необходимо скопировать в папку /etc/pki/ca-trust/source/anchors и выполнить команду обновления хранилища доверенных корневых сертификатов:

sudo update-ca-trust

Если используется компонент haproxy, то для него необходимо сертификат и приватный ключ объединить в один файл, например, командой:

cat server-key.pem server.pem >> haproxy.pem

Данный сертификат будет использоваться для подключения по HTTPS на сервер статистики.

Настройка компонентов#

Внимание!

В процессе работы инструмента развертывания производится валидация сертификатов на их соответствие требованиям указанным в разделе «Подготовка». После работы инструмента развертывания валидация сертификатов находится на стороне владельца стенда.

Произведите настройку компонентов на использование сертификатов (задача инструмента развертывания):

  1. В файле postgres.conf (для стендов в конфигурации standalone-postgresql-pgbouncer). В данном случае необходимо указать путь к подписанным сертификатам для сервера БД:

    ssl = 'on'
    ssl_cert_file = '/home/postgres/ca/server.crt'
    ssl_key_file = '/home/postgres/ca/server.key'
    ssl_ca_file = '/home/postgres/ca/rootCA.crt'
    ssl_crl_file = 'путь к файлу со списком отозванных сертификатов'
    
  2. В pangolin-pooler.ini добавьте секцию TLS-настроек. Между Pangolin Pooler и PostgreSQL настраивается обязательное SSL-соединение, между Pangolin Pooler и клиентом — по требованию клиента. В обоих случаях минимальная версия TLS 1.2 и соответствующие ему шифры (Cipher suites (TLS 1.2): ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384).

    #  TLS settings
    server_tls_protocols = secure
    server_tls_ciphers = secure
    server_tls_sslmode = verify-full
    server_tls_ca_file = /home/postgres/ca/rootCA.crt
    server_tls_cert_file = /home/postgres/ca/pgbouncer.crt
    server_tls_key_file = /home/postgres/ca/pgbouncer.key
    client_tls_protocols = secure
    client_tls_ciphers = secure
    client_tls_sslmode = prefer
    client_tls_ca_file = /home/postgres/ca/rootCA.crt
    client_tls_cert_file = /home/postgres/ca/server.crt
    client_tls_key_file = /home/postgres/ca/server.key
    
  3. В etcd.conf значения http переведите в https и добавьте секцию настроек TLS. Аутентификация в БД etcd происходит по паролю, так же необходимо указать сертификат пользователя.

    ETCD_NAME="tkles-core00133"
    ETCD_LISTEN_CLIENT_URLS="https://0.0.0.0:2379"
    ETCD_ADVERTISE_CLIENT_URLS="<hostname>:<порт>"
    ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
    ETCD_INITIAL_ADVERTISE_PEER_URLS="<hostname>:<порт>"
    ETCD_INITIAL_CLUSTER_TOKEN="test"
    ETCD_INITIAL_CLUSTER="tkles-core00133=<hostname>:<порт>,tkles-core00075=<hostname>:<порт>,tkles-core00077=<hostname>:<порт>"
    ETCD_INITIAL_CLUSTER_STATE="new"
    ETCD_DATA_DIR="/var/lib/etcd"
    ETCD_ELECTION_TIMEOUT="5000"
    ETCD_HEARTBEAT_INTERVAL="1000"
    ETCD_ENABLE_V2="false"
    # TLS settings
    ETCD_CIPHER_SUITES="TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
    ETCD_TRUSTED_CA_FILE="/home/postgres/ca/rootCA.crt"
    ETCD_CERT_FILE="/home/postgres/ca/server.crt"
    ETCD_KEY_FILE="/home/postgres/ca/server.key"
    ETCD_PEER_TRUSTED_CA_FILE="/home/postgres/ca/rootCA.crt"
    ETCD_PEER_CERT_FILE="/home/postgres/ca/server.crt"
    ETCD_PEER_KEY_FILE="/home/postgres/ca/server.key"
    ETCD_PEER_CLIENT_CERT_AUTH="true"
    ETCD_PEER_CRL_FILE="путь к файлу со списком отозванных сертификатов"
    
  4. В файле конфигурации pangolin-manager postgres.yml внесите изменения в секции restapi, etcd3, postgres, pg_hba.

    1. restapi добавить параметры verify_client, cafile, certfile, keyfile - пути до сертификатов. Параметр verify_client: optional - означает, что все запросы «управления» PUT, POST, PATCH, DELETE требуют аутентификации по сертификатам. Параметры allowlist: [] allowlist_include_members: true - означают, что доступ к запросам «управления» есть только у членов кластера и хостов, которые перечислены в allowlist. Запросы GET (только получение сведений о кластере) будут возвращаться без аутентификации.

      restapi:
          listen: 0.0.0.0:8008
          connect_address: <hostname>:<порт>
          allowlist: []
          allowlist_include_members: true
          verify_client: optional
          cafile: /home/postgres/ca/rootCA.crt
          certfile: /home/postgres/ca/server.crt
          keyfile: /home/postgres/ca/server.key
          authentication:
              username: patroniyml
              password: <пароль>
      
    2. В секции etcd добавьте параметры protocol, cacert, cert, key. Соединение с etcd будет осуществляться по протоколу HTTPS.

      etcd:
          hosts: <hostname>:<порт>,<hostname>:<порт>,<hostname>:<порт>
          protocol: https
          cacert: /home/postgres/ca/rootCA.crt
          cert: /home/postgres/ca/patronietcd.crt
          key: /home/postgres/ca/patronietcd.key
          username: patronietcd
          password: <пароль>
      
  5. В секции postgres в подразделе аутентификации пользователя patroni добавьте параметры sslmode, sslkey, sslcert, sslrootcert и в разделе parameters укажите путь к серверному сертификату. sslmode устанавливается в значение verify-ca из-за особенностей локального подключения.

    postgresql:
        listen: 0.0.0.0:5433
        bin_dir: /usr/pgsql-se-05/bin
        connect_address: <hostname>:<порт>
        data_dir: /pgdata/05/data/
        create_replica_methods:
            - basebackup
        basebackup:
            format: plain
            wal-method: fetch
        authentication:
            replication:
                username: patroni
                database: replication
                sslmode: verify-ca
                sslkey: /home/postgres/ca/patroni.key
                sslcert: /home/postgres/ca/patroni.crt
                sslrootcert: /home/postgres/ca/rootCA.crt
                sslcrl: "путь к файлу со списком отозванных сертификатов"
            superuser:
                username: patroni
                sslmode: verify-ca
                sslkey: /home/postgres/ca/patroni.key
                sslcert: /home/postgres/ca/patroni.crt
                sslrootcert: /home/postgres/ca/rootCA.crt
                sslcrl: "путь к файлу со списком отозванных сертификатов"
    
            ssl: 'on'
            ssl_cert_file: /home/postgres/ca/server.crt
            ssl_key_file: /home/postgres/ca/server.key
            ssl_ca_file: /home/postgres/ca/rootCA.crt
            ssl_crl_file: "путь к файлу со списком отозванных сертификатов"
    
  6. В секции pg_hba смените метод подключения для УЗ patroni с host на hostssl:

    hostssl all patroni <IP-адрес>/32 scram-sha-256
    hostssl all patroni <IP-адрес>/32 scram-sha-256
    hostssl replication patroni <IP-адрес>/32 scram-sha-256
    hostssl replication patroni <IP-адрес>/32 scram-sha-256
    
  7. haproxy.cfg - в haproxy активируется режим passthrough, добавляются проверки health-check по SSL (для Pangolin Manager на порту 8008) без верификации. Доступ к странице статистики осуществляется по протоколу HTTPS с методом аутентификации «логин-пароль». Доступ к серверу статистики, порт 7000, haproxy осуществляется на основе access list, где по-умолчанию ставится localhost, а дополнительные хосты можно прописать в файле настраиваемого конфигурационного файла.

    frontend fe_postgresql
        mode tcp
        option tcplog
        bind *: 5001
        default_backend be_postgres
    
    backend be_postgres
        mode tcp
        option tcplog
        option httpchk OPTIONS /master #
        http-check expect status 200
        default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions #
        server <hostname> <hostname>:<порт> verify none maxconn 100 check check-ssl port 8008
        server <hostname> <hostname>:<порт> verify none maxconn 100 check check-ssl port 8008
    
    listen stats
        mode http
        bind *:7000 ssl crt /home/postgres/ca/haproxy.crt
        stats enable
        stats uri /
        stats auth login:password
        acl whitelist src <IP-адрес>
        tcp-request connection reject if ! whitelist
    
  8. Если какой-либо сертификат был просрочен или отозван, необходимо выпустить новый, согласно инструкции описанной в разделе «Генерация сертификатов», и, в случае изменения наименования сертификата, произвести настройку компонента, где данный сертификат был задействован. В случае сохранения имени сертификата, необходимо перезапустить сервисы компонентов после замены файлов сертификатов.

Использование сертификатов PKCS#12 в кластере Pangolin#

В версиях Pangolin до 5.3.0 сертификаты и закрытые ключи, используемые для установки TLS/SSL соединений, хранились в кластере Pangolin в формате, не предусматривающем предъявление секрета для доступа к сертификату и/или закрытому ключу. В версии Pangolin 5.3.0 в целях повышения уровня информационной безопасности вводится авторизация для использования сертификатов и закрытых ключей на промышленных стендах.

Сертификаты и закрытые ключи, используемые в версии Pangolin 5.2.1, приведены в таблице ниже и используются для установления TLS-соединения между компонентами кластера Pangolin:

Клиентские сертификат и ключ Pangolin Pooler для подключения к серверу СУБД Pangolin

Назначение сертификатов и закрытых ключей

server.crt / server.key

Серверный сертификат СУБД Pangolin для установления клиентских подключений

Серверный сертификат Pangolin Manager. для установления клиентских подключений (REST API)

Клиентский и серверный сертификат для взаимодействия между экземплярами etcd

Серверный сертификат Pangolin Pooler для установления клиентских подключений

pgbouncer.crt / pgbouncer.key

Клиентский сертификат Pangolin Pooler для подключения к серверу СУБД Pangolin

patroni.crt / patroni.key

Клиентский сертификат Pangolin Manager для подключения к серверу СУБД Pangolin

patronietcd.crt / patronietcd.key

Клиентский сертификат Pangolin Manager для подключения к серверу etcd

client.crt / client.key

Клиентский сертификат пользователя postgres

root.crt

Корневой сертификат УЦ

С версии Pangolin 5.3.0 данные сертификаты и закрытые ключи, за исключением root.crt и patronietcd.crt/patronietcd.key, хранятся в файловой системе в зашифрованных контейнерах PKCS#12, а парольные фразы для их расшифровки - в зашифрованном виде. Ключ для зашифровывания/расшифровывания парольных фраз генерируется на основе параметров сервера, поэтому файлы с парольными фразами не переносимы между узлами кластера Pangolin.

Примечание:

Следующая ключевая информация хранится в файловой системе в PEM-формате:

  • Сертификаты и закрытые ключи etcd (etcd.crt/etcd.key, patronietcd.crt/patronietcd.key), так как этот компонент не поддерживается командой разработки Pangolin.

  • Корневой сертификат, которым подписаны сертификаты etcd (может не совпадать с сертификатом, подписавшим сертификаты компонентов PostgreSQL, Pangolin Pooler и Pangolin Manager.).

  • Корневой сертификат root.crt, которым подписаны сертификаты компонентов PostgreSQL, Pangolin Pooler и Pangolin Manager…

Для компонентов кластера введены настроечные параметры для установки пути до конфигурационного файла, включающего путь к контейнеру PKCS#12 и парольную фразу в зашифрованном виде:

  • в конфигурационном файле pangolin-manager postgresql.yml параметр pkcs12_config_path в секциях:

    • restapi:

      • pkcs12_config_path: example.p12.cfg;

    • postgresql:authentication:replication/superuser/rewind:

      • pkcs12_config_path: example.p12.cfg;

    • postgresql:parameters:

      • serverssl.pkcs12_config_path: example.p12.cfg;

  • в конфигурационном файле СУБД Pangolin postgresql.conf параметр serverssl.pkcs12_config_path;

  • в конфигурационном файле Pangolin Pooler pangolin-pooler.ini параметры client_tls_pkcs12_config_path и server_tls_pkcs12_config_path;

  • в строке подключения psql:

    • pkcs12_config_path (переменная окружения PKCS12_CONFIG_PATH);

    • pkcs12_passphrase (переменная окружения PKCS12_PASSPHRASE) - используется для предоставления парольной фразы без ручного ввода в случае, если в файле .p12.cfg отсутствует поле passphrase. Парольная фраза может быть как в открытом, так и в зашифрованном виде. Парольная фраза зашифровывается утилитой pg_auth_password.

Формат конфигурационного файла .p12.cfg:

{
"pkcs12": "",      // Путь к контейнеру PKCS#12
"passphrase": ""   // Парольная фраза, зашифрованная ключом на параметрах сервера, либо в открытом виде
}

Для валидации сертификатов компонентов, выполняющих подключение, по умолчанию используется полная цепочка сертификатов в контейнере PKCS#12, если в конфигурационных файлах не прописаны прежние параметры для установки цепочки доверенных сертификатов:

  • в конфигурационном файле Pangolin Manager postgresql.yml в секциях:

    • restapi:

      • cafile: /path/to/CAfile.pem;

      • capath: /path/to/CAdir (параметр введен в версии 5.3.0);

    • postgresql:authentication:replication/superuser/rewind:

      • sslrootcert: /path/to/CAfile.pem;

      • sslrootpath: /path/to/CAdir (параметр введен в версии 5.3.0);

    • postgresql:parameters:

      • ssl_ca_file: /path/to/CAfile.pem;

      • ssl_ca_path: /path/to/CAdir (параметр введен в версии 5.3.0);

  • в конфигурационном файле СУБД Pangolin postgresql.conf:

    • ssl_ca_file = '/path/to/CAfile.pem';

    • ssl_ca_path = '/path/to/CAdir' (параметр введен в версии 5.3.0);

  • в конфигурационном файле Pangolin Pooler pangolin-pooler.ini:

    • client_tls_ca_file = /path/to/CAfile.pem;

    • server_tls_ca_file = /path/to/CAfile.pem;

    • client_tls_ca_path = /path/to/CAdir (параметр введен в версии 5.3.0);

    • server_tls_ca_path = /path/to/CAdir (параметр введен в версии 5.3.0);

  • в строке подключения psql:

    • sslrootcert = /path/to/CAfile.pem (переменная окружения PGSSLROOTCERT);

    • sslrootpath = /path/to/CAdir (переменная окружения PGSSLROOTPATH (параметр введен в версии 5.3.0)).

Если один из этих параметров указан, то он будет использоваться для инициализации цепочки доверенных сертификатов для проверки сертификатов: со стороны сервера - клиентского сертификата, со стороны клиента - серверного сертификата. В дополнение к приведенным вариантам поиска доверенных сертификатов добавлен поиск среди доверенных сертификатов операционной системы. Настроечный параметр для этого не требуется.

Примечание:

Клиентские компоненты кластера (psql) используют полную цепочку сертификатов в контейнере PKCS#12 для валидации сертификатов, если в строке подключения параметр sslmode установлен в verify-ca или verify-full.

Порядок поиска доверенных сертификатов:

  • если не используются параметры, указывающие на файл, либо директорию с сертификатами: сначала в полной цепочке сертификатов из контейнера PKCS#12, затем в в директории ОС, указанной по умолчанию;

  • если используются параметры, указывающие на файл и/или директорию с сертификатами: сначала в файле, содержащем один или несколько доверенных сертификатов, затем в директории, если установлена, и, если в них не удалось найти нужный сертификат, то - в директории ОС, указанной по умолчанию.

Возможность конфигурирования сертификатов через PEM-файлы сохранена.

Реализация интерфейса получения контейнера PKCS#12 и парольной фразы к нему выполнена в виде плагинов (подключаемых модулей). В директории установки Pangolin созданы символические ссылки на плагины:

/usr/pangolin-5.3.0/lib/libpkcs12_exporter_plugin_link.so -> plugins/libpkcs12_exporter_plugin.so
/usr/pangolin-5.3.0/lib/libpkcs12_passphrase_plugin_link.so -> plugins/libpkcs12_passphrase_plugin.so

Для контроля сроков действия сертификатов и проверки подписи локальным корневым сертификатом в контейнерах PKCS#12 предоставляется утилита pkcs12_cert_info. По умолчанию поиск корневого сертификата также ведется в системных директориях по умолчанию. Утилита принимает на вход аргументы: путь к конфигурационному файлу со стратегией получения контейнера PCKS#12 и парольной фразы --pkcs12_config_path (-p), параметр включения проверки подписи --verify (-v), опционально путь к корневому сертификату --CAfile (-f), опционально путь к директории с корневым сертификатом --CApath (-d), опциональный параметр отключения поиска в директориях по умолчанию --no-CApath (-n).

Справка по использованию утилиты:

$ pkcs12_cert_info -h
Usage:
pkcs12_cert_info <option>...
Options:
--help                   [-h]     This help
--pkcs12_config_path     [-p]     Path to config file with info how to get PKCS#12 file
--verify                 [-v]     Check that PKCS#12 certificate trusted by anchor
--CAfile                 [-f]     Path to root/intermediate certificate file
--CApath                 [-d]     Path to root/intermediate certificate directory
--no-CApath              [-n]     Do not use the default directory of trusted certificates.

Pangolin product version information:
--product_version        prints product name and version
--product_build_info     prints product build number, date and hash
--product_component_hash prints component hash string

Вывод утилиты включает статус наличия закрытого ключа в контейнере, сроки действия сертификата и атрибуты, идентифицирующие сертификат (имя издателя и общее имя сертификата), а также сроки действия цепочки доверенных сертификатов. При введенном параметре проверки подписи выводится результат проверки, а также путь до использованного корневого сертификата.

Пример запуска утилиты:

$ pkcs12_cert_info -p /pg_ssl/server.p12.cfg
Certificate:
Issuer: CN=Pangolin_intermediate_CA
Validity
Not Before: Nov  8 10:52:13 2022 GMT
Not After : Nov  5 10:52:13 2032 GMT
Subject: CN=srv-0-154

Private key exists

Certificate chain:
Certificate #1:
Issuer: CN=Pangolin_CA
Validity
Not Before: Nov  8 10:52:13 2022 GMT
Not After : Nov  5 10:52:13 2032 GMT
Subject: CN=Pangolin_intermediate_CA
Certificate #2:
Issuer: CN=Pangolin_CA
Validity
Not Before: Nov  8 10:52:12 2022 GMT
Not After : Nov  5 10:52:12 2032 GMT
Subject: CN=Pangolin_CA

Использование сертификатов в локально хранящихся контейнерах PKCS#12 настраивается путем установки следующих параметров в конфигурационных файлах компонентов кластера:

  • в конфигурационном файле Pangolin Manager postgresql.yml параметр pkcs12_config_path в секциях:

    • restapi;

      • pkcs12_config_path: example.p12.cfg;

    • postgresql:authentication:replication/superuser/rewind;

      • pkcs12_config_path: example.p12.cfg;

    • postgresql:parameters;

      • serverssl.pkcs12_config_path: example.p12.cfg;

  • в конфигурационном файле СУБД Pangolin postgresql.conf параметр serverssl.pkcs12_config_path;

  • в конфигурационном файле Pangolin Pooler pangolin-pooler.ini параметры client_tls_pkcs12_config_path и server_tls_pkcs12_config_path.

Изменение данных параметров не требует перезапуска компонентов кластера, достаточно выполнить перечитывание конфигурационных файлов.

Если для подключения к СУБД Pangolin требуется предоставить сертификат, и кластер настроен с использованием контейнеров PKCS#12, хранящихся в файловой системе, то в строке подключения psql необходимо указать параметр pkcs12_config_path с путем до конфигурационного файла .p12.cfg, содержащего путь к контейнеру PKCS#12 и парольную фразу в зашифрованном виде.

Примеры запуска утилиты psql:

# В файле /pg_ssl/client.p12.cfg установлена парольная фраза.
$ psql "host=$(hostname -f) port=5433 dbname=postgres user=postgres sslmode=verify-full pkcs12_config_path=/pg_ssl/client.p12.cfg"

# В файле /pg_ssl/client.p12.cfg установлена парольная фраза. Путь к /pg_ssl/client.p12.cfg указан через переменную окружения.
$ PKCS12_CONFIG_PATH=/pg_ssl/client.p12.cfg psql "host=$(hostname -f) port=5433 dbname=postgres user=postgres sslmode=verify-full"

# В файле /pg_ssl/client.p12.cfg парольная фраза не установлена. Парольная фраза передается в строке подключения в зашифрованном виде.
$ psql "host=$(hostname -f) port=5433 dbname=postgres user=postgres sslmode=verify-full pkcs12_config_path=/pg_ssl/client.p12.cfg pkcs12_passphrase=$enc$+tsiUlhEuNw4ASyvN6ta0A==$sys$mKb2BejR/MLUBzZQ2PaFs+zXGHDRljMWqX46w0CMmDWtjPDzwbxwNSfDAmVTT3Wu"

# В файле /pg_ssl/client.p12.cfg парольная фраза не установлена. Парольная фраза передается через переменную окружения в зашифрованном виде.
$ PKCS12_PASSPHRASE='$enc$+tsiUlhEuNw4ASyvN6ta0A==$sys$mKb2BejR/MLUBzZQ2PaFs+zXGHDRljMWqX46w0CMmDWtjPDzwbxwNSfDAmVTT3Wu' psql "host=$(hostname -f) port=5433 dbname=postgres user=postgres sslmode=verify-full pkcs12_config_path=/pg_ssl/client.p12.cfg"

# В файле /pg_ssl/client.p12.cfg парольная фраза не установлена. Требуется ручной ввод парольной фразы.
$ psql "host=$(hostname -f) port=5433 dbname=postgres user=postgres sslmode=verify-full pkcs12_config_path=/pg_ssl/client.p12.cfg"
Enter passphrase for PKCS#12 file:
***

Внимание!

В режиме защищенного конфигурирования (secure_config = on) управление параметром СУБД Pangolin serverssl.pkcs12_config_path выполняется на стороне хранилища секретов.

Если для валидации сертификатов не подходит полная цепочка сертификатов в контейнере PKCS#12, предоставляется возможность использования существующих параметров для установки путей к файлам с полными цепочками доверенных сертификатов или введенных в текущей работе новых параметров для установки директории с доверенными сертификатами:

  • в конфигурационном файле Pangolin Manager. postgresql.yml в секциях:

    • restapi;

      • cafile: /path/to/CAfile.pem;

      • capath: /path/to/CAdir;

    • postgresql:authentication:replication/superuser/rewind;

      • sslrootcert: /path/to/CAfile.pem;

      • sslrootpath: /path/to/CAdir;

    • postgresql:parameters;

      • ssl_ca_file: /path/to/CAfile.pem;

      • ssl_ca_path: /path/to/CAdir;

  • в конфигурационном файле СУБД Pangolin postgresql.conf:

    • ssl_ca_file = '/path/to/CAfile.pem';

    • ssl_ca_path = '/path/to/CAdir';

  • в конфигурационном файле Pangolin Pooler pangolin-pooler.ini:

    • client_tls_ca_file = /path/to/CAfile.pem;

    • server_tls_ca_file = /path/to/CAfile.pem;

    • client_tls_ca_path = /path/to/CAdir;

    • server_tls_ca_path = /path/to/CAdir;

  • в строке подключения psql:

    • sslrootcert = /path/to/CAfile.pem (переменная окружения PGSSLROOTCERT);

    • sslrootpath = /path/to/CAdir (переменная окружения PGSSLROOTPATH).

Поиск доверенных сертификатов также выполняется среди доверенных сертификатов операционной системы. Настроечный параметр для этого не требуется.

Пример подготовки директории с доверенными сертификатами:

# Добавление корневого сертификата в директорию с доверенными сертификатами
cp /path/to/panglolin.crt /pg_ssl/root_dir
c_rehash /pg_ssl/root_dir

Пример управления доверенными сертификатами операционной системы CentOS 7.9:

# Добавление корневого сертификата с именем Pangolin_CA в хранилище доверенных сертификатов ОС
sudo cp /path/to/panglolin.crt /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust extract
trust list|grep Pangolin_CA
# Удаление корневого сертификата с именем Pangolin_CA из хранилища доверенных сертификатов ОС
sudo rm /etc/pki/ca-trust/source/anchors/panglolin.crt
sudo update-ca-trust extract
trust list|grep Pangolin_CA

Для контроля сроков действия сертификатов в контейнерах PKCS#12 предоставляется утилита pkcs12_cert_info. Утилита принимает на вход один аргумент: путь к конфигурационному файлу со стратегией получения контейнера PCKS#12 и парольной фразы. Вывод утилиты включает статус наличия закрытого ключа в контейнере, сроки действия сертификата и атрибуты, идентифицирующие сертификат (имя издателя и общее имя сертификата), а также сроки действия полной цепочки сертификатов.

В пользовательском конфигурационном файле инсталлятора введены следующие параметры:

  • Контейнер PKCS#12, помимо сертификата и закрытого ключа, может содержать полную цепочку сертификатов, включая корневой, которыми подписан сертификат. Для упрощения настройки доверенных SSL/TLS сертификатов в кластере предоставляется возможность использовать цепочку сертификатов из контейнера в качестве доверенных, установив параметр pkcs12_use_ca_chain_from_container в true.

    # Флаг определяет, использовать ли полную цепочку сертификатов в контейнере PKCS#12 в качестве доверенной.
    # Если флаг true, то использовать полную цепочку доверенных сертификатов в контейнере, если есть, в качестве доверенной, иначе - false.
    pkcs12_use_ca_chain_from_container: true
    
  • Если вариант с использованием полной цепочки сертификатов из контейнера PKCS#12 не подходит для настройки доверенных SSL/TLS сертификатов, предоставляется возможность установки доверенных сертификатов через следующие параметры:

    pg_certs_pwd:
    root_ca_file: "{{ '' | default('/pg_ssl/root.crt', true) }}" # Использовать PEM файл, который может содержать один или несколько доверенных сертификатов
    root_ca_path: "{{ '' | default('/pg_ssl/root_dir', true) }}" # Использовать подготовленную директорию с доверенными сертификатами
    
  • Параметры для поддержки использования сертификатов и закрытых ключей из контейнеров PKCS#12, расположенных в файловой системе:

    # Активация получения контейнера PKCS#12 и парольной фразы к нему из файловой системы.
    # Если флаг true, то устанавливаются плагины libpkcs12_passphrase_plugin.so и libpkcs12_exporter_plugin.so.
    # Если флаг false, то используется прежний подход для получения ключевой информации: из файлов в PEM формате. Плагин не устанавливается.
    pkcs12_plugin_enable: true
    
    pg_certs_pwd:
    # Установка параметра p12_path обязательна при активации флага pkcs12_plugin_enable.
    server_p12:
    p12_path: "{{ '' | default('/home/postgres/ssl/server.p12', true) }}" # Путь в файловой системе к контейнеру PKCS#12 с серверной ключевой парой и цепочкой доверенных сертификатов.
    p12_pass: "{{ '' | default('', true) }}" # Парольная фраза для доступа к контейнеру PKCS#12 (server.p12), зашифрованная средствами Ansible Vault (в ходе установки парольная фраза расшифровывается и сохраняется в файл по пути p12_config_path (см. ниже) в зашифрованном виде на ключе, сгенерированном на параметрах сервера). Параметр обязателен в случае установки параметра p12_path.
    p12_config_path: "{{ '' | default('/home/postgres/ssl/server.p12.cfg', true) }}" # Путь к файлу в JSON-формате, содержащему параметр ("passphrase") для получения парольной фразы для доступа к контейнеру PKCS#12, зашифрованную на ключе, сгенерированном на параметрах сервера, и параметр ("pkcs12") для получения контейнера PKCS#12. Параметр обязателен при установке флага pkcs12_plugin_enable в true.
    
    postgres_p12:
    p12_path: "{{ '' | default('/home/postgres/ssl/client.p12', true) }}" # Путь в файловой системе к контейнеру PKCS#12 с клиентской ключевой парой пользователя postgres и цепочкой доверенных сертификатов
    p12_pass: "{{ '' | default('', true) }}"
    p12_config_path: "{{ '' | default('/home/postgres/ssl/client.p12.cfg', true) }}"
    
    pgbouncer_p12:
    p12_secman_integration: true
    p12_path: "{{ '' | default('/home/postgres/ssl/pgbouncer.p12', true) }}" # Путь в файловой системе к контейнеру PKCS#12 с клиентской ключевой парой Pangolin Pooler и цепочкой доверенных сертификатов для подключения к СУБД Pangolin
    p12_pass: "{{ '' | default('', true) }}"
    p12_config_path: "{{ '' | default('/home/postgres/ssl/pgbouncer.p12.cfg', true) }}"
    
    patroni_p12:
    p12_path: "{{ '' | default('/home/postgres/ssl/patroni.p12', true) }}" # Путь в файловой системе к контейнеру PKCS#12 с клиентской ключевой парой и цепочкой доверенных сертификатов для подключения Pangolin Manager к СУБД Pangolin
    p12_pass: "{{ '' | default('', true) }}"
    p12_config_path: "{{ '' | default('/home/postgres/ssl/patroni.p12.cfg', true) }}"
    
    etcd_cert: "{{ '' | default('/home/postgres/ssl/etcd.crt', true) }}" # Путь к сертификату для взаимодействия экземпляров ETCD. Может быть подписан сертификатом, отличным от сертификата, подписавшего сертификаты компонентов PostgreSQL, Pangolin Pooler, Pangolin Manager. Тогда потребуется указать путь к корневому сертификату в параметре etcd_root_ca.
    etcd_key: "{{ '' | default('/home/postgres/ssl/etcd.key', true) }}" # Путь к приватному ключу для взаимодействия экземпляров ETCD
    etcd_root_ca: "{{ '' | default('/home/postgres/ssl/root_etcd.crt', true) }}" # Корневой сертификат для проверки действительности сертификатов ETCD
    

    Примечания к ключам словаря pg_certs_pwd:

    • p12_path - путь в файловой системе к контейнеру PKCS#12 с ключевой парой и цепочкой доверенных сертификатов.

    • p12_pass - парольная фраза для доступа к контейнеру PKCS#12, зашифрованная средствами Ansible Vault. В ходе установки парольная фраза расшифровывается и сохраняется в файл по пути p12_config_path в зашифрованном виде на ключе, сгенерированном на параметрах сервера.

    • p12_config_path - путь к файлу в JSON-формате .p12.cfg, содержащему поле "passphrase" с парольной фразой для доступа к контейнеру PKCS#12 и поле pkcs12 с путем до контейнера PKCS#12. Файл формируется инсталлятором: в поле pkcs12 прописывается путь к контейнеру PKCS#12 (из параметра p12_path), в поле passphrase помещается парольная фраза перешифрованная ключом, сгенерированном на основе параметров сервера (из параметра p12_pass). Формат файла:

      {
      "pkcs12": "",      // Путь к контейнеру PKCS#12
      "passphrase": ""   // Парольная фраза, зашифрованная ключом на параметрах сервера, либо в открытом виде
      }
      
    • etcd_root_ca - путь к корневому сертификату ETCD. Параметр является обязательным при настройке SSL между узлами etcd.

  • Параметр для выбора способа хранения парольной фразы в конфигурационном файле .p12.cfg, путь к которому указывается в параметре p12_config_path: в зашифрованном или в открытом виде.

    # Флаг, определяющий способ хранения парольной фразы к контейнеру PKCS#12.
    # Если флаг true, то парольная фраза зашифровывается ключом, генерируемым на основе параметров сервера, иначе - парольная фраза в открытом виде.
    pkcs12_encrypt_passphrase: true
    

Отключение функциональности#

Отключение функциональности выполняется переконфигурированием кластера на использование сертификатов в PEM-формате без перезапуска кластера. Достаточно выполнить перечитывание конфигурационных файлов.

Управление сертификатами для Pangolin с Secret Management System#

В целях повышения уровня информационной безопасности новая функциональность обеспечивает хранение и использование контейнеров PKCS#12 и парольных фраз к ним в хранилище секретов и сертификатов Secret Management System (SecMan) и их ротацию на промышленных стендах.

В Pangolin появляется несколько новых конфигурационных файлов. Эти файлы используются следующими компонентами кластера: СУБД Pangolin, Pangolin Pooler и Pangolin Manager. Каждый компонент использует свой конфигурационный файл. Данные, указанные в файлах, используются для генерации контейнеров PKCS#12, содержащих сертификат и частный ключ. Контейнер создается и хранится в SecMan и возвращается компоненту кластера по запросу.

Описание файла:

{
"pkcs12": {
"name": "",                // Имя роли
"common_name": "",         // CN для сертификата
"email": "",               // Почтовый адрес владельца сертификата
"alt_names": "",           // Альтернативные имена субъектов в списке, разделенном запятыми. Это могут быть имена хостов или адреса электронной почты
"ip_sans": "",             // Альтернативные имена субъекта IP в списке с разделителями-запятыми. Действителен только в том случае, если роль разрешает IP SAN (по умолчанию)
"other_sans": "",          // Настраиваемые SAN со строкой OID/UTF8
"exclude_cn_from_sans": "" // Параметр, включающий/выключающий возможность исключить common_name из DNS или электронной почты SAN
}
}

Примеры файлов для компонентов кластера:

  • Pangolin:

    {
      "pkcs12": {
        "name": "server",
        "common_name": "server",
        "email": "test@test.ru",
        "alt_names": "",
        "ip_sans": "",
        "other_sans": "",
        "exclude_cn_from_sans": ""
      }
    }
    
  • Pangolin Pooler:

    {
      "pkcs12": {
        "name": "pgbouncer",
        "common_name": "pgbouncer",
        "email": "test@test.ru",
        "alt_names": "",
        "ip_sans": "",
        "other_sans": "",
        "exclude_cn_from_sans": ""
      }
    }
    
  • Pangolin Manager:

    {
      "pkcs12": {
        "name": "patroni",
        "common_name": "patroni",
        "email": "test@test.ru",
        "alt_names": "",
        "ip_sans": "",
        "other_sans": "",
        "exclude_cn_from_sans": ""
      }
    }
    

Для того, чтобы использовать новые конфигурационные файлы, пути к ним нужно прописать в основных конфигурационных файлах:

  • В случае кластера. В файле конфигурации Pangolin Manager postgresql.yml в параметре pkcs12_config_path в секциях restapi, postgresql/authentication/replication, postgresql/authentication/superuser и postgresql/authentication/rewind, а также в параметре pkcs12_config_path в секции postgresql/parameters:

    restapi:
      pkcs12_config_path: "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    postgresql:
      authentication:
        replication:
          pkcs12_config_path: "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    postgresql:
      authentication:
        superuser:
          pkcs12_config_path: "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    postgresql:
      authentication:
        rewind:
          pkcs12_config_path: "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    postgresql:
      parameters:
        serverssl.pkcs12_config_path: "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    
  • В случае standalone конфигурации. В файле конфигурации СУБД Pangolin postgresql.conf (для случая конфигурации standalone) в параметре serverssl.pkcs12_config_path:

    serverssl.pkcs12_config_path = "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    

    Внимание!

    При включенной защите параметров конфигурационный параметр serverssl.pkcs12_config_path должен быть под защитой, а его значение должно устанавливаться только через SecMan.

  • В файле конфигурации Pangolin Pooler pangolin-pooler.ini в параметре client_tls_pkcs12_config_path и server_tls_pkcs12_config_path:

    client_tls_pkcs12_config_path = "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    server_tls_pkcs12_config_path = "" # Путь к конфигурационному файлу в JSON-формате, содержащему данные для генерации сертификата
    

Ротация сертификатов, получаемых из SecMan#

Ротация сертификатов, используемых компонентами кластера, осуществляется агентом, который:

  • контролирует срок действия сертификатов, полученных из SecMan;

  • обновляет сертификаты на SecMan при приближении конца их срока действия;

  • контролирует внешнее изменение сертификатов, обновление на SecMan, а также отзыв сертификата;

  • запускает процесс обновления сертификатов на кластере.

Агент pg_certs_rotate_agent#

Агент представляет собой исполняемый файл pg_certs_rotate_agent, который настраивается для работы с конкретным хранилищем сертификатов через систему плагинов. Расположен в директории /opt/pangolin-common/bin/ и запускается отдельной службой pg_certs_rotate_agent.service до запуска служб postgresql.service, pangolin-pooler.service и pangolin-manager.service.

Период проверки сертификатов и их обновления настраивается в конфигурационном файле агента. Первая проверка происходит на его старте. Следующий запуск агента может произойти до окончания заданного промежутка времени, если интервал между датой истечения и датой выпуска одного из сертификатов достигает 80% внутри текущего периода. Таким образом, агент будет запущен в этот момент времени, и следующий период будет отсчитываться уже от этой точки. Если в процессе работы агента произошла ошибка, то его следующий запуск произойдет через заданный в конфигурации период ожидания.

На схеме ниже приведены этапы работы агента:

Запуск агента

Если обновление сертификата на SecMan произошло без участия агента, то кластер до следующего запуска агента будет работать со старым сертификатом (в том числе, если сертификат отозван):

Агент со старым сертификатом

Для взаимодействия с SecMan применяется плагин remote_secman_pki_plugin, который использует протокол http/https, а также параметры подключения кластера. Параметры хранятся в зашифрованном хранилище /etc/postgres/enc_connection_settings_cert.cfg. Для расшифровки файла агент использует плагин шифрования.

Процесс инсталляции агента#

Настройка работы агента происходит на этапе установки кластера Pangolin:

Установка агента

Для включения агента ротации сертификатов в конфигурационном файле инсталлятора custom_file_template.yml (см. раздел «Конфигурационные файлы для настройки СУБД Pangolin») требуется добавить параметр enable в yaml-словарь pg_certs_rotate_agent. Все параметры агента сохраняются в конфигурационном файле, который тот использует при инициализации:

  • путь к конфигурационному файлу агента задается при помощи параметра agent_config, который находится в pg_certs_rotate_agent. По умолчанию используется конфигурационный файл /etc/postgres/pg_certs_rotate_agent.yaml;

  • путь к директории для лог-файлов задается с помощью параметра log_directory в yaml-словаре pg_certs_rotate_agent. По умолчанию используется путь /var/log/pg_certs_rotate_agent;

  • имя лог-файла задается параметром log_filename в yaml-словаре pg_certs_rotate_agent. По умолчанию используется имя pg_certs_rotate_agent;

  • уровень логирования задается параметром log_level в yaml-словаре pg_certs_rotate_agent. Возможны уровни: debug | info | warning | error | fatal. По умолчанию используется уровень info;

  • методы записи лога задаются параметром log_destination в yaml-словаре pg_certs_rotate_agent. Возможные методы: console, file при любой комбинации методов. По умолчанию используется метод console;

  • включить/отключить функцию ротации сертификатов можно с помощью параметра enable_update в словаре pg_certs_rotate_agent:certs. По умолчанию функция включена;

  • период проверки сертификатов настраивается при помощи параметра poll_period_in_min, который находится в словаре pg_certs_rotate_agent:certs и задается в минутах. По умолчанию период работы будет равен 60 минутам;

  • время ожидания повторного запуска агента в случае ошибки устанавливается в параметре retry_interval_in_sec, который находится в словаре pg_certs_rotate_agent:certs и задается в секундах. По умолчанию таймаут будет равен 30 секундам;

  • количество повторных проверок в случае ошибки задается параметром retry_attempts_num, который находится в словаре pg_certs_rotate_agent:certs. По умолчанию настроена одна попытка;

  • список сертификатов, за сроком действия которых «следит» агент, определяются группами locations, которые находятся в словаре pg_certs_rotate_agent:certs:watch. В каждой группе задается:

    • в словаре paths множество конфигурационных файлов сертификатов *.p12.cfg;

    • в словаре on_update множество зависимых от сертификатов команд, необходимых для обновления компонентов кластера.

      Внимание!

      В Pangolin 5.5.0 были реализованы только следующие команды:

      sudo systemctl reload postgresql
      sudo systemctl reload pangolin-manager
      sudo systemctl reload pangolin-pooler
      

Формат конфигурационного файла инсталлятора для агента ротации:

    pg_certs_rotate_agent:
        # Флаг определяет, запускается ли агент ротации.
        # Если флаг true, то агент будет запущен, иначе - false.
        enable: true
        # Путь к конфигурационному файлу агента в YAML-формате
        agent_config: "{{ '' | default('/etc/postgres/pg_certs_rotate_agent.yaml', true) }}"
        # Путь к директории для лог-файлов
        log_directory: "{{ '' | default('/var/log/pg_certs_rotate_agent', true) }}"
        # Имя лог-файла
        log_filename: "{{ '' | default('pg_certs_rotate_agent', true) }}"
        # Уровень логирования
        log_level: "{{ '' | default('info', true) }}"
        # Методы записи лога
        log_destination:  "{{ '' | default('console', true) }}"

        certs:
            # Включить/выключить автоматическое обновление сертификатов
            enable_update: "{{ '' | default(true, true) }}"
            # Период проверки валидности сертификатов [мин]
            poll_period_in_min: "{{ '' | default(60, true) }}"
            # Таймаут на повторный запуск в случае ошибки [c]
            retry_interval_in_sec: "{{ '' | default(30, true) }}"
            # Количество попыток после неудачи
            retry_attempts_num: "{{ '' | default(1, true) }}"

            # Множество обновляемых сертификатов
            watch:
                - locations:
                    # Множество файлов конфигураций сертификатов
                    paths:
                        - path/to/cert/configuration/1_1
                        - path/to/cert/configuration/1_N
                    # Множество команд, которые требуется выполнить после обновления хотя бы одного из сертификатов
                    on_update:
                        - update command 1_1
                        - update command 1_N

                # Множество файлов конфигураций
                - locations:
                    # Множество обновляемых сертификатов
                    paths:
                        - path/to/cert/configuration/M_1
                        - path/to/cert/configuration/M_N
                    # Множество команд, которые требуется выполнить после обновления хотя бы одного из сертификатов
                    on_update:
                        - update command M_1
                        - update command M_N

Для каждого сертификата существует конфигурационный файл *.p12.cfg. Если кластер получает сертификат из SecMan, то в словаре pkcs12 будут описаны параметры доступа к сертификату на SecMan:

    {
      "pkcs12": {
        "name": "",                // Имя роли
        "common_name": "",         // CN для сертификата
        "email": "",               // Почтовый адрес владельца сертификата
        "alt_names": "",           // Альтернативные имена субъектов в списке, разделенном  запятыми. Это могут быть имена хостов или адреса электронной почты
        "ip_sans": "",             // Альтернативные имена субъекта IP в списке с разделителями-запятыми. Действителен только в том случае, если роль разрешает IP SAN (по умолчанию)
        "other_sans": "",          // Настраиваемые SAN со строкой OID/UTF8
        "exclude_cn_from_sans": "" // Параметр, включающий/выключающий возможность исключить common_name из DNS или электронной почты SAN
      }
    }

Если кластер использует локальный сертификат, то в словаре pkcs12 будет указан путь к локальному сертификату. Чтобы агент ротации мог обновить файл локального сертификата, необходимо в конфигурационном файле *.p12.cfg добавить словарь secman с описанием параметров доступа к сертификату на SecMan:

    {
      "secman": {
        "name": "",                // Имя роли
        "common_name": "",         // CN для сертификата
        "email": "",               // Почтовый адрес владельца сертификата
        "alt_names": "",           // Альтернативные имена субъектов в списке, разделенном запятыми. Это могут быть имена хостов или адреса электронной почты
        "ip_sans": "",             // Альтернативные имена субъекта IP в списке с разделителями-запятыми. Действителен только в том случае, если роль разрешает IP SAN (по умолчанию)
        "other_sans": "",          // Настраиваемые SAN со строкой OID/UTF8
        "exclude_cn_from_sans": "" // Параметр, включающий/выключающий возможность исключить common_name из DNS или электронной почты SAN
      }
    }

Настройка параметров запущенного агента#

Примечание:

В случае кластерной конфигурации агент запускается на каждом из его узлов. Далее описывается настройка агента для standalone-конфигурации или при запуске на одном узле.

Чтобы изменить параметры запущенного агента, требуется обновить конфигурационный файл агента, который был указан в процессе инсталляции, и перезагрузить параметры службы pg_certs_rotate_agent.service:

Настройка параметров

На первом шаге необходимо заполнить конфигурационный файл агента в формате YAML:

    log:
    directory: PATH/TO/LOG/DIRECTORY
    filename: LOG_FILE_NAME
    level: debug | info | warning | error | fatal
    destination: console, file

    certs:
    enable_update: bool
    poll_period_in_min: unsigned integer
    retry_interval_in_sec: unsigned integer
    retry_attempts_num: unsigned integer

    watch:
        - locations:
            paths:
                - PATH/TO/CERT/CONFIGURATION/1
                - PATH/TO/CERT/CONFIGURATION/N
            on_update:
                - bash command 1
                - bash command N

        - locations:
            paths:
                - PATH/TO/CERT/CONFIGURATION/1
                - PATH/TO/CERT/CONFIGURATION/M
            on_update:
                - bash command 1
                - bash command M

Чтобы включить или отключить ротацию сертификатов, требуется установить значение ключа enable_update, который находится в yaml-словаре certs, в значение true или false соответственно.

Для изменения периода работы агента нужно задать новое значение ключа poll_period_in_min (в минутах), который тоже находится в словаре certs.

Для изменения времени ожидания с целью перезапуска агента (в случае ошибки) нужно задать новое значение ключа retry_interval_in_sec (в секундах). Ключ расположен в словаре certs.

Чтобы изменить количество повторных попыток в случае ошибки, нужно задать новое значение ключа retry_attempts_num, который находится в yaml-словаре certs.

Список сертификатов для обработки агентом задается в виде групп, определенных через ключ locations. Для каждой группы должна быть определена команда обновления сертификатов на кластере. Если один из сертификатов группы устаревает, обновляется на SecMan или появляется в списке отозванных, то выполняется команда, указанная по ключу on_update.

Далее приведен пример конфигурационного файла агента ротации сертификатов для конфигурации standalone-patroni-etcd-pgbouncer без контроля отозванных сертификатов:

    certs:
      enable_update: true
      poll_period_in_min: 1440
      retry_interval_in_sec: 60
      retry_attempts_num: 1

      watch:
        - locations:
            paths:
                - "/home/postgres/ssl/server.p12.cfg"
                - "/home/postgres/ssl/patroni.p12.cfg"
            on_update:
                - sudo systemctl reload pangolin-manager

        - locations:
            paths:
                - "/home/postgres/ssl/server.p12.cfg"
                - "/home/postgres/ssl/pgbouncer.p12.cfg"
            on_update:
                - sudo systemctl reload pangolin-pooler

При изменении имени конфигурационного файла агента требуется обновить параметры службы pg_certs_rotate_agent.service. Имя файла указывается в качестве аргумента исполняемого файла /opt/pangolin-common/bin/pg_certs_rotate_agent:

   ExecStart=/opt/pangolin-common/bin/pg_certs_rotate_agent --config=/etc/postgres/pg_certs_rotate_agent.yaml

Для применения настроек необходимо перезагрузить службу:

   sudo systemctl restart pg_certs_rotate_agent.service

Процесс обновления сертификатов на SecMan#

При успешном подключении к SecMan, агент запрашивает каждый контролируемый сертификат отдельно, используя метод read. Метод fetch не используется, чтобы исключить автоматический перевыпуск сертификатов без их последующего обновления на кластере. Если интервал между датой истечения и датой выпуска сертификата достигает 80% внутри следующего периода (или если сертификат попал в список отозванных), то агент, используя метод generate, запрашивает его перевыпуск. Если в процессе обновления сертификата произошла ошибка, то следующая попытка откладывается на другую итерацию работы агента через период ожидания, определенный в конфигурационном файле.

Примечание:

Контроль за попаданием сертификатов в список отозванных реализуется в сервисе обновления CRL. Сервис ротации сертификатов сообщает сервису обновления CRL серийные номера используемых на кластере сертификатов. Если сервис обновления CRL находит сертификаты в списке отозванных, то сообщает об этом сервису ротации сертификатов, после чего запускается процесс их обновления на SecMan.

Процесс обновления сертификатов на кластере#

При успешном обновлении на SecMan хотя бы одного сертификата из списка (или если обновление сертификатов на SecMan произошло без участия агента) агент запускает процесс обновления сертификатов на кластере. Для этой проверки он сохраняет серийные номера сертификатов, которые периодически сравнивает с полученными от SecMan.

Процесс обновления сертификатов на кластере состоит в перезагрузке параметров узла кластера или сервера конфигурации standalone с помощью команды, указанной в конфигурационном файле.

Внимание!

Агент не контролирует ошибки, которые могут произойти в процессе обновления сертификатов на кластере.

Отключению функциональности#

Отключение производится путем удаления описанных выше конфигурационных параметров для соответствующих компонентов.

Поддержка CRL в компонентах кластера Pangolin#

CRL представляет собой список сертификатов, которые УЦ пометил как отозванные (при этом сертификаты с истекшим сроком действия не вносятся в этот список). Каждая запись в списке включает идентификатор отозванного сертификата и дату отзыва. Дополнительная информация включает в себя ограничение по времени, если отзыв применяется в течение определенного периода времени, а также причину отзыва.

Начиная с версии 5.4.0, использование файлов CRL поддерживается всеми компонентами кластера, а автоматическое обновление неактуальных файлов CRL доступно как часть функциональности агента ротации сертификатов pg_certs_rotate_agent.

Настройка CRL#

Для поддержки CRL имеются следующие параметры в конфигурационных файлах компонентов:

  1. postgresql.conf (PostgreSQL):

    • ssl_crl_file - путь к файлу CRL, по которому выполняется проверка статуса клиентских сертификатов;

    • ssl_crl_dir - путь к директории с файлами CRL, по которым выполняется проверка аннулирования клиентских сертификатов.

    Примечание:

    При включенной защите параметров ssl_crl_file и ssl_crl_dir инициализируются значениями из защищенного хранилища секретов.

  2. Клиентские утилиты, использующие библиотеку libpq (psql):

    • sslcrl (переменная окружения PGSSLCRL) - путь к файлу CRL, по которому выполняется проверка статуса серверных сертификатов;

    • sslcrldir (переменная окружения PGSSLCRLDIR) - путь к директории с файлами CRL, по которым выполняется проверка статуса серверных сертификатов.

  3. postgres.yml (Pangolin Manager):

    • в секции restapi:

      • crlfile - путь к файлу CRL;

      • crlpath - путь к директории с файлами CRL, по которым выполняется проверка аннулирования клиентских сертификатов;

    • в секции postgresql/authentication/(replication/rewind/superuser):

      • sslcrldir - путь к директории с файлами CRL, по которым выполняется проверка аннулирования серверного сертификата PostgreSQL;

    • в секции postgresql/parameters:

      • sslcrldir - путь к каталогу с файлами CRL, по которым выполняется проверка аннулирования клиентских сертификатов;

  4. pangolin-pooler.ini (Pangolin Pooler):

    • client_tls_crl_file - путь к файлу CRL;

    • client_tls_crl_path - путь к директории с файлами CRL, по которым выполняется проверка аннулирования клиентских сертификатов;

    • server_tls_crl_file - путь к файлу CRL;

    • server_tls_crl_path - путь к директории с файлами CRL, по которым выполняется проверка аннулирования серверного сертификата PostgreSQL.

Внимание!

В параметрах конфигурации, приведенных выше, должны использоваться пути к существующим файлам CRL, иначе при включенном TLS/SSL запуск компонента завершится ошибкой.

Примечание:

Для использования директории c файлами CRL необходимо для каждого из файлов создать в этой директории символические ссылки, названные по хеш-значению от содержимого соответствующего файла CRL. Хеш-значения рассчитываются утилитой c_rehash.

Пример вызова утилиты:

c_rehash /pg_ssl/crl

За подробностями обратитесь к документации OpenSSL.

Для обеспечения автоматического обновления файлов CRL расширяется функциональность агента ротации сертификатов pg_certs_rotate_agent.

Запуск агента выполняется до запуска служб postgresql.service (для конфигурации standalone), pangolin-manager.service (для кластерной конфигурации) и pangolin-pooler.service, чтобы для каждого из компонентов выгрузить файлы CRL из CDP (CRL Distribution Point - точка распространения CRL). Компоненты кластера не запустятся, если файлы CRL прописаны в конфигурационных файлах, но отсутствуют на файловой системе. После выполнения первого цикла выгрузки CRL агент нотифицирует systemd о готовности в случае успешной выгрузки всех файлов CRL, иначе переводит статус службы в failed. Время цикла выгрузки CRL ограничено за счет установки времени ожидания в 30 сек на каждый запрос к CDP.

Примечание:

Агент не удаляет файлы CRL из файловой системы, только заменяет их на новые, поэтому исчезновение файлов CRL в процессе работы компонентов является результатом ручного вмешательства. Для восстановления удаленных файлов CRL перезапустите службу агента ротации и обновления CRL.

Исполняемый файл агента принимает в качестве аргумента командной строки путь к конфигурационному файлу агента pg_certs_rotate_agent.yml, который расположен в директории /etc/postgres и включает следующие параметры:

  • в секции log:

    • directory - путь к директории для лог-файлов (обязательный параметр при выводе лога в файл);

    • filename - имя лог-файла (по умолчанию pg_certs_rotate_agent.log);

    • level - (trace|debug|info|warning|error) - уровень логирования (по умолчанию info);

    • destination - методы записи лога (комбинируются через запятую):

      • console - в стандартный поток вывода или ошибок (в случае запуска под управлением службы - в системный журнал). Значение по умолчанию;

      • file - в файл.

  • в секции crl:

    • enable_update (true|false) - включить/выключить автоматическое обновление CRL (по умолчанию false);

    • poll_period_in_min - интервал времени, определяющий период проверки наличия обновленных CRL файлов (задается как целое неотрицательное число в минутах; по умолчанию 60 минут; 0 для отключения периодической проверки CRL). Опрос CDP должен выполняться не реже данного периода;

    • retry_interval_on_expire_in_sec - интервал повторных попыток выгрузки CRL, для которых дата публикации или дата окончания срока действия уже наступили (задается как целое положительное число в секундах, по умолчанию 30 секунд);

    • retry_interval_on_failure_in_sec - интервал времени, через который выполняются повторные попытки выгрузки CRL после неудачи (задается как целое положительное число в секундах, по умолчанию 30 секунд);

    • retry_attempts_num_on_failure - количество попыток выгрузки CRL по списку URI для данного пути расположения файла CRL после неудачи (по умолчанию 1 попытка);

    • crl_file_perm - права доступа, устанавливаемые на выгружаемые файлы CRL (задается в восьмеричном формате, по умолчанию 0644).

  • в секции watch:

    • locations - секция включает списки путей до файлов, обновление которых отслеживается (path), а также куда выгружаются новые CRL из CDP (uri):

      • path - путь к файлу CRL;

      • uri - массив URI для выгрузки CRL (основной и резервные);

    • on_update - список выполняемых команд, если файл CRL изменился (перечитывание конфигурации компонентами кластера).

Далее приведен формат конфигурационного файла агента ротации сертификатов и обновления CRL:

log:
  directory: /pgerrorlogs/05/pg_certs_rotate_agent
  filename: pg_certs_rotate_agent.log
  level: info
  destination: console,file

crl:
  enable_update: false
  poll_period_in_min: 60
  retry_interval_on_expire_in_sec: 30
  retry_interval_on_failure_in_sec: 30
  retry_attempts_num_on_failure: 1
  crl_file_perm: 0644

  watch:
  - locations:
    - path: CRLPATH_1
      uri:
      - URI_1
      - URI_N
    - path: CRLPATH_N
      uri:
      - URI_1
      - URI_N
    on_update:
    - sudo systemctl reload postgresql

  - locations:
    - path: CRLPATH_1
      uri:
      - URI_1
      - URI_N
    - path: CRLPATH_N
      uri:
      - URI_1
      - URI_N
    on_update:
    - sudo systemctl reload pangolin-manager

  - locations:
    - path: CRLPATH_1
      uri:
      - URI_1
      - URI_N
    - path: CRLPATH_N
      uri:
      - URI_1
      - URI_N
    on_update:
    - sudo systemctl reload pangolin-pooler

Справка по аргументам командной строки агента:

pg_certs_rotate_agent --help
Allowed options:
  -h [ --help ]                         produce this help message
  -p [ --pid-file ] arg (=/var/run/pg_certs_rotate_agent/pg_certs_rotate_agent.pid)
                                        path to agent's PID file
  -c [ --config ] arg (=/etc/postgres/pg_certs_rotate_agent.yml)
                                        path to agent's configuration file
  -d [ --dry-run ]                      check config file format and exit

Агент поддерживает режим пробного запуска с ключом --dry-run. В этом режиме проверяется корректность конфигурационного файла с последующим завершением выполнения. Результат проверки определяется кодом возврата: 0 - конфигурационный файл валидный, иначе 1. Информация об ошибке выводится в лог.

На старте агент сохраняет PID своего процесса в файл (по умолчанию /var/run/pg_certs_rotate_agent/pg_certs_rotate_agent.pid). Файл с PID процесса используется для предотвращения запуска еще одного экземпляра агента и в команде на ротацию лог-файла. Ротация лог-файлов агента выполняется с помощью утилиты logrotate. Файл конфигурации для logrotate расположен в /etc/logrotate.d/pg_certs_rotate_agent и имеет следующее содержимое:

/pgerrorlogs/05/pg_certs_rotate_agent/pg_certs_rotate_agent.log {
      rotate 10
      dateext
      daily
      missingok
      notifempty
      compress
      create 0640 postgres postgres
      sharedscripts
      postrotate
           [ ! -f /var/run/pg_certs_rotate_agent/pg_certs_rotate_agent.pid ] || /bin/kill -USR1 `cat /var/run/pg_certs_rotate_agent/pg_certs_rotate_agent.pid 2> /dev/null` 2>/dev/null
      endscript
}

Права доступа к директории с логами /pgerrorlogs/05/pg_certs_rotate_agent:

drwxr-x--- 2 postgres postgres

Если включена автоматическая проверка обновления CRL (crl:enable_update), агент в установленное время подключается к первой доступной CDP по HTTP (crl:watch:locations:uri), выгружает файл CRL и сохраняет его в PEM-формате по пути, определенному в параметре crl:watch:locations:path (если файл CRL еще ни разу не выгружался или изменился в точке распространения).

Примечание:

Выгруженный файл CRL с истекшим сроком действия не сохраняется в файловой системе и не удаляется из нее.

Внимание!

Агент не проверяет подпись выгруженного файла CRL. Данную проверку выполняют компоненты кластера, для которых файл CRL предназначен.

Агент создает символическую ссылку на выгруженный файл CRL. Символическая ссылка именуется хеш-значением, рассчитанным по содержимому файла CRL. Если файл CRL до выгрузки нового уже существовал, то символическая ссылка на старый файл удаляется, чтобы не засорять файловую систему, поскольку хеш-значения от старого и нового файлов CRL будут отличаться. Символическая ссылка требуется, чтобы иметь возможность указывать директорию с файлами CRL в конфигурационных файлах компонентов кластера, так как OpenSSL выполняет поиск CRL по хеш-значению.

Если выгруженный файл CRL не является истекшим и не содержит серийные номера сертификатов, находящихся под контролем сервиса ротации сертификатов, агент выполнит команды перечитывания конфигурации соответствующих компонентов (crl:watch:locations:on_update). Если же файл CRL содержит серийные номера таких сертификатов, то соответствующие сертификаты будут перевыпущены сервисом ротации, а команды перечитывания конфигурации выполнятся после процедуры перевыпуска сертификатов.

Внимание!

Агент не контролирует ошибки, которые могут произойти в процессе перечитывания конфигурации компонентами кластера.

Для защиты файлов CRL от их перезаписи агентом в процедуре инициализации SSL контекста в компонентах кластера применяется блокировка на базе flock(). В процессе работы создается временный файл /tmp/.crl.lock. Агент удерживает для него эксклюзивную блокировку на время записи выгруженных CRL-файлов, тогда как компоненты кластера (на старте или при перечитывании параметров) используют для него разделяемую блокировку. Таким образом, компоненты кластера могут одновременно, не мешая друг другу, загружать файлы CRL, блокируясь только при обновлении файлов CRL агентом.

Для каждого файла CRL проверка обновления выполняется:

  • при запуске агента;

  • с периодичностью, определенной в параметре crl:poll_period_in_min, если значение параметра больше 0;

  • в момент следующей публикации CRL (дата в поле CRL файла NextCRLPublish) и через каждый интервал времени, определяемый параметром crl:retry_interval_on_expire_in_sec (если после наступления даты публикации CRL еще не выпущен);

  • в момент истечения срока действия CRL (дата в поле CRL файла NextUpdate) и через каждый интервал времени, определяемый параметром crl:retry_interval_on_expire_in_sec, если после истечения срока действия CRL еще не выпущен;

  • спустя интервал времени, задаваемый параметром crl:retry_interval_on_failure_in_sec, после неудачной выгрузки;

  • по требованию путем перезапуска службы агента (на его старте):

sudo systemctl restart pg_certs_rotate_agent.service
  • при выполнении команды reload и изменении конфигурационного файла агента:

    • изменился список URI;

    • добавлена новая команда в crl:watch:locations:on_update;

    • добавлен новый путь к файлу CRL.

sudo systemctl reload pg_certs_rotate_agent.service

Примечание:

Дата следующей проверки обновления для каждого файла CRL рассчитывается индивидуально.

Процесс инсталляции#

Пути к файлу CRL и директории, содержащей файлы CRL, задаются в конфигурационном файле инсталлятора и одинаковы для всех компонентов кластера. Ниже приведен формат его полей для настройки путей к файлам CRL:

pg_certs_pwd:
  crl_file: "{{ '' | default('/pg_ssl/crl/root.crl', true) }}" # Путь к CRL файлу
  crl_path: "{{ '' | default('/pg_ssl/crl', true) }}"          # Путь к директории с файлами CRL

Для формирования конфигурационного файла агента и обновления CRL в конфигурационном файле инсталлятора необходимо добавить следующие параметры:

pg_certs_rotate_agent:
  enable: true  # Настроить и запустить службу агента (не учитывается при обновлении агента, только при первичном развертывании)
  agent_config: /etc/postgres/pg_certs_rotate_agent.yml  # Путь к конфигурационному файлу агента в формате YAML
  update_agent_config: false # Обновить файл конфигурации агента (учитывается только при обновлении, значение по умолчанию - False)

  log:
    directory: /pgerrorlogs/05/pg_certs_rotate_agent   # Путь к директории для лог-файлов
    filename: pg_certs_rotate_agent.log                # Имя лог-файла
    level: info                                        # Уровень логирования
    destination: console,file                          # Методы записи лога

  crl:
    enable_update: false                 # Включить/выключить автоматическое обновление CRL
    poll_period_in_min: 60               # Период проверки наличия обновленных CRL файлов
    retry_interval_on_expire_in_sec: 30  # Таймаут для повторной попытки выгрузки CRL после наступления даты публикации CRL или окончания срока действия
    retry_interval_on_failure_in_sec: 30 # Таймаут для повторной попытки выгрузки CRL после неудачи
    retry_attempts_num_on_failure: 1     # Количество попыток выгрузки CRL по списку URI для данного пути расположения файла CRL после неудачи
    crl_file_perm: 0644                  # Права доступа, устанавливаемые на выгружаемые файлы CRL

    watch:
    - locations:
      - path: path/to/crlfile_1  # Путь к обновляемому файлу CRL
        uri:
        - URI_1                  # Основная точка распространения CRL
        - URI_N                  # Резервная точка распространения CRL
      - path: path/to/crlfile_N  # Путь к обновляемому файлу CRL
        uri:
        - URI_1                  # Основная точка распространения CRL
        - URI_N                  # Резервная точка распространения CRL
      on_update:
      - sudo systemctl reload postgresql # Список выполняемых команд, если файл CRL изменился

Примечание:

Установка файлов агента на узел СУБД производится инсталлятором автоматически.

Обновление pg_certs_rotate_agent осуществляется по одному из двух сценариев:

  • если агент был ранее установлен в обновляемой версии СУБД Pangolin (например, при переходе с версии СУБД Pangolin 5.4.0 на более высокую):

    • в зависимости от значения параметра update_agent_config, который определяется в конфигурационном файле инсталлятора, автоматически настраивается файл конфигурации агента. По умолчанию значение параметра - False, в этом случае конфигурационный файл агента не заменяется версией конфигурации из файла инсталлятора. При необходимости ее обновления инсталлятором, параметр нужно установить в значение True;

    • в зависимости от состояния службы агента (active/inactive) по окончании обновления версии СУБД служба агента будет либо запущена, либо нет. Проверить статус службы можно следующим способом:

      sudo systemctl status pg_certs_rotate_agent | grep Active
      

      Результат будет иметь следующий вид:

      Active: active (running) since Tue 2023-05-23 15:59:02 MSK; 13s ago
      

      или

      Active: inactive (dead)
      
  • если агент не был установлен в обновляемой версии СУБД Pangolin (например, при переходе с версии СУБД Pangolin 5.2.0):

    • файл конфигурации агента создается и настраивается в соответствии с конфигурационным файлом инсталлятора (для незаполненных полей берутся значения по умолчанию);

    • запуск службы агента в данном случае не производится.

Примечание:

В рамках механизма обновления версии СУБД скрипт-разведчик проверяет корректность заполнения файла конфигурации pg_certs_rotate_agent.

В файл /etc/sudoers вручную добавляются следующие команды, разрешенные пользователю postgres для выполнения без запроса пароля:

/bin/journalctl -f -u pg_certs_rotate_agent
/usr/bin/systemctl start pg_certs_rotate_agent
/usr/bin/systemctl stop pg_certs_rotate_agent
/usr/bin/systemctl restart pg_certs_rotate_agent
/usr/bin/systemctl reload pg_certs_rotate_agent
/usr/bin/systemctl status pg_certs_rotate_agent
/usr/bin/systemctl reload pangolin-manager
/usr/bin/systemctl reload postgres

В файл конфигурации службы pangolin-manager.service необходимо добавить команду reload:

ExecReload=/bin/kill -HUP $MAINPID

Генерация и установка постоянного пароля технологической УЗ#

Расширение psql_rotate_password добавляет функцию генерации случайного пароля, удовлетворяющего парольной политике.

Установка расширения psql_rotate_password#

Установка расширения производится установщиком.

Параметры установщика (указаны значения по умолчанию):

rotate_password.enable: false

rotate_password.num_rounds: 20

Далее рассматривается, что делается в установщике или что необходимо сделать при ручной установке:

  1. Установка расширения. Распакуйте файлы расширения в каталог с расширениями, например:

    # tar xzf psql_rotate_password-<version>.tar.gz --directory $(pg_config --sharedir)/extension
    

    Необходимо убедиться, что используется подходящая утилита pg_config.

  2. Создание расширения psql_rotate_password. Установите расширение (в схему ext по умолчанию):

    postgres=# CREATE EXTENSION psql_rotate_password schema ext;
    

    Рекомендуется установка для всех БД, для которых необходимо расширение.

    Управление правами: по умолчанию права к функции не выставлены, то есть ее может вызвать суперпользователь, либо пользователь получивший права от схемы или БД. Отдельных правил для настройки прав не существует.

Настройка параметров#

Включение генерации пароля происходит при установке параметра rotate_password.enable в значение true (по умолчанию функциональность отключена, значение параметра - false):

rotate_password.enable: true

Параметры генерации пароля:

  • rotate_password.num_rounds = '' - количество попыток генерации пароля:

    rotate_password.valid_roles = '20'`
    
  • rotate_password.valid_roles = '' - список пользователей (через запятую), для которых разрешена генерация пароля:

    rotate_password.valid_roles = 'user1, "User-2", user3'
    

При изменении параметров перечитайте конфигурацию (reload).

Использование функции генерации паролей#

Входные параметры функции rotate_password:

  • (обязательный) Oid или имя пользователя;

  • (не обязательный) длина пароля. При отсутствии будет сгенерирован по минимальной длине пароля согласно парольным политикам (случайная длина до 5 символов).

Выходной параметр: сгенерированный пароль.

Пример генерации пароля для пользователя User-2:

SELECT * FROM rotate_password('User-2');
┌───────────────────────┐
    rotate_password    
├───────────────────────┤
 W+3r#0291h885I`9^JpZ@ 
└───────────────────────┘
(1 row)

Возможные ошибки:

  • исчерпано количество попыток генерации пароля;

  • синтаксические параметры парольной политики пользователя вместе с переданным параметром длины пароля не позволяют сгенерировать пароль, соответствующий требованиям;

  • пользователь не входит в rotate_password.valid_roles;

  • ошибка синтаксического анализа rotate_password.valid_roles;

  • не найден пользователь.

Отключение функциональности#

Отключение функциональности производится путем удаления расширения:

DROP EXTENSION psql_rotate_password;

Настройка подключения к SecMan для Pangolin#

Описываемая функциональность:

  • обеспечивает настройку параметров подключения к хранилищу секретов SecMan;

  • упрощает процесс изменения параметров для работы с хранилищем секретов;

  • обеспечивает возможность обнаружения ошибок в параметрах подключения к хранилищу секретов на этапе конфигурирования доступа;

  • обеспечивает настройку системы для работы с хранилищем сертификатов;

  • упрощает использование утилиты в автоматизированных скриптах.

  • обеспечивает настройку проверки серверного сертификата хранилища секретов.

Если изменение параметров подключения к хранилищу секретов или сертификатов производится на работающем кластере, то выполните/запустите перечитывание конфигурационных параметров в компонентах кластера. Перезапуск кластера не требуется.

Дополнительные параметры для работы с хранилищем секретов SecMan#

Для подключения и работы с хранилищем секретов SecMan используются дополнительные параметры:

  • Доменное имя - добавляется возможность указания сервера хранилища через доменное имя, а не только через IP-адрес.

  • Префикс для пути хранения секретов - добавляется возможность указания префикса для пути хранения kv-секретов согласно иерархии секретов. Префикс должен содержать движок секретов. Путь, используемый для доступа к секретам: /v1/{prefix/}data/{suffix/}{cluster id/}{subdomain/}secret_name. Пример заданного префикса: CI03170154_CI03214758/I/SERV/GLOB/SERV/KV.

  • Точка входа для urn аутентификации: /auth/точка_входа/login/. Указание точки входа позволяет авторизоваться по LDAP для типа авторизации Userpass (пример, auth/ad/X.XX.ru/login/). По умолчанию используются:

    • approle - для авторизации AppRole;

    • userpass - для авторизации Userpass.

  • Тенант хранилища (x-vault-namespace) - при взаимодействии с хранилищем секретов по HTTPS тенант указывается в header запроса.

  • Протокол взаимодействия с хранилищем секретов (HTTP или HTTPS, по умолчанию HTTPS).

Утилита setup_kms_credentials позволяет сохранять дополнительные параметры для работы с хранилищем секретов SecMan. Дополнительные параметры имеют значения по умолчанию или расширяют текущие типы данных. Это обеспечивает обратную совместимость формата шифрованного файла /etc/postgres/enc_connection_settings.cfg (владелец: kmadmin_pg, группа: kmadmin_pg, права: -rw-r--r--). Процесс добавления новых параметров не меняется.

Редактирование параметров для работы с хранилищем секретов#

В утилиту setup_kms_credentials добавляется новый режим, позволяющий редактировать параметры для работы с хранилищем секретов в существующих записях. Администратор безопасности запускает утилиту setup_kms_credentials в режиме редактирования параметров. Если хранилище содержит более одной записи, то необходимо указать, какую запись требуется обновить (список записей можно получить в режиме просмотра). После чего поочередно вводятся обновленные параметры. Если пропустить обновление параметра, то он сохраняет предыдущее значение.

Просмотр сохраненных параметров для работы с хранилищем секретов#

В утилиту setup_kms_credentials добавляется новый режим, позволяющий просматривать сохраненные параметры для работы с хранилищем секретов. Администратор безопасности запускает утилиту setup_kms_credentials в режиме просмотра параметров и получает список сохраненных параметров (за исключением паролей).

По умолчанию в режиме просмотра происходит проверка сохраненных параметров подключения к хранилищу секретов. Проверяются только параметры подключения к Хранилищу секретов. Параметры доступа к секретам в данном режиме не проверяются. Чтобы отключить проверку параметров в режиме просмотра, необходимо указать ключ --no-check.

Если в режиме проверки параметров указать ключ --debug, то утилита дополнительно выведет в лог информацию о взаимодействии с Хранилищем секретов (URL запроса, HTTP-код ответа и т.п.).

Очистка хранилища параметров подключения#

В утилиту setup_kms_credentials добавляется новый режим, позволяющий удалять записи с параметрами для работы с хранилищем секретов. Для удаления записи необходимо указать ее номер (список записей можно получить в режиме просмотра).

Настройка параметров для работы с хранилищем сертификатов#

В утилиту setup_kms_credentials добавляется аргумент --purpose, позволяющий настраивать параметры для работы с хранилищем сертификатов. Аргумент может принимать следующие значения:

  • secrets - настройка параметров для работы с хранилищем секретов. Параметры хранятся в шифрованном файле /etc/postgres/enc_connection_settings.cfg (владелец: kmadmin_pg, группа: kmadmin_pg, права: -rw-r--r--);

  • certs - настройка параметров для работы с хранилищем сертификатов. Параметры хранятся в шифрованном файле /etc/postgres/enc_connection_settings_cert.cfg (владелец: kmadmin_pg, группа: kmadmin_pg, права: -rw-r--r--).

Аргумент --purpose возможно указывать во всех режимах работы утилиты setup_kms_credentials. Если аргумент не указан, то утилита производит настройку параметров для работы с Хранилищем секретов.

Указание параметров для работы с хранилищем секретов через аргументы командной строки#

В утилиту setup_kms_credentials добавлена возможность передачи параметров (кроме пароля и идентификатора секрета) через аргументы командной строки. Пароль или идентификатор секрета задаются в интерактивном режиме или через перенаправление потока ввода.

Режим позволяет упростить использование утилиты в автоматизированных скриптах.

Настройка проверки серверного сертификата хранилища секретов#

При взаимодействии с хранилищем секретов по протоколу HTTPS происходит проверка серверного сертификата. Проверка осуществляется на основании корневого сертификата, путь к которому задается с помощью директории или файла в утилите setup_kms_credentials. Если не задавать путь к корневому сертификату, то его поиск будет осуществляться в системной директории с сертификатами.

Отключение функциональности#

Настройка параметров подключения производится при первоначальной настройке кластера Pangolin или при изменении настроек хранилища секретов (или сертификатов). Специальные команды для отключения функциональности отсутствуют.

Утилита setup_kms_credentials#

Утилита setup_kms_credentials позволяет:

  • добавить одну или несколько записей. Разделитель «,»;

  • редактировать, удалять и проверять параметры подключения к хранилищам секретов и сертификатов.

Для вывода доступных режимов работы setup_kms_credentials необходимо выполнить:

setup_kms_credentials --help
Usage:
setup_kms_credentials [mode] <option>...
Options:
--purpose      [-s]     выбор типа хранилища: certs - хранилище сертификатов или secrets - хранилище секретов, значение по умолчанию: secrets
--format       [-f]     Формат вывода: table или json, по умолчанию table - человекочитаемый формат
--cluster      [-c]     имя кластера
--host         [-h]     доменное имя или ip адрес хранилища
--port         [-p]     номер порта хранилища
--protocol     [-l]     протокол обмена данными: http (1) или https (2), протокол по умолчанию: https
--prefix       [-x]     путь к хранилищу секретов на сервере (префикс для пути хранения секретов, по умолчанию: kv)
--suffix       [-u]     часть пути к секрету на сервере (по умолчанию: пусто)
--namespace    [-n]     тенант хранилища, по умолчанию: пусто
--type         [-t]     тип авторизации: Userpass Auth Method (1) или AppRole Auth Method (2)
--auth         [-a]     точка входа для аутентификации, по умолчанию: userpass
--id           [-i]     логин или  id роли
--root-ca      [-r]     файл или директория, содержащая корневой сертификат для проверки хранилища секретов/сертификатов
--skip-confirm          редактирование или удаление без подтверждения
--index                 индекс записи для режимов редактирования/удаления
--plain                 простой вывод
--no-check              не проверять подключение
--debug                 показать информацию о взаимодействии с Хранилищем
--help                  эта страница помощи

Modes:
setup  - ввести новый набор данных для хранилища (хранилищ) секретов или сертификатов, поведение по умолчанию
show   - показать текущий набор параметров подключений к хранилищам секретов/сертификатов (без паролей и id секретов)
add    - добавить новую запись в набор параметров подключений к хранилищам секретов/сертификатов
delete - удалить запись из набора параметров подключений к хранилищам секретов/сертификатов по номеру записи
edit   - редактировать запись из набора параметров подключений к хранилищам секретов/сертификатов по номеру записи

Pangolin product version information:
--product_version        показать название продукта и версию
--product_build_info     показать номер сборки, дату сборки и хеш
--product_component_hash показать хеш компонента

Для работы с хранилищем сертификатов, при вызове setup_kms_credentials необходимо указывать аргумент --purpose=certs.

Примечание:

С версии 5.4.0 отсутствует обратная совместимость обновления по параметру suffix.

Интерактивный режим добавления параметров#

/usr/pangolin-5.4.0/bin/setup_kms_credentials --purpose=certs add
Enter IP address or Domain Name of Secrets storage:
<IP-адрес>
Enter port:
<PID>
Choose protocol type or leave empty to use default (https):
1. http
2. https
   1
   Enter secrets prefix or leave empty to use default (kv):
   <Префикс>
   Enter Secrets storage namespace or leave empty:
   CI00000000_CI00000000
   Choose credentials type:
1. Userpass Auth Method
2. AppRole Auth Method
   1
   Enter auth point or leave empty to use default (userpass):
   userpass
   Enter login:
   adminencryption
   Enter password:
********
Confirm password:
********
Credentials for Secrets storage has been added successfully

Режим добавления параметров через аргументы командной строки#

/usr/pangolin-5.2.1/bin/setup_kms_credentials --purpose=certs add -c test -h <IP-адрес> -p <PID> -l 2 -x <Префикс> -n CI00000000_CI00000000 -t 1 -a userpassTest -i adminencryption -r /pg_ssl
Enter password:
********
Confirm password:
********
Credentials for Secrets storage has been added successfully

Режим добавления множественных параметров через аргументы командной строки#

Пример команды добавления нескольких записей одной командой:

./setup_kms_credentials setup --cluster test --host <hostname>,<hostname> --port <порт>,<порт> -r /pg_ssl -u
Press Ctrl+C to exit
Choose credentials type:
1. Userpass Auth Method
2. AppRole Auth Method
1
Enter login:
qewr
Enter password:
****
Confirm password:
****
Credentials for Secret storage has been set successfully
Enter login:
qwer
Enter password:
****
Confirm password:
****
Credentials for Secret storage has been added successfully

Режим просмотра добавленных параметров подключения#

Пример команды просмотра записей в человекочитаемом формате:

/usr/pangolin-5.2.1/bin/setup_kms_credentials --purpose=certs show
Pangolin cluster ID: test
Root CA path: /pg_ssl
+-------------------------------------------------------------------------------------------------------------------------------------------+
|  # | protocol |       host | port  | prefix    |             namespace |            cred type | auth point |              id |     status |
-----+----------+------------+-------+-----------+-----------------------+----------------------+------------+-----------------+-------------
|  0 |     http | <IP-адрес> | <PID> | <Префикс> | CI00000000_CI00000000 | Userpass Auth Method |   userpass | adminencryption |         Ok |
|  1 |    https | <IP-адрес> | <PID> | <Префикс> | CI00000000_CI00000000 | Userpass Auth Method |   userpass | adminencryption |         Ok |
+-------------------------------------------------------------------------------------------------------------------------------------------+

Режим просмотра добавленных параметров подключения в JSON#

Пример команды просмотра записей в JSON-формате:

./setup_kms_credentials show --format json
{
	"cluster_id" : "test",
	"credentials" :
	[
		{
			"auth_point" : "userpass",
			"host" : "10.40.0.9",
			"id" : "qewr",
			"namespace" : "",
			"port" : 8201,
			"prefix" : "kv",
			"protocol" : "HTTPS",
			"status" : "Storage error",
			"type" : "USER_PASS"
		},
		{
			"auth_point" : "userpass",
			"host" : "10.40.0.5",
			"id" : "qwer",
			"namespace" : "",
			"port" : 1111,
			"prefix" : "kv",
			"protocol" : "HTTPS",
			"status" : "Storage error",
			"type" : "USER_PASS"
		}
	],
	"root_ca" : "/pg_ssl",
	"suffix" : ""
}

Режим редактирования добавленных параметров подключения#

В режиме просмотра необходимо определить номер записи, которую следует отредактировать. Например, нужно отредактировать первую запись - изменить тенант хранилища. Передаем аргументом индекс записи: 1 и новый тенант хранилища CI00000001_CI00000001:

/usr/pangolin-5.2.1/bin/setup_kms_credentials --purpose=certs edit --index=1 --plain -n CI00000001_CI00000001
Enter password:
********
Confirm password:
********
+---------------------------------------------------------------------------------------------------------------------------------------+
|  # | protocol |       host | port | prefix |             namespace |            cred type | auth point |              id |     status |
-----+----------+------------+------+--------+-----------------------+----------------------+------------+-----------------+-------------
|  0 |     http | <IP-адрес> | <PID> | <Префикс> | CI00000000_CI00000000 | Userpass Auth Method |   userpass | adminencryption |        N/A |
|  1 |    https | <IP-адрес> | <PID> | <Префикс> | CI00000001_CI00000001 | Userpass Auth Method |   userpass | adminencryption |        N/A | <update data/password>
|  1 |    https | <IP-адрес> | <PID> | <Префикс> | CI00000000_CI00000000 | Userpass Auth Method |   userpass | adminencryption |        N/A | <original>
+---------------------------------------------------------------------------------------------------------------------------------------+
Do you want to edit data? (yes/no)?:
yes
Credentials for Secrets storage has been edited successfully

Режим удаления добавленных параметров подключения#

В режиме просмотра необходимо определить номер записи, которую следует удалить. Например, нужно удалить нулевую запись.

/usr/pangolin-5.2.1/bin/setup_kms_credentials --purpose=certs delete --index=0 --plain
+---------------------------------------------------------------------------------------------------------------------------------------+
|  # | protocol |       host | port | prefix |             namespace |            cred type | auth point |              id |     status |
-----+----------+------------+------+--------+-----------------------+----------------------+------------+-----------------+-------------
|  0 |     http | <IP-адрес> | <PID> | <Префикс> | CI00000000_CI00000000 | Userpass Auth Method |   userpass | adminencryption |        N/A | <delete>
|  1 |    https | <IP-адрес> | <PID> | <Префикс> | CI00000001_CI00000001 | Userpass Auth Method |   userpass | adminencryption |        N/A |
+---------------------------------------------------------------------------------------------------------------------------------------+
Do you want to remove the record? (yes/no)?:
yes
Credentials for Secrets storage has been removed successfully

Архивирование и восстановление#

Для архивирования и восстановления в СУБД Pangolin используется система резервного копирования и репликации. Она включает в себя утилиты для резервного копирования и восстановления (например, pg_probackup), а также для потоковой и логической репликации.

Система резервного копирования Pangolin позволяет защитить данные от потери в случае отказа оборудования, ошибок оператора, ошибок приложений, проблем сервисных служб, а также используется для целей аудита.

Функции системы:

  • резервное копирование и восстановление данных Pangolin;

  • создание полной резервной копии по расписанию;

  • снятие резервных копий с любого сервера кластера высокой доступности;

  • возможность хранения метаданных на отдельном служебном сервере;

  • дедупликация;

  • восстановление состояния на определенный момент времени (в соответствии с политиками хранения копий);

  • обеспечение соответствия нефункциональным требованиям к системам уровня Mission critical.

В этом разделе рассматриваются следующие сценарии восстановления из резервной копии:

  • Полное восстановление кластера. Например, кластер полностью неработоспособен и требуется восстановление из последней резервной копии всего кластера.

  • Восстановление на определенный момент времени. Например, изменения в БД привели к сбою или потере данных. БД находится в рабочем состоянии, но требуется восстановление данных на определенный момент времени до сбоя. Также используется при миграции и для тестирования и аудита.

  • Создание резервного сервера. Например, в результате сбоя на предыдущем резервном сервере БД на нем оказывается недоступна, требуется восстановление из резервной копии.

В качестве сетевой централизованной системы хранения резервных копий используется служебная база данных (далее - «Каталог»). Интеграция с Каталогом позволяет выполнять резервное копирование экземпляров Pangolin и связанных с ними файлов журналов записи с опережением (файлы Write Ahead Log, WAL).

Резервное копирование файлов WAL обеспечивает целостность данных Pangolin. Такая резервная копия позволяет использовать таблицы базы данных во время сеанса без каких-либо ограничений.

Резервное копирование с ведомого сервера кластера производится в автоматизированном режиме с помощью клиентского приложения (Далее - «Агент»). Выполняется либо снятие полной резервной копии, либо архива файлов WAL, накопившихся со времени последней резервной копии.

Восстановление инициируется пользователем и предполагает ручное указание параметров восстановления. Pangolin потребуется учетная запись с правами на создание резервных копий: отдельная роль с минимальными правами, необходимыми для выбранной стратегии копирования. Управление функциями резервного копирования Pangolin выполняется специалистами по резервному копированию.

Поддержка резервного копирования настраивается в конфигурационном файле custom_file.yml через параметр SRC (резервная копия системы).

Резервное копирование#

Pangolin, как и все современные СУБД, поддерживает возможность резервного копирования для защиты данных от потери в случае отказа оборудования, ошибки администратора, ошибок приложений, проблем сервисных служб, а также для помощи при миграции данных на новые сервера. Начиная с версии Pangolin 4.1.0 добавлены улучшения, упрощающие мониторинг, управление и интеграцию с различными системами резервного копирования (СРК):

  • manage_backup.bin – вспомогательный python-скрипт, распространяемый в бинарном виде, который необходим для интеграции с различными СРК и управления процессом резервного копирования;

  • pgse_backup – расширение, включающее набор представлений и процедур для организации и контроля мониторинга прохождения заданий резервного копирования;

  • pg_probackup – утилита резервного копирования для подготовки и контроля архивов резервной копии.

Главные функции резервного копирования:

  • создание полной резервной копии данных;

  • резервное копирование файлов WAL (Write Ahead Log) для обеспечения целостности данных;

  • восстановление данных из резервной копии;

  • восстановление на определенный момент времени (Point-in-Time Recovery или PITR);

  • интеграция с системами резервного копирования.

Резервное копирование экземпляра СУБД Pangolin осуществляется python-скриптом manage_backup.bin.

Этот скрипт автоматизирует вызовы стандартных функций управления резервным копированием PostgreSQL: pg_start_backup, pg_stop_backup.

При запуске скрипта создается отдельный процесс с подключением к libpq. Одновременно может быть выполнено только одно резервное копирование. Если существует старый сеанс резервного копирования, новое резервное копирование не будет запущено. Ошибки могут быть обнаружены в журнале postgres и в файле backup_manager.log в каталоге (по умолчанию /pgarclogs/[pangolin_<major_version>]) резервного копирования pg_probackup.

Пример:

/usr/local/pgsql/postgres_venv/bin/python3 manage_backup.py --host 127.0.0.1 -p 5432 -U user -d db -B <path_to_label_dir> --session-id=<SESS> start
# copy data from $PGDATA...
/usr/local/pgsql/postgres_venv/bin/python3 manage_backup.py --host 127.0.0.1 -p 5432 -U user -d db -B <path_to_label_dir> --session-id=<SESS> stop

Резервное копирование журналов предзаписи (WAL) в режиме онлайн осуществляется с помощью утилиты pg_probackup. Таким образом обеспечивается целостность резервной копии и возможность восстановления данных на любой момент времени (Point-in-Time Recovery, PITR).

Такая резервная копия позволяет активно использовать таблицы базы данных во время сеанса без каких-либо ограничений в использовании. Также при использовании СРК присутствует возможность выбирать между интерактивным и запланированным резервным копированием. Снятие полной резервной копии или архива WAL (журналов, накопившихся со времени последней резервной копии) может производиться в автоматизированном режиме с помощью клиентского приложения (агента) СРК с ведомого сервера кластера. Восстановление происходит по запросу вследствие инцидента либо запланированных работ и предполагает ручное указание параметров восстановления.

Более подробно о работе pg_probackup можно ознакомиться на страницах официальной документации проекта.

Доступные типы резервного копирования#

Доступны следующие типы резервного копирования:

  • полная резервная копия (включает все базы данных в экземпляре Pangolin);

  • резервное копирование транзакций (включает только файлы WAL, заархивированные со времени предыдущего полного резервного копирования или резервного копирования транзакций. Данные резервной копии транзакции являются необходимыми для успешного восстановления кластера с применением непрерывного архивирования, поэтому цепочка архивированных WAL-файлов так же должна быть непрерывной. Для восстановления экземпляра сначала используется полная резервная копия и затем подается последовательность архивных WAL-файлов для применения на экземпляре, что позволяет восстановить копию на необходимый момент времени).

Создание полной резервной копии:

  • инициализация процесса создания резервной копии агентом СРК или вручную;

  • исполнение pre-exec-скриптов;

  • копирование файлов БД;

  • копирование архива WAL;

  • исполнение post-exec-скриптов;

  • завершение резервного копирования.

Восстановление данных#

Pangolin поддерживает различные способы восстановления данных.

Перед восстановлением данных необходимо определить следующие аспекты процесса восстановления:

  • Область действия:

    • Восстановление всего экземпляра – в таком случае восстановление производится отдельно на каждый сервер, после чего выполняется синхронизация с помощью Pangolin Manager.

    • Восстановление ведомого сервера – в таком случае восстановление происходит из резервной копии на последний возможный момент времени.

  • Расположение восстанавливаемых данных:

    • Исходное расположение.

    • Другой путь на исходном клиенте.

    • Другой клиент (на него тоже потребуется установить Pangolin).

  • Восстановление на определенный момент времени при условии наличия соответствующей цепочки восстановления (включая полный образ резервной копии и резервную копию соответствующих файлов WAL):

    • На время последней резервной копии транзакции (откат до последнего возможного состояния).

    • На определенный момент времени по выбору (восстановление на момент времени с повтором).

    • На момент выбранного успешного полного или резервного копирования транзакции.

На момент восстановления из резервной копии СУБД должна быть остановлена.

Более подробно с работой Pangolin Manager можно ознакомиться на страницах официальной документации проекта.

Мониторинг резервных копий#

Функциональность мониторинга резервных копий реализована через расширение pgse_backup.

При установке расширения создаются следующие объекты:

  • схема backup;

  • представления для отображения истории и контроля резервных копий backup.data_history, backup.wal_history, backup.history;

  • таблица для хранения настроек backup.settings;

  • типы данных backup.data_history_row_type, backup.wal_history_row_type;

  • функции для наполнения представлений backup.read_data_history(), backup.read_wal_history(), backup.reset_history().

Для безопасного считывания файлов с историей (backup_state, wal_backup_state) используется функция Pangolin с атрибутом SECURITY DEFINER. Функция разрешает доступ к файлам с историей без прав суперпользователя, но в пределах строго фиксированного каталога, чтобы исключить доступ к чтению посторонних файлов. Директория, в которой хранятся файлы истории и предоставляется доступ через SECURITY DEFINER, задается через таблицу backup.settings. Данная таблица должна быть доступна только владельцу расширения (Администратору БД).

Информация в представлениях backup.data_history, backup.wal_history — результат работы функций backup.read_data_history и backup.read_wal_history. Данные функции через встроенную функцию PostgreSQL pg_read_file() читают файлы в формате json с историей резервного копирования, заполняемые утилитами manage_backup.bin и pg_probackup. Файлы с историей (backup_state, wal_backup_state) располагаются в каталоге резервного копирования (по умолчанию /pgarclogs/[pangolin_<major_version>] и указываются в таблице backup.settings).

postgres=# select * from backup.settings;
 name |    setting
------+---------------
 dir  | /pgarclogs/05
(1 row)

Итоговый результат сессии резервного копирования представляет собой сверку состояний из backup.data_history, backup.wal_history и доступен в backup.history, как на таблице ниже.

Состояние сессии DATA

Состояние сессии WAL

Итоговое состояние

starting

*

starting

started

*

started

stopping

*

stopping

failed

*

failed

completed

Хотя бы одна сессия WAL началась после окончания сессии DATA, включает в свой интервал stop_walfile и имеет состояние completed

completed

completed

Хотя бы одна сессия WAL началась после окончания сессии DATA, включает в свой интервал stop_walfile и имеет состояние started

wal_backup_started

completed

Не найдена ни одна подходящая сессия WAL

waiting_for_wal_backup

Ролевая модель#

Для интеграции с СРК может потребоваться выделенная роль для проведения процедуры резервного копирования со следующими разрешениями:

BEGIN;
CREATE ROLE BACKUP_USER WITH LOGIN;
GRANT USAGE ON SCHEMA pg_catalog TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_checkpoint() TO BACKUP_USER;
COMMIT;

Где:

BACKUP_USER – пользователь для возможности подключения к СУБД Pangolin со стороны СРК.

Архитектура#

Концептуальная архитектура Pangolin в части резервного копирования#

Концептуальная архитектура Pangolin в части резервного копирования

Схема процесса создания резервной копии Pangolin#

Схема процесса создания резервной копии Pangolin

Табличное описание процесса#

Наименование шага

Входной документ

Описание

Исполнитель

Характер изменений

Продолжительность

Выходной документ

ИТ-система

Переход к шагу

010 Инициация создания резервной копии

Инициация создания резервной копии по расписанию либо вручную по запросу

Инженер СРК или по расписанию

В зависимости от размера БД

СРК

020

020 Исполнение скрипта определяющего роль сервера

Исполнение заранее заданного скрипта, определяющего роль сервера в кластере Pangolin и запускающего необходимую спецификацию копирования

Автоматически

СРК

030

030 Исполнение pre-exec скриптов

Выполнение заранее заданных скриптов на целевом узле до создания резервной копии

Автоматически

Снятие резервной копии в локальный каталог резервных копий с помощью pg_probackup

СРК Pangolin

040

040 Копирование файлов БД

Копирует каталог Pangolin на серверы СРК, вносит информацию о резервной копии в Каталог

Автоматически

СРК

050

050 Копирование файлов WAL

Копирование архива файлов WAL на серверы СРК

Автоматически

Резервная копия БД

СРК

060

060 Исполнение post-exec скриптов

Выполнение заранее заданных скриптов на целевом узле после завершения копирования резервной копии

Автоматически

Удаление локальной резервной копии с помощью pg_probackup

СРК

070

070 Завершение резервного копирования

Завершение резервного копирования

Автоматически

СРК

Схема процесса восстановление Pangolin из резервной копии#

Схема процесса создания резервной копии Pangolin

Табличное описание процесса#

Наименование шага

Входной документ

Описание

Исполнитель

Характер изменений

ИТ-система

Переход к шагу

010 Инициация восстановления

Запрос операции восстановления

Инженер эксплуатации

Service Manager

020 или 025

020 Выбор экземпляра Pangolin и версии резервной копии для восстановления

Выбор PostgreSQL для восстановления и версии резервной копии для восстановления

Инженер СРК

СРК

030

025 Выбор КТС и версии резервной копии для восстановления

Выбор КТС для восстановления и версии резервной копии для восстановления

Инженер СРК

СРК

030

030 Проверка доступности носителей и устройств для восстановления

Проверка доступности копий и данных для восстановления

Автоматически

СРК

040

040 Установка параметров процесса восстановления

Выбор допустимой нагрузки на сеть, а также уровня логирования при восстановлении

Инженер СРК

СРК

050 или 060

050 Исполнение preexec скриптов

Выполнение preexec-скриптов

Автоматически

При необходимости

СРК

060

060 Копирование файлов резервной копии на узел

Копирование файлов резервной копии и архива WAL с серверов СРК на целевую систему в локальный каталог копий

Автоматически

СРК

070 или 080

070 Исполнение postexec скриптов

Выполнение postexec-скриптов

Автоматически

При необходимости

СРК

080

080 Запуск восстановления БД

Использование восстановление из локального каталога копий с помощью pg_probackup

Автоматически

Pangolin

090 или 100 или 110

090 Обновление ключа TDE

Администратор БД производит следующие действия:
- получает из резервной копии метку мастер-ключа, актуального на момент резервного копирования;
- получает из KMS мастер-ключ, актуальный на момент backup;
- получает из KMS мастер-ключ, актуальный на текущий момент;
- загружает ключи шифрования из резервной копии, перешифровав их

Администратор БД

Pangolin

110

100 Настройка параметров recovery_conf в файла Pangolin Manager

Настройка recovery_conf секции для успешного восстановления БД

Администратор БД

Pangolin

110

110 Запуск Pangolin Manager

Запуск службы Pangolin Manager

Администратор БД

Pangolin

Администрирование#

Настройка#

Проверка установленного расширения и утилит#

Pangolin изначально поставляется со всеми необходимыми установленными расширениями и утилитами для организации резервного копирования.

Проверка наличия расширения pgse_backup :

postgres=# select * from pg_extension where extname = 'pgse_backup';

  oid  |      extname       | extowner | extnamespace | extrelocatable | extversion |   extconfig   | extcondition
-------+--------------------+----------+--------------+----------------+------------+---------------+--------------
 16407 | pgse_backup        |       10 |        16404 | f              | 1.2        |               |
(1 row)

Из вывода видно, что расширение pgse_backup (oid 16407) установлено и готово к использованию.

Внимание!

С Pangolin совместима только та утилита pg_probackup, что идет в составе дистрибутива.

Проверка наличия утилиты pg_probackup:

$ which pg_probackup
/usr/pgsql-se-05/bin/pg_probackup

Утилита manage_backup.bin доступна в каталоге pg_backup инсталлятора и копируется в любое произвольное место на сервере с БД при интеграции Pangolin c СРК.

Настройка Pangolin для организации резервного копирования#

Установку и настройку необходимых для организации резервного копирования, расширения и утилит выполняет инсталлятор Pangolin в автоматическом режиме:

  1. Устанавливается утилита pg_probackup.

  2. Инициализируется локальный каталог резервных копий:

    pg_probackup init -B $PGBACKUP
    
  3. Определяется копируемый экземпляр (по умолчанию) резервных копий:

    pg_probackup add-instance -B $PGBACKUP -D $PGDATA --instance <название экземпляра>
    
  4. Устанавливаются параметры БД:

    wal_level = replica
    hot_standby = on
    full_pages_writes = on
    archive_mode = always
    archive_command = 'pg_probackup archive-push -B <локальный каталог копий> --instance <экземпляр> --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4'
    archive_timeout = 180
    
  5. Добавляются параметры работы pg_probackup:

    pg_probackup set-config -B $PGBACKUP -D $PGDATA --instance <название экземпляра> -d <имя_базы> -h <локальный сервер> -p <локальный порт> -U <имя_пользователя>
    
Интеграция с системой мониторинга#

В системе мониторинга используются следующие метрики:

Метрика

Запрос

Описание

backup completed count

SELECT count(state) FROM backup.history WHERE state = ‘completed’ AND start_time >= (now() - ‘1 day’::interval);

Возвращает количество успешных резервных копий за последние 24 часа

backup failed count

SELECT count(state) FROM backup.history WHERE state = ‘failed’ AND start_time >= (now() - ‘1 day’::interval);

Возвращает количество неуспешных резервных копий за последние 24 часа

backup wal failed count

SELECT count(state) FROM backup.wal_history WHERE state = ‘failed’ AND start_time >= (now() - ‘1 day’::interval);

Возвращает количество неуспешных резервных копий WAL-сессий за последние 24 часа

Если резервная копия снята успешно, то значение backup completed count будет больше 0, а значение backup wal failed count равно 0.

Состояние резервной копии на каждом экземпляре БД свое, поэтому при мониторинге необходимо опросить все узлы кластера, чтобы гарантировано получить самую последнюю резервную копию.

Управление#

Интерфейс просмотра истории резервных копий (РК)#
Просмотр истории полного цикла РК#

Для просмотра истории полного цикла РК создано специальное представление backup.data_history.

backup.data_history берет информацию из локального файла $PGBACKUP/backup_state и выводит его содержимое в виде таблицы:

postgres=# select * from backup.data_history;

 session_id |   state   | tli |       start_time       | start_lsn  |       stop_time        |  stop_lsn  | duration |       stop_walfile
------------+-----------+-----+------------------------+------------+------------------------+------------+----------+--------------------------
 FULL-16    | completed |  54 | 2020-11-13 01:52:22+03 | 4/5A000060 | 2020-11-13 01:52:31+03 | 4/5D000060 | 00:00:09 | 00000036000000040000005D
 FULL-16    | completed |  54 | 2020-11-13 01:53:05+03 | 4/5A000060 | 2020-11-13 01:53:11+03 | 4/5E000060 | 00:00:06 | 00000036000000040000005E

Где:

  • session_id - id сессии;

  • state - состояние сессии;

  • tli - timeline снятой копии;

  • start_time - начало выполнения сессии;

  • start_lsn - позиция WAL-сегмента при переходе БД в режим снятия РК;

  • stop_time - конец выполнения сессии;

  • stop_lsn - позиция WAL-сегмента при выходе БД из режима снятия РК;

  • duration - длительность сессии (end_time - start_time);

  • stop_walfile - конечный WAL-архив.

Просмотр истории РК промежуточных WAL#

Для просмотра истории резервных копий промежуточных WAL создано специальное представление backup.wal_history:

postgres=# select * from backup.wal_history ;
session_id |   state   |       start_time       |       stop_time        | duration |  info
------------+-----------+------------------------+------------------------+----------------
WAL-5      | completed | 2020-11-09 16:11:02+03 | 2020-11-09 16:11:04+03 | 00:00:02 |  [{"tli": 40, "parent_tli": 0, "switchpoint": "0/0", "min_segn
o": "000000280000000200000044", "max_segno": "00000028000000020000004E", "n_segments": 11, "size": 955436, "zratio": 193.16, "status": "ok", "lost_s
egments": []}]

Где:

  • session_id - id сессии СРК;

  • state - состояние сессии;

  • start_time - начало выполнения сессии;

  • stop_time - конец выполнения сессии;

  • duration - длительность сессии (end_time - start_time);

  • info - информация о хранящихся на диске архивах WAL (собирается на старте копирования с помощью pg_probackup).

В поле info помещается номер стартового и конечного архивов WAL. Если на диске отсутствуют промежуточные архивы — будет выведена ошибка, и в поле info.lost_segments будут записаны потерянные файлы.

Для мониторинга связанных сессий PGDATA и WAL используется представление backup.history. Оно учитывает представления backup.data_history и backup.wal_history. Состояние completed выставляется только тогда, когда для сессии PGDATA существует успешно завершенная сессия WAL, скопировавшая необходимый архив WAL (поле data_history.stop_walfile).

postgres=# select * from backup.history ;

session_id  |         state          | tli |       start_time       | start_lsn  |       stop_time        |  stop_lsn  | duration
------------+------------------------+-----+------------------------+------------+------------------------+------------+----------
FULL-5     | completed              |  40 | 2020-11-09 16:36:09+03 | 2/50000028 | 2020-11-09 16:46:59+03 | 2/5103C430 | 00:10:50
FULL-5     | completed              |  40 | 2020-11-09 16:47:01+03 | 2/53000028 | 2020-11-09 16:47:36+03 | 2/53000108 | 00:00:35
Автоматическая очистка истории старых резервных копий#

В файле backup_state хранится состояние нескольких резервных копий (по умолчанию последние 6).

Размер хранимой истории задается параметром утилиты manage_backup.bin: --rotate-history N - количество успешных (completed) резервных копий, хранимых в истории (0 - история не удаляется).

История сессий WAL удаляется автоматически, удаляются все записи старше самой старой сессии полного резервного копирования. Таким образом, история содержит все сессии WAL, связанные с текущими сессиями полного копирования.

Ручная очистка истории резервных копий#

Если файлы с историей резервных копий содержат данные в некорректном формате (например, в результате проблем с дисками), представления backup.*_history не смогут их прочитать. В таком случае будет выведена ошибка:

postgres=# select * from backup.history;
ERROR:  invalid input syntax for type json
DETAIL:  history file "/pgarclogs/05/backup_state" might be corrupted
HINT:  you may need to clean up all backup history with "SELECT backup.reset_history()" CONTEXT:  PL/pgSQL function backup.read_data_history() line 18 at RAISE

В случае возникновения этой ошибки можно воспользоваться механизмом ручной очистки истории. Для ручной очистки истории предусмотрена функция backup.reset_history(), доступная только администраторам БД:

postgres=# select backup.reset_history();
reset_history
---------------
(1 row)

После выполнения будут очищены сессии DATA и WAL. Также можно вручную удалить файлы /pgarclogs/05/backup_state и /pgarclogs/05/wal_backup_state или дождаться очередной сессии (DATA/WAL), которая сама очистит некорректные файлы.

Даже если файлы испорчены, сам процесс резервного копирования будет происходить без ошибок. В начале сессии испорченный файл перезапишется автоматически. Состояние старых резервных копий хранится в журнале /pgarclogs/05/backup_manager.log.

Если файлов backup_state и wal_backup_state не существует, соответствующие представления выполнятся без ошибок и вернут пустые наборы строк.

Утилита manage_backup.bin#

Утилита имеет следующие ключи:

usage: manage_backup.bin [-h] -B label_dir --host host -p port -d database -U
user [--password password] [--session-timeout sec]
[--start-timeout sec] [--stop-timeout sec]
[--patroni-host patroni_host]
[--patroni-port patroni_port]
[--rotate-history rotate_history] --session-id
session_id
action

Устранение неисправностей#

Ошибки, возникающие в процессе копирования, заносятся в журнал Pangolin, в приложение backup_session и в файл backup_manager.log в каталоге резервного копирования.

При нештатном прерывании процедуры резервного копирования (например, при отключении сервера) может возникнуть ситуация, при которой незавершенная копия останется в промежуточном состоянии. Такая процедура считается неуспешной (эквивалентной failed). В начале следующей сессии резервного копирования такие зависшие состояния будут автоматически переведены в failed.

Сообщения системного журнала опционально в формате вывода поддерживаемом функциональностью.

Безопасность#

Для проведения процедуры резервного копирования в Pangolin существует выделенная роль со следующими разрешениями:

BEGIN;
CREATE ROLE BACKUP_USER WITH LOGIN;
GRANT USAGE ON SCHEMA pg_catalog TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO BACKUP_USER;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_checkpoint() TO BACKUP_USER;
COMMIT;

Где:

BACKUP_USER - пользователь для возможности подключения к СУБД Pangolin со стороны СРК.

Роль BACKUP_USER имеет атрибут LOGIN, тем самым ей разрешена авторизация на сервере Pangolin. По умолчанию после инсталляции в конфигурационной секции pg_hba для роли BACKUP_USER определено правило: host all backup_user 0.0.0.0/0 scram-sha-256.

Пароль для этой роли задается при инсталляции с помощью переменной pg_backup_user_passwd в предустановочном конфигурационном файле custom_file_template.yml. Пароль должен удовлетворять парольной политике Pangolin. После инсталляции хеш пароля хранится в системной таблице pg_authid.

Для обеспечения безопасности критичных данных в резервных копиях в СУБД Pangolin используется прозрачное шифрование данных (TDE) (см. раздел «Прозрачное шифрование»). При включенном механизме шифруются данные, которые находятся в файлах данных, резервных копиях и временных файлах баз данных, а также данные, передаваемые по каналам связи в ходе физической и логической репликации.

Для шифрования сетевого трафика между клиентом и сервером в Pangolin встроена поддержка SSL, по умолчанию ssl = on.

Описание объектов#

Схемы#

CREATE SCHEMA backup;

Таблицы#

Имя столбца

Тип

Описание

name

text

Поле, в котором содержится тип настройки (в данный момент он единственный и называется 'dir')

setting

text

Путь к каталогу на файловой системе, где будут храниться архивы

CREATE TABLE backup.settings(name text, setting text);
INSERT INTO backup.settings(name, setting) VALUES ('dir', '/pgarclogs/' ||
-- get major version (11, 12, ...)
(SELECT split_part((SELECT setting FROM pg_settings WHERE name = 'server_version'), '.', 1)));

Типы#

CREATE TYPE backup.data_history_row_type AS (
session_id text,
state text,
tli integer,
start_time text,
start_lsn text,
stop_time text,
stop_lsn text,
duration text,
stop_walfile text COLLATE "C"
);
CREATE TYPE backup.wal_history_row_type AS (
session_id text,
state text,
start_time text,
stop_time text,
duration text,
info json
);

Функции#

CREATE OR REPLACE FUNCTION backup.read_data_history()
RETURNS SETOF backup.data_history_row_type AS
$$
DECLARE
filename text;
json_data text;
BEGIN
filename := (SELECT setting FROM backup.settings WHERE name = 'dir') || '/backup_state';
json_data := replace(trim(pg_read_file(filename)), e'\n', '');
if (json_data = '') is not false then
return;
end if;

    return QUERY SELECT * FROM json_populate_recordset(null::backup.data_history_row_type, json_data::json);

EXCEPTION
WHEN undefined_file THEN
return;
WHEN invalid_text_representation THEN
RAISE EXCEPTION '%', SQLERRM
USING DETAIL = format('history file "%s" might be corrupted', filename),
HINT = 'you may need to clean up all backup history with "SELECT backup.reset_history()"';
END;
$$
LANGUAGE plpgsql SECURITY DEFINER;
CREATE OR REPLACE FUNCTION backup.read_wal_history()
RETURNS SETOF backup.wal_history_row_type AS
$$
DECLARE
filename text;
json_data text;
BEGIN
filename := (SELECT setting FROM backup.settings WHERE name = 'dir') || '/wal_backup_state';
json_data := replace(trim(pg_read_file(filename)), e'\n', '');
if (json_data = '') is not false then
return;
end if;

    return QUERY SELECT * FROM json_populate_recordset(null::backup.wal_history_row_type, json_data::json);

EXCEPTION
WHEN undefined_file THEN
return;
WHEN invalid_text_representation THEN
RAISE EXCEPTION '%', SQLERRM
USING DETAIL = format('history file "%s" might be corrupted', filename),
HINT = 'you may need to clean up all backup history with "SELECT backup.reset_history()"';
END;
$$
LANGUAGE plpgsql SECURITY DEFINER;
CREATE OR REPLACE FUNCTION backup.reset_history()
RETURNS void AS
$x$
DECLARE
dir text := (SELECT setting FROM backup.settings WHERE name = 'dir');
data_dir text := dir || '/backup_state';
wal_dir text := dir || '/wal_backup_state';
BEGIN
EXECUTE format('COPY (SELECT '''') TO %L', data_dir);
EXECUTE format('COPY (SELECT '''') TO %L', wal_dir);
END;
$x$
LANGUAGE plpgsql SECURITY DEFINER;

Представления#

Представление backup.data_history – просмотр истории полного цикла РК. Берет информацию из локального файла $PGBACKUP/backup_state и выводит его содержимое в виде таблицы.

Имя столбца

Тип

Описание

session_id

text

Уникальный идентификатор сессии

state

text

Состояние сессии

tli

integer

Номер линии времени снятой копии

start_time

text

Начало выполнения сессии

start_lsn

text

Позиция WAL сегмента при переходе БД в режим снятия РК

stop_time

text

Конец выполнения сессии

stop_lsn

text

Позиция WAL сегмента при выходе БД из режима снятия РК

duration

text

Длительность сессии (stop_time - start_time)

stop_walfile

text

Конечный WAL архив

CREATE VIEW backup.data_history AS
SELECT
s.session_id,
s.state,
s.tli,
TO_TIMESTAMP(s.start_time, 'YYYY-MM-DD HH24:MI:SS') as start_time,
s.start_lsn,
TO_TIMESTAMP(s.stop_time, 'YYYY-MM-DD HH24:MI:SS') as stop_time,
s.stop_lsn,
TO_TIMESTAMP(s.stop_time, 'YYYY-MM-DD HH24:MI:SS')
- TO_TIMESTAMP(s.start_time, 'YYYY-MM-DD HH24:MI:SS') as duration,
s.stop_walfile
FROM backup.read_data_history() AS s;

Представление backup.wal_history – для просмотра истории резервных копий (РК), промежуточных WAL.

Имя столбца

Тип

Описание

session_id

text

Уникальный идентификатор сессии

state

text

Состояние сессии

start_time

text

Начало выполнения сессии

stop_time

text

Конец выполнения сессии

duration

text

Длительность сессии (stop_time - start_time)

info

json

Информация о хранящихся на диске архивах WAL (собирается на старте копирования с помощью pg_probackup) В поле info помещается номер стартового и конечного архивов WAL. Если на диске отсутствуют промежуточные архивы — будет выведена ошибка, и в поле info.lost_segments будут записаны потерянные файлы

CREATE VIEW backup.wal_history AS
SELECT
s.session_id,
s.state,
TO_TIMESTAMP(s.start_time, 'YYYY-MM-DD HH24:MI:SS') as start_time,
TO_TIMESTAMP(s.stop_time, 'YYYY-MM-DD HH24:MI:SS') as stop_time,
TO_TIMESTAMP(s.stop_time, 'YYYY-MM-DD HH24:MI:SS')
- TO_TIMESTAMP(s.start_time, 'YYYY-MM-DD HH24:MI:SS') as duration,
s.info
FROM backup.read_wal_history() AS s;

Представление backup.history – для просмотра состояния резервных копий (РК).

Имя столбца

Тип

Описание

session_id

text

Уникальный идентификатор сессии

state

text

Состояние сессии

tli

integer

Номер линии времени снятой копии

start_time

text

Начало выполнения сессии

start_lsn

text

Позиция WAL сегмента при переходе БД в режим снятия РК

stop_time

text

Конец выполнения сессии

stop_lsn

text

Позиция WAL сегмента при выходе БД из режима снятия РК

duration

text

Длительность сессии (stop_time - start_time)

CREATE VIEW backup.history AS
SELECT
d.session_id,
-- $PGDATA has been successfully backed up, look for a valid WAL backup
CASE WHEN d.state = 'completed' THEN
COALESCE(
-- WAL backup done successfully -> mark full backup record as 'completed'
(SELECT 'completed' FROM backup.wal_history w
WHERE
w.state = 'completed' AND
w.start_time >= d.stop_time AND
d.stop_walfile >= w.info -> d.tli::text ->> 'min_segno' AND
d.stop_walfile <= w.info -> d.tli::text ->> 'max_segno' LIMIT 1),
-- WAL backup has not been completed yet, but WAL session was started -> show this in our history
(SELECT 'wal_backup_started' FROM backup.wal_history w
WHERE
w.state = 'started' AND
w.start_time >= d.stop_time AND
d.stop_walfile >= w.info -> d.tli::text ->> 'min_segno'::text COLLATE "C" AND
d.stop_walfile <= w.info -> d.tli::text ->> 'max_segno'::text COLLATE "C" LIMIT 1),
-- WAL backup has not been started (or some WAL session failed) -> show that we are currently waiting for a session
'waiting_for_wal_backup')
ELSE d.state END as state,
d.tli,
d.start_time,
d.start_lsn,
d.stop_time,
d.stop_lsn,
d.duration
FROM backup.data_history d;

Развертывание на КТС#

Ниже перечислены операции, которые должны быть выполнены при развертывании на КТС, на которых будут располагаться БД. Данные действия выполняются в автоматическом режиме при развертывании инсталлятором.

  1. Создайте директорию PGBACKUP: /pgbackup/13.

  2. Установите pg_probackup.

  3. Создайте локальный каталог резервных копий: pg_probackup-13 init -B $PGBACKUP. В случае, если каталог не пустой, операция завершится с ошибкой, поэтому перед установкой каталог должен быть очищен.

  4. Определите копируемый экземпляр резервных копий: pg_probackup-13 add-instance -B $PGBACKUP -D $PGDATA --instance <название экземпляра>.

  5. Установите параметры БД:

    wal_level = replica
    hot_standby = on
    full_pages_writes = on
    archive_mode = always
    archive_command = 'pg_probackup-13 archive-push -B <локальный каталог копий> --instance <экземпляр> --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4'
    archive_timeout = 180
    
  6. Добавьте параметры работы pg_probackup: pg_probackup-13 set-config -B $PGBACKUP -D $PGDATA --instance <название экземпляра> -d <имя_базы> -h <локальный сервер> -p <локальный порт> -U <имя_пользователя>.

Примечание:

Установка СРК посредством ДИ выполняется автоматически.

Ролевая модель#

В силу особенностей работы Data Protector необходима выделенная роль для проведения процедуры резервного копирования со следующими разрешениями:

        BEGIN;
CREATE ROLE masteromni WITH LOGIN;
GRANT USAGE ON SCHEMA pg_catalog TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.current_setting(text) TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_is_in_recovery() TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_start_backup(text, boolean, boolean) TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_stop_backup(boolean, boolean) TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_create_restore_point(text) TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_switch_wal() TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_last_wal_replay_lsn() TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current() TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_current_snapshot() TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.txid_snapshot_xmax(txid_snapshot) TO masteromni;
GRANT EXECUTE ON FUNCTION pg_catalog.pg_control_checkpoint() TO masteromni;

        COMMIT;

В файле pg_hba.conf необходимо разрешить подключение к кластеру баз данных пользователю с именем masteromni.

Восстановление БД из резервной копии#

Внимание!

Для восстановления необходима новая чистая установка Pangolin, полученная в ДИ либо созданная вручную. При наличии доступа к изначальному кластеру, проверить, что полная резервная копия существует:

SELECT * FROM backup.history;

Внимание!

Ниже по тексту используются в качестве параметров clustername и new_clustername. Это общие обозначения, которые необходимо заменить действительными. Получить их можно, например, командой:

etcdctl ls /service

clustername - имя кластера на новом сервере, new_clustername - имя кластера для сервера, с которого снята резервная копия.

system-identifier для файла pg_probackup.conf можно получить на сервере, с которого снята резервная копия командой (clustername в данном случае нужно заменить на имя кластера):

etcdctl get /service/clustername/initialize

Для восстановления БД кластера cluster-patroni-etcd-pgbouncer из резервной копии:

  1. Остановите сервис Pangolin Manager сначала на реплике, потом на лидере:

    sudo systemctl stop pangolin-manager
    
  2. Очистите каталоги data и tablespaces на реплике и лидере:

    rm -rf /pgdata/04/data
    rm -rf /pgdata/04/tablespaces
    
  3. Очистите хранилище etcd (clustername замените на действительное имя кластера):

    etcdctl rm -r /service/clustername
    
  4. Исправьте конфигурационный файл Pangolin Manager (clustername и new_clustername замените на действительные лидера и реплику, добавьте секцию recovery_conf на лидере):

    scope: new_clustername
    …
    …
    …
    parameters:
    archive_mode: 'always'
    archive_command: '/usr/pgsql-se-04/bin/pg_probackup archive-push -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4 --batch-size=100'
    …
    …
    …
    wal_sync_method: 'fsync'
    work_mem: '16384kB'
    …
    …
    is_tde_on: 'off'
    recovery_conf:
    recovery_target_timeline: latest
    standby_mode: off
    restore_command: /usr/pgsql-se-04/bin/pg_probackup archive-get -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f -j 4 --batch-size=100
    …
    …
    …
    
  5. Восстановите на новый сервер со старого каталоги /pgarclogs/04, /pgdata/04/data, /pgdata/04/tablespaces.

  6. Скопируйте файл /pgarclogs/04/backups/clustername/pg_probackup.conf в /pgarclogs/04/backups/new_clustername/pg_probackup.conf и исправьте в нем system-identifier (clustername и new_clustername замените на действительные имена кластеров):

    # Backup instance information
    pgdata = /pgdata/04/data
    system-identifier = 6855546122949875180
    xlog-seg-size = 16777216
    # Connection parameters
    pgdatabase = postgres
    pghost = 10.110.34.117
    pgport = 5433
    pguser = backup_user
    

    Примечание:

    IP-адрес и порт (pghost и pgport) указаны в качестве примера.

  7. Запустите сервис Pangolin Manager на лидере и убедитесь, что БД запущена и загружаются файлы журналов:

    sudo systemctl start pangolin-manager
    less /pgerrorlogs/clustername/postgresql.log
    
  8. Запустите сервис Pangolin Manager на реплике, дождитесь синхронизации и убедитесь, что кластер перешел в синхронный режим:

    sudo systemctl start pangolin-manager
    patronictl -c /etc/pangolin-manager/postgresql.yml list
    

Восстановление типа инсталляции standalone-patroni-etcd-pgbouncer#

  1. Остановите сервис Pangolin Manager:

    sudo systemctl stop pangolin-manager
    
  2. Очистите каталоги data и tablespaces:

    rm -rf /pgdata/05/data
    rm -rf /pgdata/05/tablespaces
    
  3. Очистите хранилище etcd (clustername замените на действительное имя кластера):

    etcdctl rm -r /service/clustername
    
  4. Исправьте конфигурационный файл pangolin-manager (clustername и new_clustername замените на действительные, добавьте секцию recovery_conf):

    scope: new_clustername
    parameters:
      archive_mode: 'always'
      archive_command: '/usr/pgsql-se-04/bin/pg_probackup archive-push -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4 --batch-size=100'
      wal_sync_method: 'fsync'
      work_mem: '16384kB'
      is_tde_on: 'off'
    recovery_conf:
      standby_mode: off
      restore_command: /usr/pgsql-se-04/bin/pg_probackup archive-get -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f -j 4 --batch-size=100
    
  5. Восстановите на новый сервер со старого каталоги /pgbackup/05, /pgdata/05/data, /pgdata/05/ts (ЗНО на СРК).

  6. Скопируйте файл /pgbackup/04/backups/clustername/pg_probackup.conf в /pgbackup/05/backups/new_clustername/pg_probackup.conf и исправьте в нем system-identifier (clustername и new_clustername замените на действительные имена кластеров):

    # Backup instance information
    pgdata = /pgdata/04/data
    system-identifier = 6855546122949875180
    xlog-seg-size = 16777216
    # Connection parameters
    pgdatabase = postgres
    pghost = 10.110.34.117
    pgport = 5433
    pguser = backup_user
    
  7. Запустите сервис Pangolin Manager и убедитесь, что БД запустилась и загружаются файлы журналов (в логах отсутствуют ошибки проигрывания WAL-файлов):

    sudo systemctl start pangolin-manager
    less /pgerrorlogs/clustername/postgresql.log
    

Восстановление типа инсталляции standalone-postgresql-only или standalone-postgresql-pgbouncer#

Примечание:

Различий в восстановлении типов кластера standalone-postgresql-only и standalone-postgresql-pgbouncer нет.

  1. Остановите сервис PostgreSQL :

    sudo systemctl stop postgresql.service
    
  2. Очистите каталоги data и tablespaces:

    rm -rf /pgdata/05/data
    rm -rf /pgdata/05/tablespaces
    
  3. Создайте конфигурационный файл recovery.conf:

    recovery_target_timeline = 'latest'
    restore_command = '/usr/pgsql-se-04/bin/pg_probackup archive-get -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f -j 4 --batch-size=100'
    
  4. Восстановите на новый сервер со старых каталогов /pgbackup/05, /pgdata/05/data, /pgdata/05/ts (ЗНО на СРК).

  5. Скопируйте файл /pgbackup/04/backups/clustername/pg_probackup.conf в /pgbackup/04/backups/new_clustername/pg_probackup.conf и исправьте в нем system-identifier (clustername и new_clustername замените на действительные имена кластеров):

    # Backup instance information
    pgdata = /pgdata/04/data
    system-identifier = 6855546122949875180
    xlog-seg-size = 16777216
    # Connection parameters
    pgdatabase = postgres
    pghost = 10.110.34.117
    pgport = 5433
    pguser = backup_user
    
  6. Запустите сервис PostgreSQL, чтобы убедиться что БД запустилась, и загружаются файлы журналов (в логах отсутсвуют ошибки проигрывания WAL-файлов):

    sudo systemctl start postgresql.service
    less /pgerrorlogs
    /clustername/postgresql.log
    

Восстановление сервера реплики из резервной копии#

  1. Остановите сервис pangolin-manager на реплике:

    sudo systemctl stop pangolin-manager
    
  2. Очистите каталоги data и tablespaces на реплике:

    rm -rf /pgdata/04/data
    rm -rf /pgdata/04/tablespaces
    
  3. Исправьте конфигурационный файл pangolin-manager (добавьте секцию recovery_conf):

    parameters:
      archive_mode: 'always'
      archive_command: '/usr/pgsql-se-04/bin/pg_probackup archive-push -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4 --batch-size=100'
      wal_sync_method: 'fsync'
      work_mem: '16384kB'
      is_tde_on: 'off'
    recovery_conf:
      recovery_target_time: latest
      standby_mode: off
      restore_command: /usr/pgsql-se-04/bin/pg_probackup archive-get -B /pgarclogs/04 --instance new_clustername --wal-file-path=%p --wal-file-name=%f -j 4 --batch-size=100
    

    Внимание!

    Вероятно, проигранных WAL-файлов будет недостаточно для того, чтобы догнать ведущий сервер, если нагрузка на ведущий сервер продолжает подаваться. Необходимо запросить внеочередное снятие резервной копии WAL-файлов ведущего сервера, а так же настроить синхронизацию директорий с помощью lsyncd.

  4. Восстановите на новый сервер со старого каталоги /pgbackup/05, /pgdata/05/data, /pgdata/05/ts (ЗНО на СРК).

  5. Запустите сервис pangolin-manager и убедитесь, что БД запустилась и загружаются файлы журналов, дождитесь синхронизации и убедитесь, что кластер перешел в синхронный режим:

    sudo systemctl start pangolin-manager
    less /pgerrorlogs/clustername/postgresql.log
    

Шаблон параметров формирования SRC спецификаций для резервного копирования#

Ниже приведен пример шаблона параметров формирования SRC спецификаций для резервного копирования (файл datalist_serveraXserverb_RUN_PG_FULL.j2, где servera - имя мастера-сервера, serverb - имя реплицирующего сервера):

DATALIST "hostname-serveraXhostname-serverb_RUN_PG_FULL"`
GROUP "DININFRA"
DESCRIPTION "PostgreSQL_SE"
RECONNECT
DYNAMIC 1 1
POSTEXEC "patroni_session_run.sh" -on_host "{{ data_protector_host }}"
DEFAULTS
{
    FILESYSTEM
    {
        -vss    no_fallback
    } -protect days 3
    RAWDISK
    {

    }
}

DEVICE "{{ device }}"
{
}

FILESYSTEM "fqdn-servera" fqdn-serverb:"/"
{
    -trees
        "/etc/opt/omni/client/cell_server"
}

FILESYSTEM "fqdn-serverb" fqdn-serverb:"/"
{
    -trees
        "/etc/opt/omni/client/cell_server"
}

А также шаблон формирования расписания создания резервной копии (файл schedule_serveraXserverb_RUN_PG_FULL.j2, где servera - имя мастер-сервера, serverb - имя реплицирующего сервера):

-full
-every
     -day
     -at {{ (23,0,1,2) |random }}:{{ '%02d' | format( 59 | random | int )}}

Снятие резервной копии с реплики#

Функция резервного копирования позволяет снять с базы данных архивную копию, которую в дальнейшем можно использовать для восстановления. PostgreSQL поддерживает создание резервной копии как с лидера, так и с реплики.

Резервное копирование выполняется следующей командой:

PGPASSWORD={backup_pass} pg_probackup backup -B {PGBACKUP} --instance {cluster_name} -b FULL

Восстановление из резервной копии выполняется следующей командой:

pg_probackup restore -B {PGBACKUP} --instance {cluster_name} --recovery-target='latest

Процедуры резервного копирования на главном сервере и на копии принципиально идентичны.

Мониторинг блокировок#

Для оперативного мониторинга заблокированных объектов предусмотрен отдельный инструмент psql_lockmon.

Механизм отслеживания блокировок представляет собой набор представлений, позволяющий проводить оперативный мониторинг блокировок в разрезе:

  • заблокированных объектов;

  • типов блокировок;

  • параметров сессии, которая заблокировала объект (при наличии прав);

  • длительности сессий, запросов, ожидания блокировок, смены статуса (при наличии прав);

  • текста последнего запроса в сессии (при наличии прав);

  • дерева блокировок, при наличии очереди заблокированных объектов.

Поставка механизма отслеживания блокировок производится в виде расширения psql_lockmon.

Предусмотрена автоматизация развертывания решения на уровне специализированного сценария (custom.yml). Решение по умолчанию устанавливается в БД пользователя и в шаблонную БД.

Управление учетными записями#

Учетные записи пользователей и технические учетные записи создаются, удаляются и изменяются администраторами безопасности и администраторами Pangolin.

Разрешения для учетных записей регулируются политиками, которые определяют права доступа той или иной роли к объектам базы данных.

Парольные политики описываются в документе «Список PL/SQL функций продукта» раздел «Функции для работы с парольными политиками».

Разграничение доступа к данным#

В этом разделе описываются механизмы разграничения доступа к данным(включая функции маскирования, хеширования и т.п).

Управление доступом на уровне ролей (RBAC)#

Система ограничивает доступ пользователей к объектам БД в зависимости от их роли и привилегий, которые назначены для этой роли.

Подробнее в разделе «Ролевая модель и права доступа».

Row level security#

Механизм ограничения доступа пользователей к отдельным строкам в таблицах.

Защита от привилегированных пользователей#

В Pangolin используется механизм защиты данных от привилегированных пользователей, построенный на принципе разделения ролей.

В стандартном PostgreSQL привилегированные пользователи имеют доступ к объектам БД и настройкам подключения:

  • администраторы БД имеют произвольный доступ к любым пользовательским данным, что может привести к утечкам конфиденциальной информации;

  • администраторы ОС могут менять настройки БД таким образом, чтобы получать доступ к пользовательским данным, что тоже ведет к утечкам.

В Pangolin Администраторы БД и ОС теряют возможность самостоятельно управлять некоторыми параметрами и перестают иметь полный доступ ко всем объектам БД.

В дополнение к роли суперпользователя, которая есть в стандартной версии PostgreSQL, в Pangolin можно создать специальную роль Администратора безопасности (АБ).

АБ – независимый администратор, не обладающий особыми правами в операционной системе (в том числе не имеющий прав Linux-пользователя postgres) и не имеющий доступа к объектам БД. Внутри БД роль Администратора безопасности является особенной — она не может быть изменена суперпользователем. Таким образом, ни один из пользователей не может единолично получить доступ к конфиденциальным данным или изменить важные для безопасности настройки БД и права доступа.

Администратор безопасности создается при инициализации кластера, либо существующим администратором безопасности через функцию pm_grant_security_admin.

Примечание:

Для модификации защиты и предоставления прав доступа доступны только объекты, расположенные в базе, к которой осуществлено подключение.

При защите схемы целиком права на доступ к объектам выдаются на все объекты заданного типа, находящиеся в защищенной схеме.

В случае если необходимо выделить права доступа к какому-то конкретному объекту в защищенной схеме, этот объект ставится под индивидуальную защиту. Настройка доступа к такому объекту происходит без учета защиты схемы, в которой этот объект расположен.

Внимание!

При включенном механизме защиты от привилегированных пользователей прямая модификация записей в системных каталогах, относящихся к защищаемым объектам, запрещена.

Имеется опасность свободного использования расширения pageinspect и схожих с ним на БД с включенной защитой от привилегированных пользователей, в связи с тем что pageinspect позволяет посмотреть расшифрованные данные и не учитывает защиту от привилегированных пользователей.

Ниже описаны основные функции, подробнее о функциях в «Список PL/SQL функций продукта», раздел «Защита от привилегированных пользователей».

Помещение объекта под защиту#

Для защиты пользовательских данных, хранимых в объектах базы, можно поставить объект под защиту с помощью функции pm_protect_object, например:

SELECT pm_protect_object('role', 'u1');

При включенной защите от привилегированных пользователей функция pm_protect_object при помещении под защиту объекта типа «роль» выполняет завершение открытых сессий указанного пользователя, исходно открытых другой ролью (случаи set role, set session authorization), где роль выступает как session_user либо как current_user, если исходный пользователь не имеет права на переключение на эффективную роль сессии в соответствии с текущим состоянием каталогов безопасности.

Снятие защиты с объекта#

В случае, если защита более не требуется, она может быть снята вызовом функции pm_unprotect_object, например:

SELECT pm_unprotect_object('table','ext.t1');

Получение доступа к защищенному объекту#

При включенной защите от привилегированных пользователей функция вывода объекта из-под защиты pm_unprotect_object не снимает защиту с администраторов безопасности, до исключения их из роли sec_admin_role, и групповой роли администраторов безопасности sec_admin_role, поднимая ошибку с сообщением «Can't remove protection for a security administrator's role».

Получить список всех объектов, находящихся под защитой#

Чтобы получить список всех объектов, находящихся под защитой, нужно вызвать функцию pm_get_protected_objects.

pm_get_protected_objects()

При включенной защите от привилегированных пользователей функция pm_get_protected_objects возвращает в результате выполнения поля:

  • state OID - состояние защиты объекта. Не NULL означает приостановленную защиту объекта;

  • staterole OID - роль для которой изменено состояние защиты объекта.

Доступ к защищенному объекту#

Доступ к объекту, находящемуся под защитой, запрещен всем пользователям, включая владельца и суперпользователя.

Для осуществления доступа к таким объектам создаются политики доступа через функцию pm_make_policy, и наполняются правилами доступа к объекту (какие действия над объектом разрешены для выполнения).

Пример создания политики:

SELECT pm_make_policy('pol1');

Функция pm_grant_to_policy добавляет правило в политику, например:

SELECT pm_grant_to_policy('pol1', 'table', 'ext.t1', array['select','update']::name[]);

Назначение политики пользователю#

Политика может быть назначена пользователю с помощью функции pm_assign_policy_to_user. Он получит разрешение на выполнение действий над защищенными объектами согласно правилам назначенной политики.

Пример назначения политики пользователю:

SELECT pm_assign_policy_to_user('u1', 'pol1');

Пользователю может быть назначено любое количество политик, и они могут содержать правила доступа к различным объектам.

Изъятие выданных прав доступа#

Изъятие ранее выданных прав доступа может осуществляться двумя способами:

  • вызовом функции pm_unassign_policy_from_user (единовременный отзыв всех правил политики), например:

    SELECT pm_unassign_policy_from_user('u1','pol1');
    
  • удалением конкретных правил из указанной политики при помощи функции pm_revoke_from_policy, например:

    SELECT pm_revoke_from_policy('pol1', 'function', 'public.f1', array['call', 'drop', 'alter']::name[]);
    

Помещение всех объектов схемы под защиту#

Тип объектов schema помещается под защиту функциями интерфейса администратора безопасности. При этом все объекты, находящиеся в схеме, автоматически считаются защищенными. Операции изменения и удаления непосредственно самой защищенной схемы могут быть выданы через настройку политик функциями интерфейса администратора безопасности.

Функциональность наполнения политик доступа правилами, разрешающими выполнение действий не над конкретным объектом, а над типом объектов в защищенной схеме, использует ту же функцию pm_grant_to_policy, что и при работе с защитой конкретных объектов, однако, имеет отличный синтаксис для параметра, задающего объект:

SELECT pm_grant_to_policy('имя_политики',  'тип_объекта', 'имя_схемы.*', array['действие1', ..., 'действиеN']::name[]);

Примечание:

Символ * после имени схемы означает применимость этого правила ко всем объектам заданного типа в данной схеме, как к существующим на момент определения правила, так и ко вновь добавляемым в данную схему.

Пример обобщенного правила для действия SELECT над всеми таблицами в защищенной схеме myschema:

SELECT pm_grant_to_policy('schema_objects_policy', 'table', 'myschema.*', array['select']::name[]);

Объект в защищенной схеме может находиться под индивидуальной защитой. В этом случае настройка доступа к нему производится без учета защиты схемы в которой объект расположен.

Предоставление доступа ко всем объектам защищенной схемы#

Исходя из ранее созданных политик и логики приложения, определите необходимость отдельной политики для предоставления доступа к защищенной схеме. В случае необходимости создайте новые политики доступа к защищенным объектам (pm_make_policy). Затем наполните политику правилами доступа (pm_grant_to_policy). Для этого добавьте в политику правила доступа для всех таблиц (партиций, представлений, функций) схемы (см. пример и примечание в предыдущем подразделе). С помощью команды pm_assign_policy_to_user, назначьте наполненную правилами доступа политику пользователям.

Предоставление доступа к объекту в защищенной схеме#

Для предоставления доступа к отдельному объекту в защищенной схеме необходимо определить тип защиты объекта, если:

  • объект под защитой — политики, разрешающие доступ к объекту, содержат правила доступа только к данному объекту БД;

  • объект под защитой через схему — доступ к объекту предоставляется политиками, содержащими правила доступа ко всем объектам данного типа в схеме.

После определения типа защиты необходимо наполнить политику правилами, при этом, если:

  • объект под защитой: наполните политику правилами доступа к конкретному объекту;

  • объект под защитой через схему: наполните политику правилами доступа ко всем объектам данного типа, находящимся в защищенной схеме.

В случае предоставления доступа к объекту в защищенной схеме необходимо назначить политику с правами доступа на выполнение действий над объектом пользователю БД.

Перенос объекта из защищенной схемы#

Перенос объектов из защищенной схемы в другую невозможен, так как нет гарантии сохранения согласованности правил доступа к переносимому объекту. Таким образом, при необходимости переноса объекта в другую схему с сохранением защиты этого объекта, переносимый объект должен быть помещен под индивидуальную защиту, а правила доступа должны быть настроены индивидуально для переносимого объекта. При достаточности правил доступа целевой схемы (если она под защитой) для типа объектов, соответствующего типу перенесенного объекта, индивидуальная защита с объекта может быть снята.

Обращение к объекту БД#

Выполнение запроса, содержащего обращение к объекту БД, происходит, если имеются права на доступ к объекту или на доступ к типу объектов защищенной схемы.

Механизм защиты данных проверяет выполнение хотя бы одного из двух условий:

  • нахождение запрашиваемого объекта под защитой и наличие у субъекта (пользователя) разрешений на выполнение действия над объектом БД;

  • нахождение схемы, содержащей запрашиваемый объект, под защитой и наличие у субъекта (пользователя) разрешений на выполнение действия над данным типом объектов БД.

Если проверка пройдена и есть права на доступ, запрашивающей стороне будет возвращен результат выполнения запроса. В случае отсутствия прав на доступ, запрос завершится ошибкой.

Параметры настройки, управляемые администраторами безопасности через KMS в режиме защищенного конфигурирования, находятся в таблице документа «Параметры, настраиваемые через KMS».

Назначить пользователю политики администратора безопасности#

Функция pm_grant_security_admin назначает пользователю политики администратора безопасности.

Формат:

pm_grant_security_admin(role_name name)

Входные параметры:

  • role_name (name) — имя пользователя.

Пример:

Команда:

SELECT pm_grant_security_admin('u1');

При включенной защите от привилегированных пользователей функция pm_grant_security_admin:

  • проверяет пользовательскую роль на наличие опции SUPERUSER или вхождение в любую роль, отличную от sec_admin_role. При наличии такой опции или роли, поднимается ошибка с сообщением о невозможности назначить такого пользователя администратором безопасности;

  • для указанного пользователя устанавливаются опции LOGIN, NOINHERIT, IN ROLE sec_admin;

  • указанному пользователю устанавливает изменение его роли при логине на sec_admin_role.

Указанному пользователю-администратору безопасности выдает политику secAdminUser. Также для пользователя не устанавливаются (снимаются, если есть) ограничения на время действия пароля через VALID UNTIL. Сама функция помещается под защиту утилитой initprotection. Привилегия на ее выполнение включается в политику для роли sec_admin_role в initprotection.

Снять с пользователя политики администратора безопасности#

Функция pm_revoke_security_admin снимает с пользователя политики администратора безопасности.

Формат:

pm_revoke_security_admin(role_name name)

Входные параметры:

  • role_name (name) — имя пользователя.

Пример:

Команда:

SELECT pm_revoke_security_admin('u1');

При включенной защите от привилегированных пользователей функция pm_revoke_security_admin:

  • изымает у указанного пользователя роль sec_admin_role;

  • исключает переключение пользователя на роль sec_admin_role при логине;

  • изымает у пользователя политику secAdminUser;

  • функция помещается под защиту утилитой initprotection;

  • привилегия на выполнение функции включается в политику для роли sec_admin_role в initprotection.

Примечание:

При включенной защите от привилегированных пользователей функции pm_grant_to_policy, pm_revoke_from_policy, pm_unprotect_object, pm_get_protected_objects не производят изменений предустановленных политик и объектов.

Защита переноса между табличными пространствами#

Данная функциональность призвана защищать данные пользователя на уровне физического представления и представляет собой пересечение функциональностей «Прозрачное шифрование данных (TDE)» и «Защита данных от привилегированных пользователей». Включает расширение механизма защиты данных, которое не позволяет пользователям, имеющим права на изменение объектов, переносить их между табличными пространствами. Исключает возможность раскрытия данных при переносе в не зашифрованное целевое табличное пространство.

Управление механизмом защиты данных от привилегированных пользователей осуществляет администратор безопасности. В случае необходимости предоставления доступа к защищенным объектам сотрудники сопровождения производят выдачу прав согласно действующим нормативным документам на уровне ролевой модели и передают запрос на выдачу прав администратору безопасности

Для переноса индекса между табличными пространствами проверяется наличие прав на перенос самого объекта, которому этот индекс соответствует.

Партиционированная таблица не имеет физического представления в файловой системе, права на изменение табличного пространства для такой таблицы должны выдаваться отдельно. Поскольку в целевом случае партиции защищаются через партиционированную таблицу, для перемещения их между табличными пространствами проверяется право на выполнение действия у родительской (партиционированной) таблицы.

Если запрошен перенос таблицы или индекса, у которых исходное табличное пространство было зашифровано, а новое нет (явно указаны параметры rel_tablespace и/или ind_tablespaces), то результатом будет:

  • отказ в выполнении переноса с ошибкой Action is forbidden — если политика по таблице отсутствует или не содержит явного разрешения на действие move;

  • успешный перенос таблицы или индекса с переносом объекта — если защита объекта отключена или политика по таблице разрешает действие move.

Маскирование запросов#

СУБД, в том числе Pangolin, предназначены для оперирования с данными. Среди данных могут присутствовать такие, разглашение которых нежелательно, по причине наличия в них категорированной информации, либо информации, раскрытие которой может предоставлять возможность несанкционированного доступа к СУБД.

Модель функционирования СУБД Pangolin строится на выполнении запросов со стороны аутентифицированных и авторизованных пользователей. В том числе запросов на:

  • управление ролями и пользователями, включая задание параметров аутентификации и авторизации, в том числе паролей;

  • управление структурой хранимых данных, включая БД, схемы, табличные пространства, объекты схем;

  • выполнение действий над хранимыми данными, таких как выборка, вставка, изменение и удаление.

Запросы, поступающие на вход СУБД, проходят многоступенчатую обработку, и могут быть выведены в лог или служебные представления СУБД в неизмененном виде, в соответствии с настройками СУБД или расширений, выполняющих обработку запросов.

Известные для СУБД Pangolin точки, в которых может быть выполнен вывод пользовательских запросов, следующие:

Что

Когда

Условие

Кто может задать/использовать

Полный текст запроса, соответствующего условию

Вывод в лог сразу после получения запроса

Параметр log_statement=условие

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов

Полный текст запроса, соответствующего условию

Вывод в лог после выполнения запроса

Параметр log_min_duration_statement=минимальная длительность

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов

Полный текст запроса + ошибочная лексема при ошибке разбора

При выводе сообщения в лог, в том числе при ошибке

Параметр log_min_error_statement=уровень логирования, для записей лога с уровнем логирования равным или выше указанного

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов

Урезанный до 1024 символов текст любого запроса

При запросе из представления pg_stat_activity

По своей сессии, запросе пользователем с ролью pg_read_all_stats или суперпользователем

Администратор СУБД авторизованный пользователь

Запрос на задание или изменение пароля с паролем

При сохранении в файл pg_stat_tmp/pgss_query_texts.stat. При запросе из представления pg_stat_statements

Установленное расширение pg_stat_statements, при запросе пользователем с ролью pg_read_all_stats или суперпользователем

Администратор СУБД авторизованный пользователь ОС, имеющий доступ к файлу pg_stat_tmp/pgss_query_texts.stat

Урезанный до 1024 символов текст любого запроса, выполнение которого попало на момент формирования среза сессий со стороны ASH (performance insight)

При сохранении в файлы ASH. При запросе из представления ASH

Без ограничений

Администратор СУБД авторизованный пользователь ОС, имеющий доступ к файлам ASH

Полный текст запроса, соответствующего условию

При выводе в лог результат работы расширения auto_explain

Установленное расширение auto_explain, соответствие запроса параметрам расширения

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов

Полный текст запроса, соответствующего условию

При выводе в лог результат работы расширения pg_hint_plan

Установленное расширение pg_hint_plan, соответствие запроса параметрам расширения, при значении параметра pg_hint_plan.debug_print большем, чем on

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов

Полный текст запроса, соответствующего условию аудита

При выводе в лог записей аудита, соответствующих критериям аудита

Соответствие сессии и/или запроса заданным критериям аудита

Администратор СУБД пользователь ОС, имеющий доступ к файлам логов (содержащих, среди прочего, записи лога аудита)

Выполняемые запросы могут содержать следующую информацию, которая не должна быть доступна администраторам СУБД (superuser) или лицам, имеющим доступ к файлам логов, но не имеющим доступ к БД (администраторы ОС):

  • значения паролей или хешей паролей в запросах на задание или изменение паролей пользователей;

  • значения параметров-паролей в функциях API администраторов безопасности;

  • явно заданные как константы значения параметров в функциях;

  • явно заданные как константы значения, вставляемые (INSERT) в таблицы и представления, в том числе заданные через выражения SELECT или CTE;

  • явно заданные как константы значения, задаваемые для изменения полей (UPDATE) в таблицах и представлениях, или используемые для фильтрации записей для изменения;

  • явно заданные как константы значения, задаваемые как условия выражений SELECT, UPDATE и DELETE по полям таблиц и представлений.

Для поддержки возможности сокрытия такой информации реализована функциональность маскирования указанных выше значений для категорий запросов при:

  • выводе запроса в лог по условию log_statement=условие, влияет на попадание в лог запросов определенных типов - либо dll (только запросы DDL), либо mod (запросы DDL, модификации данных и COPY FROM), либо all (все запросы);

  • выводе запроса в лог по условию log_min_duration_statement=минимальная длительность, влияет на попадание в лог запросов с определенной длительностью;

  • выводе запроса в лог при ошибке по условию log_min_error_statement=уровень логирования запросов, влияет на попадание в лог запросов определенных типов;

  • вывод в лог информации об обрабатываемых запросах от расширения auto_explain;

  • вывод в лог информации об обрабатываемых запросах от расширения pg_hint_plan;

  • вывод в лог (аудита) в соответствии с критериями аудита, включая значения параметров подготовленных запросов при pgaudit.log_parameter = on;

  • накопление, сохранение в файл pg_stat_tmp/pgss_query_texts.stat и получение запросов из представления pg_stat_statements;

  • накопление и получение текстов запросов из представления pg_stat_activity.

Включение маскирования запросов выполняется для всех указанных выше случаев, без разделения по категориям маскируемых запросов.

Внимание!

Сохранение текста запроса в файлы ASH (performance insight) - регулируется собственными параметрами performance insight и performance_insights.masking.

При этом, при заданном маскировании запросов через параметр masking_mode со значением full, маскирование запросов в ASH (performance insight) будет выполняться независимо от значения параметра performance_insights.masking. Это связано с тем, что ASH пользуется текстами запросов, помещенных в представление pg_stat_activity, и при включенном маскировании тексты запросов в представлении находятся в уже замаскированном виде.

Особенности маскирования запросов:

  • текст подготовленных запросов при их вызове через EXECUTE также обрабатывается по вышеуказанным правилам;

  • в случае вывода ошибки, в которой отдельно выводится лексема, которую Pangolin считает ошибочной: она должна быть замаскирована по тем же правилам. То есть, если эта лексема была замаскирована в полном тексте запроса, то должна быть замаскирована и в ошибке. Исключением являются ошибки в лексемах, определяющих категорию запроса - SELECT/INSERT/UPDATE/DELETE и CREATE/ALTER ROLE/USER.

Настройка маскирования#

Маскирование запросов настраивается новым конфигурационным параметром masking_mode, который может принимать два значения:

  • disabled - механизм отключен, маскирование запросов не производится, за исключением значений паролей и параметров функций, принимающих пароли, которые маскируются всегда;

  • full - механизм маскирования работает по всем обрабатываемым запросам SELECT/INSERT/UPDATE/DELETE и их параметрам, а также запросам CREATE/ALTER ROLE/USER и параметру пароля в их составе.

По умолчанию механизм выключен (disabled), параметр хранится в $PGDATA/postgresql.conf - в случае конфигурации сервера standalone, в случае конфигурации cluster - в файле /etc/pangolin-manager/postgres.yml; а при защищенном конфигурировании (настроенное соединение с KMS + значение параметра secure_config = on) берется из хранилища секретов (KMS), из параметра кластера с именем masking_mode.

Для изменения значения параметра masking_mode выполните перезапуск СУБД Pangolin.

Автоматическое завершение неактивных соединений#

Соединения, остающиеся неактивными определенное время, подлежат принудительному завершению. Для завершения таких соединений используется фоновый процесс «idle sessions terminator», осуществляющий мониторинг и завершение бездействующих клиентских сеансов. Этот процесс запускается при старте сервера Pangolin и завершается вместе с остановкой сервера.

Процесс регулируется двумя параметрами:

  • check_idle_time_delay - интервал мониторинга в миллисекундах;

  • backend_idle_alive_time - допустимое время бездействия в секундах.

Если хотя бы один из этих параметров равен нулю, неактивные соединения завершаться не будут.

Прозрачное шифрование#

В Pangolin используется прозрачное шифрование данных (TDE). С его помощью шифруются данные:

  • хранящиеся в журналах изменений, файлах данных, резервных копиях и временных файлах БД;

  • передаваемые по каналам связи в ходе физической и логической репликаций.

Решение HashiCorp Vault используется как система управления, обеспечивая защищенное хранение ключей шифрования и настроек.

Настройка прозрачного шифрования хранимых данных (TDE) в Pangolin возможна с использованием хранилища секретов в HashiCorp Vault или с использованием хранилища KMS-заменителя.

При ротации на стороне хранилища секретов необходимо соблюдать структуру хранения параметров. При этом на стороне СУБД работает фоновый процесс, периодически проверяющий изменение мастер-ключа и при его изменении выполняющий перешифрование ключей в локальном хранилище ключей keyring БД, которое размещается в общей памяти сервера.

Ротация мастер-ключа кластера высокой доступности так же может инициироваться и выполняться посредством выполнения смены мастер-ключа на узле лидера БД, входящем в кластер.

Функции для поддержки ротации и изменения мастер-ключей на стороне БД:

  • block_rotate_master_key — захватывает блокировку изменения мастер-ключа, служит для исключения ротации мастер-ключа TDE на кластере при работе таких утилит, как pg_rewind;

  • unblock_rotate_master_key — снимает блокировку изменения мастер-ключа на кластере;

  • set_master_key — устанавливает новое значение мастер-ключа;

  • rotate_master_key — генерирует и устанавливает новое значение мастер-ключа;

  • reencrypt_keys — перешифровывает keyring актуальным мастер-ключом, опираясь на информацию о предыдущем использованном мастер-ключе;

  • restore_keys — перешифровывает keyring актуальным мастер-ключом, в том числе поддерживает нахождение мастер-ключа из истории в хранилище секретов, которым был зашифрован конкретный ключ шифрования объекта. Используется в том числе в восстановлении резервных копий, снятых во время действия предыдущих мастер-ключей.

Подробное описание функций для поддержки ротации и изменения ключей шифрования на стороне БД в документе «Список PL/SQL функций продукта».

Прозрачное шифрование предотвращает несанкционированный доступ к пользовательским данным, хранящимся:

  • в файлах отношений БД на базе СУБД Pangolin;

  • во временных файлах, формируемых СУБД Pangolin в процессе работы;

  • в журналах предварительной записи СУБД Pangolin;

  • в резервных копиях баз данных Pangolin.

Средства криптографической защиты информации#

Для использования шифрования между клиентом и сервером необходимо настроить OpenSSL на клиенте и на сервере.

SSL включается с помощью параметра ssl = on в файле postgresql.conf.

SSL использует файлы сертификата и закрытого ключа сервера. По умолчанию они называются server.crt и server.key. Эти названия менять не рекомендуется.

Доступ к файлу server.key должен быть ограничен командой chmod 0600 server.key.

Чтобы клиенты могли подключаться к серверу с помощью сертификатов, поместите сертификаты корневых центров сертификации в каталог data, укажите имя файла с сертификатами в параметре ssl_ca_file в postgresql.conf.

После этого добавьте параметр clientcert=1 в соответствующие строки hostssl в файле pg_hba.conf.

Оптимизация таблиц#

В процессе работы с Pangolin возникает table bloat — ситуация, при которой данные таблиц будут храниться неэффективно. Они фрагментируются, что приводит к ухудшению производительности и нерациональному использованию места на диске.

Примеры ситуаций, при которых может возникать фрагментация:

  • непредвиденный скачок запросов UPDATE и/или DELETE, сильно отличающийся от обычного профиля нагрузки;

  • наличие долгих транзакций, препятствующих удалению старых версий записей (VACUUM не может удалить запись, если есть хотя бы одна незакрытая транзакция старше записи, удалившей или изменившей эту запись);

  • наличие незавершенных PREPARED-транзакций;

  • наличие открытых слотов репликации. Это может произойти из-за сильной задержки между лидером и репликой либо в случае недоступности реплики;

  • фрагментация может накапливаться естественным образом, если в таблице есть типы данных переменной длины. Это приводит к образованию кусков удаленных данных такого размера, которые сложно будет перезаписать.

Механизм работы с данными в PostgreSQL#

При первом наполнении таблицы данные добавляются последовательно и равномерно занимают блоки. Пример наполнения записями таблицы bloated_table:

CREATE TABLE bloated_table(id integer, data integer);
INSERT INTO bloated_table SELECT i, random() FROM generate_series(1, 1000000) AS g(i);

Посмотреть статистику по таблице можно с помощью запроса к pg_stat_user_tables командой ANALYZE:

ANALYZE bloated_table;
SELECT n_tup_ins, n_tup_upd, n_tup_del, n_live_tup, n_dead_tup FROM pg_stat_user_tables WHERE relname = 'bloated_table';

 n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
-----------+-----------+-----------+------------+------------
   1000000 |         0 |         0 |    1000000 |          0

Полученные результаты:

  • n_tup_ins, n_tup_upd, n_tup_del — количество вставок, изменений, удалений строк таблицы;

  • n_live_tup — актуальные записи;

  • n_dead_tup — «мертвые» записи, помеченные на удаление.

Команда pg_size_pretty покажет объем таблицы на диске:

SELECT pg_size_pretty(pg_table_size('bloated_table'));
 pg_size_pretty
----------------
 35 MB

Симуляция фрагментации методом удаления каждой второй строки:

DELETE FROM bloated_table WHERE (id % 2) = 0;

Статистика таблицы после фрагментации:

n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
-----------+-----------+-----------+------------+------------
   1000000 |         0 |    500000 |     500000 |     500000

 pg_size_pretty
----------------
 35 MB

Теперь 500 000 записей считаются «мертвыми» (dead) и могут быть удалены сборщиком мусора (VACUUM). При штатной работе это сделает auto vacuum, а для таблицы из примера очистка запущена вручную:

VACUUM bloated_table;

...

 n_tup_ins | n_tup_upd | n_tup_del | n_live_tup | n_dead_tup
-----------+-----------+-----------+------------+------------
   1000000 |         0 |    500000 |     500000 |          0

 pg_size_pretty
----------------
 35 MB

«Мертвых» записей больше нет, но размер таблицы не изменился. VACUUM не возвращает место на диске кроме случаев, когда удаляет последний блок с данными. Свободное место будет переиспользовано Pangolin для новых записей.

Примечание:

Обновление существующих записей также может привести к фрагментации: UPDATE и DELETE не изменяют значение текущей строки (tuple), а создают ее новую версию.

Анализ фрагментации таблиц#

В PostgreSQL есть расширение pgstattuple, позволяющее анализировать состояние таблиц. Оно устанавливается вместе с Pangolin по умолчанию.

Пример использования:

test=> SELECT * FROM pgstattuple('bloated_table');
-[ RECORD 1 ]------+-------
table_len          | 458752
tuple_count        | 1470
tuple_len          | 438896
tuple_percent      | 95.67
dead_tuple_count   | 11
dead_tuple_len     | 3157
dead_tuple_percent | 0.69
free_space         | 8932
free_percent       | 1.95

Значение строк вывода:

  • free_percent — процент свободных записей. Чем он выше, тем больше фрагментирована таблица. Нормальными считаются значения не более 20%;

  • table_len — физическая длина отношения в байтах;

  • tuple_count — количество «живых» записей;

  • tuple_len — общая длина «живых» записей в байтах;

  • tuple_percent — процент «живых» записей;

  • dead_tuple_count — количество «мертвых» записей;

  • dead_tuple_len — общая длина «мертвых» записей в байтах;

  • dead_tuple_percent — процент «мертвых» записей;

  • free_space — общий объем свободного пространства в байтах.

Примечание:

Рекомендуется периодически проверять активные и перенесшие всплеск нагрузки таблицы.

Стандартные утилиты PostgreSQL#

Вернуть освобожденное после VACUUM место на диске можно стандартными средствами PostgreSQL:

  • VACUUM FULL полностью пересоберет таблицу, освободив все неиспользуемые строки:

    VACUUM FULL bloated_table;
    ...
     pg_size_pretty
    ----------------
     17 MB
    
  • CLUSTER выполнит все операции VACUUM FULL и упорядочит строки по индексу, уменьшая количество обращений к диску на некоторых запросах:

    CLUSTER bloated_table USING <index_name>;
    

Использовать VACUUM FULL и CLUSTER на БД под нагрузкой не рекомендуется. Эти команды работают медленно и полностью блокируют обрабатываемую таблицу. Для решения table bloat без прибегания к блокировке в состав Pangolin входят утилиты по реорганизации данных: pg_repack и pgcompacttable.

Расширение pg_repack#

Инструмент для реорганизации таблиц без эксклюзивной блокировки. Позволяет реорганизовать таблицы и индексы к ним и переносить их в другое табличное пространство.

Функциональность:

  • реорганизация таблиц без блокировки, в отличие от стандартных средств PostgreSQL VACUUM FULL и CLUSTER. Производительность сравнима с CLUSTER;

  • удаление пустот в таблицах и индексах;

  • восстановление физического порядка кластеризованных индексов.

Установка не требуется, включить расширение в Pangolin:

CREATE EXTENSION pg_repack;

Реорганизации таблиц без блокировки#

Особенности функциональности:

  • для работы pg_repack требуются права суперпользователя;

  • в реорганизуемых таблицах требуется наличие primary key или хотя бы одного уникального поля;

  • во время работы утилиты с обрабатываемой таблицей можно производить любые манипуляции, кроме DDL.

Алгоритм:

  1. Создается таблица для логирования операций над оригинальной таблицей, которые будут происходить во время выполнения алгоритма.

  2. В оригинальной таблице создаются триггеры для операций Insert, Update и Delete. Триггеры записывают действия в созданную таблицу для логирования.

  3. Создается новая таблица – копия оригинальной таблицы.

  4. Копируются индексы из оригинальной таблицы в новую.

  5. К новой таблице применяются все операции из таблицы логирования (см. шаг 1).

  6. Выполняется swap оригинальной и новой таблиц.

  7. Удаляется оригинальная таблица.

На шагах 1, 2, 6 и 7 для оригинальной таблицы применяется короткая Access Exclusive-блокировка. Данная блокировка незначительна по времени. На остальных шагах к оригинальной таблице применяется Access Share-блокировка.

Недостатки pg_repack#

Имеются следующие недостатки:

  • отсутствие ограничений на работу с диском и невозможность распределить нагрузку. Это приводит к значительной нагрузке на диск и падению производительности при работе с большими таблицами (падение сравнимо с вызовом полного копирования таблицы);

  • во время работы переполняется WAL, что приводит к задержке между лидером и репликой и может привести к падению экземпляра PostgreSQL. При обработке больших таблиц рекомендуется отключить слот репликации на время работы утилиты;

  • для реорганизации требуется дополнительное место на диске, равное сумме размеров оригинальной таблицы, таблиц с логами и индексов. При небольшой нагрузке размером логов можно пренебречь.

Пример использования#

Реорганизовать таблицу «bloated_table»:

pg_repack -U <username> -d <dbname> -t bloated_table

Ключи:

  • -U USERNAME — имя пользователя;

  • -d DBNAME — имя базы данных;

  • --table TABLE_NAME или -t SCHEME_NAME.TABLE_NAME — выбор таблицы для обработки;

  • --schema SCHEME_NAME — выбор схемы для обработки;

  • --index INDEX_NAME — выбор индекса для обработки;

  • --jobs NUMBER_OF_PROCESSES — запустить несколько параллельных процессов для ускорения обработки.

Внимание!

При включенном прозрачном шифровании (TDE) использовать pg_repack запрещено.

Инструмент pgcompacttable#

Инструмент представляет собой скрипт реорганизации данных в раздутых таблицах (bloated tables) без применения Access Exclusive блокировки.

Отличия от pg_repack:

  • не требует много места на диске:

  • таблицы обрабатываются «на месте»;

  • индексы перестраиваются друг за другом, от меньшего к большему. Максимальное требуемое место на диске равно размеру наибольшего индекса;

  • таблицы обрабатываются с настраиваемыми задержками для предотвращения перегрузки IO и всплесков задержки репликации (см. ключ --delay-ratio);

  • не может переносить таблицы или индексы в другое табличное пространство.

Принцип работы pgcompacttable#

  1. Вызовом команды SET field_name = field_name выполняется фиктивное обновление всех записей таблицы, начиная с конца. Утилита проходит по таблице итеративно. На первом шаге обновляется несколько страниц (число считается динамически, максимум 5). Задержка перед обработкой каждого поля вычисляется как произведение --delay-ratio и длительности предыдущей итерации. Это позволяет контролировать нагрузку на БД.

    Внимание!

    PostgreSQL гарантирует, что все новые данные заполняют свободные места, начиная с начала таблицы. Таким образом, по прохождению всех строк таблица будет укомплектована.

  2. После обработки таблицы pgcompacttable перестраивает индексы за три шага:

    1. Создается новый индекс (команда CREATE INDEX с параметром CONCURRENTLY).

    2. Происходит замена (swap) имени старого индекса на новый (команда ALTER INDEX RENAME).

    3. Удаляется старый индекс (команда DROP INDEX с параметром CONCURRENTLY).

  3. На шаге ii может возникнуть длительная блокировка. Чтобы не блокировать индексы на длительное время, pgcompacttable выполняет множество коротких попыток замены индексов. Поведение управляется ключами:

    • --reindex-retry-count – максимальное количество попыток;

    • --reindex-retry-pause – задержка между попытками;

    • --reindex-lock-timeout – максимальное время выполнения переименования. При превышении количества попыток выводится WARNING-сообщение вида:

    Reindex <имя индекса>, lock has not been acquired
    
  4. После обработки всех строк запускается VACUUM для удаления пустых блоков с конца таблицы.

Запуск скрипта#

Для запуска скрипта требуются права superuser.

Рекомендуется запускать его от имени владельца кластера. В этом случае скрипт может использовать ionice в бэкенде PostrgreSQL для понижения приоритетов IO.

Используемые ключи делятся на группы:

  • общие ключи;

  • ключи настройки соединения;

  • ключи работы с БД;

  • ключи настройки поведения инструмента.

Общие ключи:

  • -?, --help — вывести короткую справку об инструменте;

  • -m, --man — вывести полную справку об инструменте;

  • -V, --version — вывести версию инструмента;

  • -q, --quiet — включить тихий режим. В этом режиме выводятся только сообщения об ошибках и результирующее сообщение;

  • -v, --verbose — включить режим протоколирования. В этом режиме выводятся все сообщения.

Ключи настройки соединения:

  • -h HOST, --host HOST — имя или IP-адрес сервера базы данных;

  • -p PORT, --port PORT — порт для подключения к базе данных;

  • -U USER, --user USER — имя пользователя базы данных, под которым выполняется подключение. По умолчанию имя текущего пользователя, получаемое командой whoami;

  • -W PASSWD, --password PASSWD — пароль для указанного пользователя.

Примечание:

Инструмент pgcompacttable использует Perl модуль DBI для соединения с базой данных.

Если настройки соединения не передаются в ключах, то инструмент использует переменные окружения PGHOST, PGPORT, имя текущего пользователя и PGPASSWORD.

Если пароль не задан, инструмент попробует применить пароль (в порядке обращения):

  1. Из файла, указанного в переменной окружения PGPASSFILE.

  2. Из файла HOME/.pgpass.

Ключи работы с БД:

  • -a, --all – обработать все базы данных в кластере;

  • -d DBNAME, --dbname DBNAME – имя базы данных для обработки. По умолчанию – все базы данных, которыми владеет пользователь, под которым выполняется подключение;

  • -n SCHEMA, --schema SCHEMA – имя схемы для обработки. По умолчанию обрабатывается публичная (public) схема;

  • -N SCHEMA, --exclude-schema SCHEMA – имя исключаемой из обработки схемы;

  • -t TABLE, --table TABLE – имя таблицы для обработки. По умолчанию – все таблицы обрабатываемой схемы;

  • --tables-like 'LIKE expression' – SQL LIKE условие поиска таблиц для обработки. По умолчанию – все таблицы обрабатываемой схемы;

  • -T TABLE, --exclude-table TABLE – имя исключаемой из обработки схемы.

Инструмент игнорирует не найденные в кластере базы данных, схемы и таблицы. Избыточные исключения так же игнорируются.

Все ключи, кроме --all, можно использовать несколько раз.

Ключи настройки поведения инструмента:

  • -R, --routine-vacuum – включить использование VACUUM. По умолчанию выключено;

  • -r, --no-reindex – выключить переиндексирование таблиц после их обработки;

  • --no-initial-vacuum – выключить запуск VACUUM перед обработкой таблицы;

  • -i, --initial-reindex – включить переиндексирование таблицы перед ее обработкой;

  • -s, --print-reindex-queries – выводить запросы на переиндексацию. Пример применения: выполнение самостоятельного переиндексирования после работы инструмента;

  • --reindex-retry-count – максимальное количество попыток замены имени индекса. По умолчанию 100;

  • --reindex-retry-pause – задержка между попытками реиндексации, в секундах. По умолчанию 1 секунда;

  • --reindex-lock-timeout – задержка перед переиндексацией после выполнения запросов ALTER TABLE, в миллисекундах. По умолчанию 1000 миллисекунд;

  • -f, --force – принудительная реорганизация всех таблиц в указанной базе данных;

  • -E RATIO, --delay-ratio RATIO – коэффициент для вычисления задержки между раундами. Задержка вычисляется как произведение времени выполнения прошлого раунда и указанного коэффициента. По умолчанию 2;

  • -Q Query, --after-round-query Query – SQL выражение, выполняемое после каждого раунда обработки базы данных;

  • -o COUNT, --max-retry-count COUNT – максимальное количество попыток повторной обработки в случае ошибки. По умолчанию 10.

Внимание!

Таблицы и индексы с «раздутием» меньше 20% считаются нормальными.

Пример использования#

Реорганизовать таблицу bloated_table:

pgcompacttable  --dbname -t bloated_table

Расширение pg_squeeze#

Расширение предназначено для оптимизации хранения данных в таблицах и индексах методом переупаковки данных в новый объект.

Предусмотрен обмен данными между расширением и администратором СУБД только через следующие объекты:

Объект

Тип

Назначение

squeeze.tables

таблица

Регистрация автоматически обслуживаемых таблиц, по одной записи на таблицу

squeeze.log

таблица

Журнал переупаковок, заполняется по записи на каждую успешно переупакованную таблицу

squeeze.errors

таблица

Журнал ошибок, заполняется ошибками переупаковки

squeeze.start_worker();

функция

Запустить фоновую обработку

squeeze.stop_worker();

функция

Остановить фоновую обработку

squeeze.squeeze_table();

функция

Переупаковать таблицу вручную

Проверка расширения#

Для проверки подключения расширения необходимо:

  1. Убедиться, что установлены следующие параметры сервера:

wal_level: logical
max_replication_slots = 1 # или добавить 1 к существующему значению
shared_preload_libraries = 'pg_squeeze' # или добавить библиотеку к существующим
  1. Проверить наличие схемы squeeze, а также подключение под ТУЗ squeeze_tuz;

  2. Перезапустить узлы для применения.

Включение автоматической обработки#

Установите два параметра сервера:

squeeze.worker_autostart = 'my_database your_database'
squeeze.worker_role = squeeze_tuz

При следующем перезапуске сервера запустятся четыре обработчика: планировщик и переупаковщик по my_database, такие же процессы по your_database. Все обработчики получат привилегии суперпользователя squeeze_tuz.

Настройка существующей базы#

Добавьте установленное расширение к существующей базе, для этого подключитесь к базе суперпользователем и выполните команду:

CREATE EXTENSION pg_squeeze;

Чтобы настроить автоматический запуск фоновых обработчиков по базе, дополните или добавьте параметр сервера:

squeeze.worker_autostart = 'my_database your_database next_database'

Регистрация таблицы#

Подключитесь к базе в качестве суперпользователя, после чего выполните:

INSERT INTO squeeze.tables (tabschema, tabname, first_check) VALUES ('app', 'foo', now());

Поля таблицы и их значения подробно описаны ниже.

Отмена регистрации#

Подключитесь к базе в качестве суперпользователя, после чего выполните:

DELETE FROM squeeze.tables WHERE tabschema='app' and tabname='foo';

Ручная переупаковка таблицы#

Выполните команду:

SELECT squeeze.squeeze_table('app', 'pgbench_accounts', null, null, null);

Полная форма: squeeze.squeeze_table(tabchema name, tabname name, clustering_index name, rel_tablespace name, ind_tablespaces name[]). Параметры - см. ниже.

Поля таблицы squeeze.tables и параметры функции squeeze.squeeze_table#

Следующие параметры применяются как при регистрации таблицы для автоматической обработки, так и при ручной переупаковке. Им соответствуют и поля таблицы squeeze.tables, и аргументы squeeze.squeeze_table():

  • tabschema – название схемы;

  • tabname – название таблицы;

  • clustering_index – название существующего индекса обрабатываемой таблицы. Когда обработка будет завершена, записи в таблице будут физически упорядочены и отсортированы в порядке ключа индекса;

  • rel_tablespace – существующее табличное пространство, в которое должна быть перемещена таблица. NULL означает, что таблицу следует оставить на своем месте;

  • ind_tablespaces – двумерный массив, в котором каждая запись задает соответствие табличного пространства индексу. Первая и вторая колонка представляют из себя название индекса и табличного пространства соответственно. Все индексы, для которых соответствие не задано, останутся в изначальном табличном пространстве.

    Внимание!

    Если табличное пространство задано для таблицы, но не для индексов, то в это табличное пространство перемещается только таблица. Индексы в таком случае остаются в первоначальном пространстве. Таким образом, пространство таблицы не принимается по умолчанию и для индексов.

Следующие параметры применяются только при регистрации таблицы, им соответствуют поля таблицы squeeze.tables:

  • schedule – указывает, когда следует проверять и, возможно, переупаковывать таблицу. Расписание задается значением следующего составного типа данных, который напоминает по значению элемент файла crontab:

    CREATE TYPE schedule AS ( minutes minute[], hours hour[], days_of_month dom[], months month[], days_of_week dow[] );
    

    Здесь minutes (от 0 до 59) и hours (от 0 до 23) задают время проверки внутри суток, а days_of_month (от 1 до 31), months (от 1 до 12) и days_of_week (от 0 до 7, где 0 и 7 означают воскресенье) определяют дни проверок; Проверка выполняется, если minute, hour и month совпадают с текущим временем. При этом NULL означает любую минуту, час и день соответственно. Для того чтобы проверка запустилась, как минимум один из параметров days_of_month, days_of_week должен совпасть с текущим временем. В противном случае оба параметра должны быть NULL. Например, следующая таблица будет проверяться в 22:30 каждую среду и пятницу:

    INSERT INTO squeeze.tables (tabschema, tabname, schedule, free_space_extra, vacuum_max_age, max_retry)
         VALUES ('app', 'bar', ('{30}', '{22}', NULL, NULL, '{3, 5}'), 30, '2 hours', 2);
    
  • free_space_extra – минимальный процент дополнительного свободного пространства, при котором запускается переупаковка таблицы. «Дополнительный» означает, что порожденное fillfactor свободное пространство - не причина сжимать таблицу; Например, если fillfactor равен 60, то как минимум 40 процентов каждой страницы (блока) должны оставаться свободными при обычной работе. Так, для детектирования со стороны pg_squeeze состояния таблицы при 70 процентах свободного места, необходимо установить порог free_space_extra в значение 30. Порог вычисляется как разность требуемых свободных 70 процентов и 40 процентов, свободных по fillfactor. Значение по умолчанию для free_space_extra равно 50.

  • min_size – минимальное дисковое пространство, которое должна занимать на диске таблица, чтобы подходить для обработки. Значение по умолчанию - 8;

  • vacuum_max_age – максимальное время после завершения последней процедуры VACUUM по таблице, в течение которого карта свободного места (free space map, FSM) считается свежей. Как только этот интервал истек, доля устаревших версий записей (dead tuples), возможно, становится значительной. Поэтому для оценки потенциального эффекта pg_squeeze потребуется больше усилий, чем простейшая проверка FSM. Значение по умолчанию - 1 hour;

  • max_retry – максимальное число повторных попыток переупаковки таблицы, если произошел сбой первой попытки обработки соответствующей задачи. Типичная причина повтора обработки - то, что определение таблицы поменялось на протяжении операции переупаковки. Если достигнуто максимальное число повторов, то обработка таблицы считается завершенной. Как только наступит следующее запланированное время, будет создана следующая задача. Значение по умолчанию - 0 (т.е. не повторять);

  • skip_analyze – указывает, что за обработкой таблицы не должна следовать команда ANALYZE. Значение по умолчанию - false, поэтому по умолчанию ANALYZE после обработки таблицы выполняется.

По требованиям к механизму защиты данных от привилегированных пользователей в Pangolin (перенос таблиц между табличными пространствами как отдельное подлежащее защите действие), запрещено переносить объекты из зашифрованного табличного пространства в открытое как при автоматической обработке, так и вручную. В случае возникновения ошибки Action is forbidden, которая связана с отказом в выполнении переноса в новое табличное пространство, необходимо обратиться к администратору безопасности для получения соответствующих прав. Отказ происходит, когда при явно установленных параметрах rel_tablespace или ind_tablespaces и включенной защите объекта запрошена переупаковка таблицы или индекса, у которых исходное табличное пространство было зашифровано, а новое таковым не является.

Мониторинг метрик репликации#

Рекомендуется обеспечить на стороне инфраструктуры мониторинг стандартной логической репликации. Как минимум, необходимо отслеживать следующие метрики:

SELECT slot_name,
pg_wal_lsn_diff(restart_lsn, pg_current_wal_lsn()) process_lag_bytes,
pg_wal_lsn_diff(confirmed_flush_lsn, pg_current_wal_lsn()) apply_lag_bytes
FROM pg_replication_slots WHERE slot_type='logical';

Для найденных slot_name можно построить графики process_lag_bytes и apply_lag_bytes с триггерами, например, 256 МБ/1 ГБ warning/critical.

В списке рекомендованных метрик для Pangolin эти метрики объединены под именем pgse_replication_slots_retained_bytes_active. Подробнее о событиях мониторинга смотрите в разделе «События мониторинга». В разделе репликация той же таблицы доступны запросы и правила для более подробного отслеживания процесса. А на странице мониторинг статуса репликации можно узнать смысл этой информации и познакомиться с примерным решением в виде панели отчетов для Grafana.

Можно использовать для мониторинга любое решение на выбор. Чтобы узнать подробнее об использовании Grafana для мониторинга параметров Pangolin и сборе метрик смотрите документ «Установка и настройка дополнительных компонентов системы, не входящих в состав дистрибутива Pangolin», раздел «Мониторинг с помощью Grafana».

Чтобы исправить ситуацию по сигналам на эти метрики, если слот репликации относится к pg_squeeze, следует прервать переупаковку. Возможно, для этого придется самостоятельно удалить процесс ручной переупаковки или фоновый процесс-переупаковщик, после чего можно будет удалить не используемый слот. Далее операцию ручной переупаковки придется повторить. В случае фонового процесса, он будет запланирован на следующий интервал автоматически.

Стандартная метрика для отслеживания свободного пространства на дисковом томе, который хранит WAL, также должна быть включена.

Аудит действий, выполняемых расширением#

Для того чтобы в логе сервера присутствовали записи аудита с маркером AUDIT:, интегрированное решение pgaudit должно быть корректно настроено. Расширение pg_squeeze самостоятельно регистрирует два события:

  • факт вызова функции переупаковки squeeze.squeeze_table(), вне зависимости от способа вызова функции - в ручном или автоматическом режиме. Данное событие соответствует классу событий аудита MISC.

  • факт переноса таблицы и/или индекса в другое табличное пространство, выполняемого в рамках функции по переупаковке таблицы. Данное событие соответствует классу событий аудита DDL.

Настройка аудита для регистрации этих действий заключается в добавлении MISC и DDL в переменную pgaudit.log в соответствии с ролевой моделью, то есть:

  • при ручном способе переупаковки эти классы аудита должны быть установлены для пользователя, выполняющего вызов переупаковщика;

  • при автоматизированной переупаковке - для пользователя, от которого запущен процесс, запускающий переупаковку по расписанию (squeeze.worker_role - если запуск рабочего процесса осуществляется на старте сервера или тот пользователь, который запустил процесс вручную).

Например:

ALTER ROLE db_admin SET pgaudit.log='ddl, role, connection, misc_set, misc';

First_db=# \drds db_admin
List of settings
   Role   | Database |                       Settings
----------+----------+-------------------------------------------------------
 db_admin |          | pgaudit.log=ddl, role, connection, misc_set, misc
(1 row)

Для аудита событий добавления/изменения/модификации расписания автоматизированного переупаковщика необходимо настроить аудит над объектом squeeze.tables. С инструкцией можно ознакомиться в документации pgaudit. Ниже приведен пример настройки:

CREATE ROLE squeeze_auditor;
GRANT INSERT, UPDATE, DELETE, TRUNCATE ON squeeze.tables TO squeeze_auditor;
\dp+ squeeze.tables
ALTER ROLE db_admin set pgaudit.role=squeeze_auditor;
\drds db_admin

                              List of settings
   Role   | Database |                       Settings
----------+----------+-------------------------------------------------------
 db_admin |          | pgaudit.log=ddl, role, connection, misc_set, function+
          |          | pgaudit.role=squeeze_auditor
(1 row)

Также в параметр log_line_prefix может быть добавлен тип процесса - %b. Это позволит различать в логе записи о ручной и автоматизированной переупаковке.

Аналитика производительности Pangolin#

Для сбора данных в Pangolin создается дочерний процесс, в цикле которого происходит периодический опрос статистики активности и блокировок.

Для последующего анализа собранной статистики можно сформировать отчет с указанием временного диапазона. Отчет сохраняется в формате HTML. Описание и примеры разделов отчета представлены в отдельном документе.

Конфигурационные параметры#

Примечание:

  • Для применения внесенных изменений настроечных параметров необходимо выполнить перезагрузку.

  • При изменении пути к папке хранения файлов необходимо содержимое старой папки перенести в новую.

Настройка параметров для аналитики производительности осуществляется в файле postgresql.conf:

  • performance_insights.enable — включает/выключает функциональность (значение по умолчанию — false);

  • performance_insights.sampling_enable — включает/выключает сбор данных (значение по умолчанию — true). После изменения настроек параметра требуется выполнить одно из предложенных действий:

    • перезагрузка;

    • вызов команды SELECT pg_reload_conf();;

    • отправить сигнал SIGHUB;

  • performance_insights.sampling_period — задает периодичность сбора данных в миллисекундах (значение по умолчанию — 1s). Минимальное значение min - 100ms, значение max — не ограничено;

  • performance_insights.num_samples_in_ram — количество итераций сбора данных активности текущих сессий, хранящихся в оперативной памяти (значение по умолчанию — 900). Определяет время хранения данных активности текущих сессий в оперативной памяти. Время определяется количеством сборов данных (performance_insights.num_samples_in_ram), умноженным на периодичность сбора данных (performance_insights.sampling_period). Таким образом, время хранения данных активности текущих сессий по умолчанию (900 * 1s) —> 900 секунд (или 15 минут), при этом:

    • min значение - 1;

    • max значение — не ограничено (2147483647);

  • performance_insights.num_samples_in_files — количество итераций сбора данных активности текущих сессий, хранящихся в файлах (на диске) (значение по умолчанию — 86400). Определяет время хранения данных активности текущих сессий в файлах (на диске). Время определяется количеством сборов данных (performance_insights.num_samples_in_files) умноженное на периодичность сбора данных (performance_insights.sampling_period). Таким образом, время хранения данных активности текущих сессий по умолчанию (86400 * 1s) —> 86400 секунд (или 1 сутки), при этом:

    • min значение - 1;

    • max значение — не ограничено (2147483647);

  • performance_insights.directory — путь к папке, в которую сохраняются файлы с полученными данными (значение по умолчанию ${PGDATA}/pg_perf_insights);

    Внимание!

    Рекомендуется задать директорию хранения, находящуюся за пределами директории с данными СУБД (PGDATA).

    В противном случае возможна потеря статистики при реиницилизации кластера.

  • performance_insights.masking — включает/выключает маскирование параметров запроса, параметров соединения и имени пользователя (значение по умолчанию — true). Параметр performance_insights.masking рекомендуется поместить под защиту.

Функции#

Для работы с данными по аналитике производительности Pangolin применяются следующие функции:

  • pg_stat_get_activity_history — возвращает набор записей с данными об активности сессий в определенный момент времени;

  • pg_stat_get_activity_and_lock_status_history — возвращает данные активности текущих сессий вместе с данными блокировок (если они имеются) и затраченными ресурсами (CPU, IO);

  • pg_stat_get_activity_history_last — возвращает набор записей с данными об активности сессий в последний период обновления истории;

  • pg_lock_status_history — возвращает набор записей с информацией о блокировках в определенный момент времени;

  • pg_stat_activity_history_reset — функция для управления сохраненными данными, которая полностью очищает историю;

  • pg_stat_activity_and_lock_status_history_report — формирует отчет из собранных данных.

Примечание:

По умолчанию функции по аналитике производительности может вызвать суперпользователь или пользователь, у которого есть привилегии групповой роли pg_read_all_perfinsight.

Подробное описание функций приведено в документе «Список PL/SQL функций продукта», раздел «Аналитика производительности Pangolin».

Получение диагностической информации об узле СУБД#

Утилита формирования диагностического отчета предназначена для упрощения и ускорения сбора информации о состоянии и настройках стенда Pangolin. Информация собирается посредством запуска утилиты и передачи в нее определенных параметров сбора и формирует на выходе набор файлов, упакованный в tar.gz архив. Некоторые компоненты отчета требуют повышенных привилегий или доступов к каталогам.

После установки Pangolin утилита доступна в каталоге /usr/pgsql-05-se/diagnostic_tool. Есть возможность скопировать каталог в любое другое доступное пользователю место. Утилита представляет собой скомпилированный бинарный файл и набор .so библиотек. Утилита не требует выполнения дополнительных действий для работоспособности и установки дополнительных модулей.

Примечание:

Утилита diagnostic_tool версии 1.0 работает с версией Pangolin не ниже 5.2.0.

Файловый состав утилиты следующий:

  • diag — основной файл, который является точкой входа и используется для запуска сбора статистики. Утилита осуществляет сбор аргументов, вывод справки и последовательный запуск модулей сбора информации. После окончания работы утилиты осуществляется архивирование отчета, вывод сообщения о завершении работы и пути до сформированного отчета;

  • utils/common.so — модуль общих переиспользуемых функций (печать в общий лог, создание каталогов, синтаксический анализ текста в csv и т.д.);

  • utils/vars.so — модуль глобальных переменных;

  • utils/sql.so — модуль SQL-скриптов для работы с БД;

  • utils/linux_info.so — модуль сбора информации об ОС;

  • utils/linux_stat.so — модуль сбора статистики использования ОС;

  • utils/logs_collect.so — модуль сбора лог-файлов;

  • utils/config.so — модуль сбора конфигурационных файлов.

Использование#

Для запуска утилиты необходимо перейти в каталог diagnostic_tool с исполняемым файлом утилиты и ее библиотеками. Затем произвести запуск утилиты. Примеры:

    ./diag
    ./diag --help
    ./diag --host 127.0.0.1 --port 5433 --user psimax --database first_db --pgbuser pgbouncer --logs --log_lines_count 10

Утилита поддерживает следующие параметры:

    $ ./diag --help
    usage: diag [-h] [-H HOST] [-p PORT] [-U USER] [-d DATABASE]
                [--pgbuser PGBUSER] [--logs] [--pgdata PGDATA]
                [--log_lines_count LOG_LINES_COUNT] [--version]

    This is the Pangolin or PostgreSQL Diagnostics Collection Script. Some parts
    of script need superuser or root privileges, if the privileges are
    insufficientsome information cannot be collected.

    optional arguments:
      -h, --help            show this help message and exit
      -H HOST, --host HOST  database server host or socket directory (default:
                            127.0.0.1)
      -p PORT, --port PORT  database server port (default: 5433)
      -U USER, --user USER  database user name (default: postgres)
      -d DATABASE, --database DATABASE
                            database name (default: postgres)
      --pgbuser PGBUSER     Pangolin Pooler user name
      --logs                collect log files
      --pgdata PGDATA       pgdata dir path
      --log_lines_count LOG_LINES_COUNT
                            count last lines of log for collecting (default: 300)
      --version             show program's version number and exit

Описание параметров:

  • -U USER, --user USER

    Параметр username для подключения к СУБД Pangolin.

    Значение по умолчанию: postgres.

  • -p PORT, --port PORT

    Параметр port для подключения к СУБД Pangolin.

    Значение по умолчанию: 5433.

  • -h, --help

    Выводит справку по использованию утилиты.

  • -H HOST, --host HOST

    Параметр host для подключения к СУБД Pangolin.

    Значение по умолчанию: 127.0.0.1.

  • -d DATABASE, --database DATABASE

    Параметр database для подключения к СУБД Pangolin.

    Значение по умолчанию: postgres.

  • --pgdata PGDATA

    Параметр, определяющий путь к $PGDATA. Если не задан — будет произведена попытка поиска данного каталога в переменных окружения и запущенных процессах PostgreSQL.

    Значение по умолчанию отсутствует.

  • --pgbuser PGBUSER

    Параметр username для подключения к виртуальной БД Pangolin Pooler для сбора статистики использования Pangolin Pooler.

    Значение по умолчанию отсутствует.

  • --logs

    Параметр, включающий сбор лог-файлов. По умолчанию лог-файлы не собираются.

  • --log_lines_count LOG_LINES_COUNT

    Параметр, определяющий, сколько последних строк лог-файлов сохранить в отчет. Параметр введен для ограничения размера итогового отчета, количество строк должно быть достаточным для анализа и не слишком большим для экономии размера, как правило, достаточно 300-700 последних строк.

    Значение по умолчанию: 300.

  • --version

    Выводит версию утилиты и завершает работу.

В случае, если переданные параметры --user или --pgbuser отличаются от значений по умолчанию, утилита запросит пароль для данных пользователей. В ответ на запрос утилиты введите соответствующий пароль (пароль при вводе не отображается).

После того, как утилита отработала, она выдаст сообщение о том, где сохранена диагностическая информация. Отчет формируется в каталоге с утилитой из префикса pgse_diag_out_ и временной метки запуска утилиты YYYYMMDD_HHmmSS, где YYYY — год, MM — месяц, DD — день, HH — часы, mm — минуты, SS — секунды. Сформированный архив с отчетом можно скопировать с удаленного хоста, например, с помощью scp:

scp postgres@10.11.12.13:/home/postgres/diagnostic_tool/pgse_diag_out_20220607_145935.tar.gz .

Чтобы проверить содержимое архива его нужно распаковать:

tar -xvf ./pgse_diag_out_20220607_145935.tar.gz

Внимание!

Перед отправкой отчета нужно убедиться в отсутствии недопустимой к передаче информации, а именно:

  • непараметризованных запросов или значений параметров в секции collect hot statements stat файла diag.log;

  • непараметризованных запросов или значений параметров в секции collect slow statements stat файла diag.log;

  • непараметризованных запросов или значений параметров в файле csv/dbms/hot_statements.csv;

  • непараметризованных запросов или значений параметров в файле csv/dbms/slow_statements.csv;

  • логинов/паролей, а также иной чувствительной информации в секции collect running services файла diag.log (в колонке COMMAND строка запуска процесса);

  • логинов/паролей, а также иной чувствительной информации в файле csv/psaux.csv (в колонке COMMAND строка запуска процесса);

  • логинов/паролей(в том числе хешей паролей) в конфигурационном файле config/haproxy.cfg;

  • логинов/паролей(в том числе хешей паролей) в конфигурационном файле config/pg_hba.conf;

  • логинов/паролей(в том числе хешей паролей) в конфигурационном файле config/postgresql.yml (конфигурационный файл Pangolin Manager, проверить в том числе секцию pg_hba);

  • непараметризованных запросов и значений параметров в файле logs/postgresql-XXXXXXXX.log, где XXXXXXXX комбинация из даты и порядкового номера лог файла.

Отчетность по нагрузке Pangolin#

Отчетность по нагрузке в Pangolin реализована с помощью расширения pg_profile. Для расширения pg_profile в БД создается набор таблиц под историческое хранилище. Это хранилище будет накапливать статистические выборки с кластера postgres. Выборки собираются вызовом функции take_sample(). Для сбора статистики по расписанию можно использовать cron или расширение pg_cron.

Периодические выборки могут помочь найти источники интенсивной нагрузки в прошлом. Например, стало известно о деградации производительности, которая была несколько часов назад. Для решения подобных проблем можно построить отчет между двумя выборками, охватывающими период проблемы с производительностью, чтобы увидеть профиль нагрузки БД. Это поможет узнать точное время возникновения проблемы с производительностью. Для этого рекомендуется использовать инструмент мониторинга (например, Zabbix).

Выборку можно сохранить непосредственно перед запуском любой бизнес-задачи (блока транзакций) и после того, как она будет выполнена.

Когда сохраняется выборка, вызывается функция pg_stat_statements_reset() как гарантия того, что отчеты не будут потеряны из-за достижения параметра pg_stat_statements.max. Отчет будет содержать раздел, информирующий о том, что количество собранной статистики в любой выборке достигнет 90% от параметра pg_stat_statements.max.

При установке расширения автоматически создается локальный сервер. Это сервер для кластера, где установлено расширение pg_profile.

Для подключения к БД используется расширение db_link.

Управление планами запросов#

Расширения pg_outline и pg_hint_plan входят в состав Platform V Pangolin. Эти расширения, в совокупности, предоставляют возможность фиксации и подмены планов запросов для оптимизации работы планировщика запросов.

Расширение pg_outline

Функциональные возможности:

  • управление (добавить, заменить, удалить, включить, выключить) правилами подмены (фиксациями подсказок pg_hint_plan) планов запросов;

  • возврат информации о созданных правилах подмены планов запросов;

  • возврат идентификатора запроса (queryId) для текста запроса (queryText).

Расширение pg_hint_plan

Функциональные возможности:

  • подсказки (hint) планировщику запросов для управления планами выполнения запросов, в части:

    • методов сканирования таблиц;

    • методов соединения таблиц;

    • порядка соединения;

    • корректировки числа строк результата соединения;

    • настройки параллельности обработки таблиц;

    • установки значений параметров конфигурации на время планирования запроса;

  • управление планами подготовленных запросов (prepared statements) через заданные в тексте этих запросов подсказок (hint);

  • управление планами запросов в составе PL/pgSQL-блока через подсказки (hint), заданные в тексте запросов в PL/pgSQL-блоках;

  • дополнение запросов подсказками «на лету» на этапе планирования запроса на уровне всей СУБД в составе Platform V Pangolin. Это позволяет выполнять:

    • компенсационную корректировку запросов на основе заполняемой таблицы подсказок, которая устанавливает соответствие текста дополняемого запроса и имени приложения (опционально);

    • компенсационную корректировку для:

      • запросов с динамическими параметрами (подсказкой плейсхолдеров, вместо конкретных значений);

      • подготовленных запросов;

  • управление (через настроечные параметры) на уровне сессии пользователя или всей СУБД в составе Platform V Pangolin:

    • активностью расширения;

    • использованием функциональности дополнения подсказками через таблицу подсказок;

    • уровнем логирования, с которым в лог будут писаться сообщения об ошибках разбора подсказок;

    • детализацией записей отладочной информации расширения;

    • уровнем логирования, с которым в лог будут писаться сообщения с отладочной информацией.

Использование подсказок#

Подсказки (hint) должны быть заданы в первом комментарии вида /* */ в тексте запроса. Первым символом в теле комментария должен быть +.

Пример запроса с подсказками (в качестве метода соединения выбрано соединение по хешу, а pgbench_accounts сканируется последовательным способом).

 /*+
    HashJoin(a b)
    SeqScan(a)
  */
 EXPLAIN SELECT *
    FROM pgbench_branches b
    JOIN pgbench_accounts a ON b.bid = a.bid
   ORDER BY a.aid;
                                      QUERY PLAN
---------------------------------------------------------------------------------------
 Sort  (cost=31465.84..31715.84 rows=100000 width=197)
   Sort Key: a.aid
   ->  Hash Join  (cost=1.02..4016.02 rows=100000 width=197)
         Hash Cond: (a.bid = b.bid)
         ->  Seq Scan on pgbench_accounts a  (cost=0.00..2640.00 rows=100000 width=97)
         ->  Hash  (cost=1.01..1.01 rows=1 width=100)
               ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=100)
(7 rows)

В следующем примере применяются только подсказки HashJoin и SeqScan, так как IndexScan не входит в первый комментарий.

 /*+
    HashJoin(a b)
    SeqScan(a)
  */
 /*+ IndexScan(a) */
EXPLAIN SELECT /*+ MergeJoin(a b) */ *
    FROM pgbench_branches b
    JOIN pgbench_accounts a ON b.bid = a.bid
   ORDER BY a.aid;
                                      QUERY PLAN
---------------------------------------------------------------------------------------
 Sort  (cost=31465.84..31715.84 rows=100000 width=197)
   Sort Key: a.aid
   ->  Hash Join  (cost=1.02..4016.02 rows=100000 width=197)
         Hash Cond: (a.bid = b.bid)
         ->  Seq Scan on pgbench_accounts a  (cost=0.00..2640.00 rows=100000 width=97)
         ->  Hash  (cost=1.01..1.01 rows=1 width=100)
               ->  Seq Scan on pgbench_branches b  (cost=0.00..1.01 rows=1 width=100)
(7 rows)
Фиксация метода сканирования#

Для того, чтобы сформировать план запроса, планировщику необходимо для начала определиться с методами сканирования источников данных. Pangolin предлагает следующие методы доступа к источникам:

  • Sequential Scan — последовательное сканирование таблицы.

    Полный перебор всех блоков таблицы с извлечением 100% данных.

    Подходит для:

    • очень маленьких таблиц (десятки блоков);

    • полностью кэшированных таблиц, которые помещаются в области разделяемых буферов сервера и файловом кэше ОС;

    • всех остальных случаев, когда требуется извлечь данные полностью или почти полностью.

    Не подходит для:

    • извлечения малой доли данных (до 1-3%) из объемной таблицы.

  • Index Scan — индексное сканирование таблицы.

    Индекс — заранее подготовленный, отсортированный перечень значений ключа поиска. К значениям ключа в индексе приложены ссылки на страницы (блоки) таблицы и записи в них. Исполнитель сначала ищет в списке значение ключа (или диапазон значений в прямом или обратном порядке), затем читает ссылки, извлекает по ссылкам блоки таблицы, определяет видимость записей и извлекает из видимых записей данные тех полей таблицы, которых не было в ключе.

    Подходит для:

    • выбора небольшого количества данных из большой таблицы (соответствующее условие в разделе WHERE запроса называют предикат высокой селективности);

    • получения данных в порядке сортировки по ключу индекса, потому что индекс хранит уже отсортированные списки.

    Не подходит для:

    • извлечения большей части записей таблицы (более 10%), потому что чтение хаотично разбросанных блоков таблицы включает множество случайных дисковых операций, а разрешение множества ссылок добавляет нагрузку на процессор.

  • Index-only Scan — cтрогое индексное сканирование таблицы.

    Вид индексного сканирования, при котором обращений к таблице почти не происходит, потому что все требуемые для запроса данные уже есть в индексе, а видимость большинства записей уже описана в карте видимости таблицы.

    Подходит для:

    • такого индексного сканирования, когда запрос не требует данных, не входящих в индекс.

    Неприменим, когда:

    • данных в индексе недостаточно для получения результатов запроса;

    • у таблицы нет карты видимости, не выполнялся autovacuum или VACUUM.

  • Bitmap Index Scan — сканирование таблицы по битовой карте индекса.

    Промежуточный вариант между последовательным сканированием таблицы и поиском по индексу.

    Пример:

    Для предикатов с не самой высокой селективностью невыгодно читать таблицу полностью (90% блоков — лишние, не содержат интересных данных) или извлекать блоки таблицы в случайном порядке. Пример такого предиката: id between 100 and 1000000 на таблице с десятком млн записей, где:

    • при последовательном сканировании пришлось бы прочесть с диска множество лишних блоков;

    • при поиске по индексу — обработать порядка миллиона ссылок из индекса на записи в хаотично разбросанных блоках таблицы.

    Поэтому лучше действовать в две стадии:

    1. Сформировать битовую карту всей таблицы, в которой 1 биту будет соответствовать 1 запись (точная битовая карта, exact) или 1 блок таблицы (грубая карта, lossy), для чего пройти весь индекс, выставляя в 1 биты, указывающие на искомые записи или блоки, содержащие искомые записи.

    2. Один раз последовательно пройти таблицу, интересуясь только отмеченными в полученной карте записями / блоками.

    Если в запросе есть несколько низкоселективных предикатов, то соответствующие им битовые карты могут быть объединены в одну общую карту. В этом случае сначала строятся промежуточные карты по каждому из индексов, затем они побитово объединяются в результирующую карту таблицы двоичными логическими операциями, а затем по общей карте выполняется единственный проход таблицы.

  • TID Scan — сканирование таблицы по TID (tuple identifier).

    Быстрое прямое извлечение записи по ее внутреннему физическому адресу, например: where ctid='(1000,10)'::tid, где:

    • ctid — это псевдоколонка любой из таблиц, физический идентификатор записи. Он состоит из номера блока (в примере 1000) и номера записи в блоке (в примере 10).

Примечание:

В Pangolin для того, чтобы индекс мог поддерживать поиск по набору полей, ключ поиска должен лидировать в ключе индекса, начиная с первого поля.

Исключение – строгое индексное сканирование, которое может выполняться и без первых полей в ключе. В этом случае индекс служит не в качестве указателя для поиска записей, а в качестве частичного «снимка» таблицы или кэша часто запрашиваемых полей.

Фиксация метода объединения результатов#

Методы объединения источников в общий результат:

  • Nested Loop – вложенный цикл.

    В цикле открывается перебор подходящих записей ведущего (внешнего) источника. Для каждой из записей внешнего источника выбираются все записи из внутреннего (ведомого) источника, подходящие по условию соединения. Далее происходит переход к следующей записи ведущего источника. Для внешних соединений ведущим (первым по порядку, во внешнем цикле) всегда будет внешний источник, левый для LEFT OUTER JOIN или правый для RIGHT OUTER JOIN.

    Подходит для:

    • очень небольших наборов данных, особенно когда поддерживается индексами с обеих сторон соединения;

    • условий соединения, которые не являются равенствами (ON a.id >= b.first_a_id) (более того, это единственный метод выполнения таких условий).

    Не подходит:

    • при отсутствии индекса по ключу соединения со стороны ведомого источника — становится крайне неудобно отбирать записи из ведомого источника столько раз, сколько записей вернул ведущий;

    • при большом количестве записей в любом из источников.

  • Hash Join – хеш-соединение.

    Выбирается полностью ключ объединения из обоих источников. Для этого строится хеш-таблица выборки ключа из ведущего источника, размещается в памяти (work_mem), если места не хватает - то во временных файлах на диске. Из ведомого источника отбирать значения ключа, хешировать их и искать совпадения значений хеш-функций ключа: hash(a.id) = hash(b.a_id). При совпадении хешей сравнить ключи по данным из таблиц, разрешая конфликты хеширования и извлекая те данные, которых нет в ключе объединения.

    Подходит:

    • для объединения больших объемов данных, в том числе без поддержки индексов;

    • для условий объединения по присутствию в списке (EXISTS, IN) – называется Hash Semi Join;

    • и по отсутствию в списке (NOT EXISTS, NOT IN) — это Hash Anti Join.

    Не подходит:

    • когда ограничены физические ресурсы: недостаточно work_mem, мало свободного пространства для временных файлов – приходится хешировать ведущий источник порциями, повторять проходы ведомого источника по каждой из порций;

    • для внешних соединений — не поддерживает их.

  • Merge Join – соединение слиянием сортированных списков.

    Выбирается полностью ключ объединения из обоих источников. Для этого оба источника должны быть отсортированы. Далее сортированные списки значений объединяются между собой.

    Подходит для:

    • внешних соединений средних по объемам источников, особенно при поддержке индексов с обеих сторон.

    Не подходит:

    • когда ограничены физические ресурсы: недостаточно work_mem, мало места на диске, ограничены процессорные ресурсы для сортировки. Столь же чувствителен к work_mem, как и хеш-соединение. Предполагает размещение в памяти / на диске полных списков значений ключа для выполнения сортировки.

Фиксация порядка соединения таблиц#

Порядок таблиц в соединении имеет большое значение для планировщика. Например, 10 раз просканировать таблицу из 1 млн записей или 1 млн раз просканировать таблицу из 10 записей — операции разного порядка, по времени и по затратам ресурсов они существенно различаются.

Если количество соединяемых источников не превышает 3-5, то планировщику легко перебрать все варианты соединяемых пар. Если же источников более 12 (порог настраивается), то из-за огромного количества вариантов сочетаний будет применяться эвристический алгоритм (GEQO). Его задача — найти не самый оптимальный план, но сделать это быстро.

Если оптимальный порядок соединения найден, то зафиксировать его позволяет подсказка Leading.

  • Leading(таблица таблица[ таблица...]) — указание планировщику: объединять источники в указанном порядке, от ведущей таблицы до ближайшей к результату.

  • Leading(<пара для объединения>) — указание объединять пару источников в указанном порядке и направлении. Пара для объединения — пара, в которую могут входить таблицы и/или другие пары. Описания пар, заключенные в скобки, могут образовывать вложенные структуры.

Примеры:

  • Указание использовать порядок объединения

    /*+ Leading(t2 t3 t1) */ select t1.f2, t2.f2 from table1 t1 join table2 t2 on t1.f1=t2.f1 join table1 t3 on t3.f1=t2.f1 where t2.f1<1000;
    
  • Указание использовать порядок объединения с группировкой

    /*+ Leading((t2 (t3 t1))) */ select t1.f2, t2.f2 from table1 t1 join table2 t2 on t1.f1=t2.f1 join table1 t3 on t3.f1=t2.f1 where t2.f1<1000;
    

Установка pg_profile и pg_stat_kcache#

Установка всех расширений и их первоначальная настройка производится инсталлятором.

  • Расширению pg_profile требуются расширения plpgsql, dblink.

  • Расширению pg_stat_kcache требуется pg_stat_statements (устанавливается по умолчанию на всех серверах). Также pg_stat_statements должен быть указан в параметре shared_preload_libraries раньше.

Параметры установщика#

Параметр

Значение по умолчанию

Описание

pg_profile.is_enable

true

Установка базы с установленным расширением pg_profile и настроенным в pg_cron заданием на сборку статистики

pg_profile.topn

20

Количество основных объектов (statements, relations и т.д.), которые должны быть представлены в каждой отсортированной таблице отчета. Параметр влияет на размер выборки - чем больше объектов требуется отобразить в отчете, тем больше объектов нужно сохранить в выборке

pg_profile.max_sample_age

7

Срок хранения выборок в днях

pg_profile.track_sample_timings

off

Когда этот параметр включен, pg_profile будет отслеживать точное время сбора выборок

pg_profile.stats_periods

0,30 * * * *

Строка в стиле crontab для насторойки периодов сбора статистики, по умолчанию: раз в полчаса, каждый час в 0 и 30 минут

pg_stat_track_activities

on

Отслеживание выполняемых серверным процессом команд

pg_stat_track_counts

on

Контроль, собирается ли статистика о доступе к таблицам и индексам

pg_stat_track_io_timing

on

Отслеживание времени чтения и записи блоков

pg_stat_track_functions

off

Отслеживание использования пользовательских функций

pg_stat_statements_track

top

Контроль учитываемых модулем операторов

pg_stat_statements_max

5000

Максимальное количество операторов, отслеживаемых модулем (то есть максимальное количество строк в представлении pg_stat_statements)

pg_stat_kcache.is_enabled

true

Установка базы с установленным расширением pg_kcache

relnblocks_enable

on

Включение механизма подсчета (pg_profile автоматом подхватит значение из этого механизма, а не из pg_class). Изменение требует перезагрузки: в случае значения off память под кэш при старте выделена не будет

relnblocks_hash_max_size

1000000

Максимальное количество отношений (имеющих физические файлы на диске) в базе. В случае превышения заданного значения новое отношение создать будет нельзя. Нужно помнить, что к этим отношениям относятся таблица, индекс, генератор последовательности, таблица хранения сверхбольших атрибутов, материализованное представление. Необходимо внимательно отнестись к этому параметру и установить значение «с запасом»

relnblocks_hash_init_size

1024

Параметр определяет количество отношений в базе (имеющих физические файлы на диске), на которые будет предаллоцирован кэш. Кэш-таблица для отслеживания размеров объектов будет размещена одним выровненным куском памяти, и поиск по ней будет быстрее

Установка в ручном режиме#

При ручной установке необходимо выполнить следующие шаги:

  1. Установите файлы расширения pg_profile.

    Распакуйте файлы расширения в каталог с расширениями PostgreSQL, например:

        tar xzf pg_profile-<version>.tar.gz --directory $(pg_config --sharedir)/extension
    

    Необходимо убедиться, что используется подходящая утилита pg_config.

  2. Создайте расширения pg_profile.

    Рекомендуется установка в отдельную схему – расширение создает свои собственные таблицы, представления, последовательности и функции. Создайте схему для сбора статистики и установите расширение в эту схему:

    CREATE SCHEMA pgse_profile;
    CREATE EXTENSION dblink schema ext;
    CREATE EXTENSION plpgsql schema pgse_profile;
    CREATE EXTENSION pg_stat_statements schema ext;
    CREATE EXTENSION pg_profile SCHEMA pgse_profile;
    
  3. Настройте пользователя:

    CREATE ROLE profile_tuz NOLOGIN;
    REVOKE ALL ON SCHEMA pgse_profile FROM public;
    GRANT USAGE ON SCHEMA ext TO profile_tuz;
    GRANT USAGE ON SCHEMA pgse_profile TO profile_tuz;
    GRANT pg_read_all_stats TO profile_tuz;
    GRANT EXECUTE ON FUNCTION pg_stat_statements_reset TO profile_tuz;
    GRANT all ON all TABLES IN SCHEMA ext TO profile_tuz;
    GRANT SELECT, USAGE ON all sequences IN SCHEMA ext TO profile_tuz;
    GRANT EXECUTE ON all functions in SCHEMA ext TO profile_tuz;
    GRANT all ON all tables in SCHEMA pgse_profile TO profile_tuz;
    GRANT SELECT, USAGE ON all sequences IN SCHEMA pgse_profile TO profile_tuz;
    GRANT EXECUTE ON all functions IN SCHEMA pgse_profile TO profile_tuz;
    GRANT USAGE ON TYPE dblink_pkey_results TO profile_tuz;
    
  4. Настройте права пользователя as_admin.

  5. Настройте серверы pg_profile и задачи cron:

    SELECT pgse_profile.create_server('master', 'dbname={{ db_name }} host={{ hostname }} port={{ port }} user=profile_tuz');
    

    Если установка мастер + standalone:

    SELECT pgse_profile.create_server('slave', 'dbname={{ db_name }} host={{ hostname }} port={{ port }} user=profile_tuz'); ()
    

    В общем случае, если на одном экземпляре есть несколько БД, достаточно добавить один сервер, который обойдет все базы.

    SELECT cron.schedule('{{ pg_profile.stats_periods }}', 'SELECT pgse_profile.take_sample()');
    
  6. Обновите pg_profile до новой версии.

    Новые версии pg_profile будут содержать скрипт миграции (когда это возможно). В случае обновления необходимо установить новые файлы расширения (см. шаг 1) и обновить расширение:

    ALTER EXTENSION pg_profile UPDATE;
    
  7. Установите расширение pg_stat_kcache.

    Распакуйте файлы расширения в каталог с расширениями PostgreSQL:

    tar xzf pg_stat_kcache-<version>.tar.gz --directory $(pg_config --sharedir)/extension
    

    Убедитесь, что используется подходящая утилита pg_config.

  8. Cоздайте расширение pg_stat_kcache.

    Пропишите расширение в параметр предзагружаемых библиотек:

    shared_preload_libraries = 'pg_stat_statements,pg_stat_kcache'
    

    Внимание!

    Расширение pg_stat_kcache должно идти после pg_stat_statements, иначе база не запустится.

  9. Установите расширение в схему ext:

    CREATE EXTENSION pg_stat_kcache schema ext;
    -- Настройте пользователя:
    GRANT EXECUTE ON FUNCTION ext.pg_stat_kcache_reset TO profile_tuz;
    GRANT EXECUTE ON FUNCTION ext.pg_stat_kcache TO profile_tuz;
    -- Настроить права пользователя as_admin:
    GRANT EXECUTE ON FUNCTION ext.pg_stat_kcache_reset to as_admin;
    GRANT EXECUTE ON FUNCTION ext.pg_stat_kcache to as_admin;
    
  10. Обновите pg_stat_kcache до новой версии.

    Новые версии pg_stat_kcache будут содержать скрипт миграции (когда это возможно). Так, в случае обновления необходимо будет установить новые файлы расширения (см. шаг 1) и обновить расширение:

    ALTER EXTENSION pg_profile UPDATE;
    

Собрать статистику с других кластеров#

Расширение pg_profile, установленное на один кластер, может собирать также статистику с других кластеров, именуемых servers (далее — серверы).

Для этого:

  • создайте необходимые серверы (функция create_server()), указав имя и строку подключения (подробнее о функции читайте в документе «Список PL/SQL функций продукта», раздел «Отчетность по нагрузке Pangolin»);

  • убедитесь, что подключение может быть установлено ко всем БД всех серверов.

После этих действий можно собирать, например, статистику с пассивного узла кластера СУБД (Standby) подключаясь к ней с активного узла кластера СУБД (Active).

Настройка параметров#

Задать параметры настроек можно в файле postgresql.conf (указаны значения по умолчанию):

  • track_activities = on — мониторинг текущих команд для каждого процесса в pg_stat_activity;

  • track_counts = on — мониторинг текущих команд для каждого процесса в pg_stat_all_tables;

  • track_io_timing = on — мониторинг времени чтения/записи блоков в pg_stat_statements, pg_stat_kcache;

  • track_functions = none — включает подсчет вызовов функций и времени их выполнения. Значение pl включает отслеживание только функций на процедурном языке, а all — также функций на языках SQL и C для представления pg_stat_user_functions;

  • track_activity_query_size = 1024 — задает число байт, которое будет зарезервировано для отслеживания выполняемой в данный момент команды в каждом активном сеансе в pg_stat_statements.

Параметры pg_profile#

  • pg_profile.topn = 20 — количество основных объектов (statements, relations и т.д.), которые должны быть представлены в каждой отсортированной таблице отчета. Этот параметр влияет на размер выборки — чем больше объектов необходимо отобразить в отчете, тем больше объектов нужно сохранить в выборке;

  • pg_profile.max_sample_age = 7 — срок хранения выборок в днях. Выборки, возраст которых равен pg_profile.max_sample_age дней и более, будут автоматически удалены при следующем вызове take_sample();

  • pg_profile.track_sample_timings = off — когда этот параметр включен, расширение pg_profile будет отслеживать точное время сбора выборок;

  • pg_profile.query_length = 20000 — ограничение размера запросов, применяется только к тем запросам, которые выполнялись во время сбора статистики. Не применяется к запросам из pg_stat_statements.

Параметры pg_stat_statements (влияют на pg_stat_kcache)#

  • pg_stat_statements.max = 5000 (из установщика) — максимальное количество различных запросов, по которым хранится статистика. Если этот параметр будет недостаточно большим — расширение pg_profile будет выдавать предупреждения (в случае, если кэш при сборе статистики заполнен на 80%);

  • pg_stat_statements.track = 'top' — типы запросов (top/nested) по которым хранится статистика: top, all, none;

  • pg_stat_statements.track_utility = 'on' — при значении параметра off, статистика будет храниться только для запросов SELECT, INSERT, UPDATE и DELETE;

  • pg_stat_statements.track_planning = 'off' — сохранять отдельно статистику этапа планирования;

  • pg_stat_statements.save = 'on' — сохранять статистику в файл, в случае штатной перезагрузки сервера.

Параметры pg_stat_kcache#

  • pg_stat_kcache.linuz_hz = -1 — установить частоту аппаратных прерываний (тиков ЦПУ) для компенсации ошибок выборки. Для данного расширения можно явно указать, какой параметр задан в системе (параметр CONFIG_HZ ядра linux). По умолчанию установлено значение -1 — это означает, что расширение попытается автоматически рассчитать эту частоту при старте.

Параметры подсчета точных размеров отношений (указаны значения по умолчанию)#

  • relnblocks_enable = 'on' — включение механизма подсчета (pg_profile автоматом подхватит значение из этого механизма, а не из pg_class);

  • relnblocks_hash_max_size = 1000000 — максимальное количество отношений (имеющих физические файлы на диске) в базе. В случае переполнения этого числа новое отношение нельзя будет создать.

    Внимание!

    Необходимо внимательно отнестись к параметру relnblocks_hash_max_size и взять достаточный запас, так как к этим отношениям относятся:

    • таблица;

    • индекс;

    • генератор последовательности;

    • таблица хранения сверхбольших атрибутов;

    • материализованное представление.

  •   `relnblocks_hash_init_size = 1024` — количество отношений (имеющих физические файлы на диске) в базе, на которые будет предварительно выделен кэш.
    

    В этом случае хеш-таблица для отслеживания размеров объектов будет размещена одним выровненным куском памяти, и поиск по ней будет быстрее.

Использование pg_profile#

Во время установки расширение создает один активированный локальный сервер для кластера, где установлено расширение.

При необходимости можно добавить дополнительные сервера для сбора статистики командой:

SELECT pgse_profile.create_server('omega','host=name_or_ip dbname=postgres port=5432');

Выборки#

Каждая выборка содержит статистическую информацию о рабочей нагрузке БД со времени предыдущей выборки.

Функция сбора выборок также обслуживает хранилище сервера — удаляет устаревшие выборки в соответствии с политикой хранения.

Сохранение выборки#

Нужно собрать не меньше 2 выборок, чтобы иметь возможность создания первого отчета между 1-ой и 2-ой выборками. Выборки для всех активированных серверов собираются вызовом функции take_sample(). Как правило, собирают одну или две выборки в час.

Для взятия выборок по расписанию можно использовать cron или похожие инструменты. Пример с 30-ти минутным периодом:

*/30 * * * *   psql -c 'SELECT pgse_profile.take_sample();' > /dev/null 2>&1

Рассмотренный выше вызов функции не имеет проверки на ошибки результатов take_sample().

Функцию take_sample() можно вызвать так, чтобы она вернула OK для всех серверов, где выборка взята успешно, и показала текст ошибки для неудачных попыток:

select * from take_sample();

server     |        result                                                                 |      elapsed
-----------+-------------------------------------------------------------------------------+---------------
 ok_node   |          OK                                                                   | 00:00:00.48
 fail_node | could not establish connection                                               +| 00:00:00
           | SQL statement "SELECT dblink_connect('server_connection',server_connstr)"    +|
           | PL/pgSQL function take_sample(integer) line 69 at PERFORM                    +|
           | PL/pgSQL function take_sample_subset(integer,integer) line 27 at assignment  +|
           | SQL function "take_sample" statement 1                                       +|
           | FATAL:  database "nodb" does not exist                                        |
(2 rows)
Хранение данных выборки#

Чтобы не хранить данные выборок вечно, существует политика хранения.

Уровни хранения:

  1. Обычное хранение (действует, если не определен другой уровень хранения). Задайте параметр pg_profile.max_sample_age в файле postgresql.conf.

  2. Определите параметр max_sample_age сервера при создании сервера или с помощью функции set_server_max_sample_age() для существующего сервера.

    Примечание:

    Параметр max_sample_age отменяет глобальный параметр pg_profile.max_sample_age для конкретного сервера.

  3. Baseline переопределяет срок хранения для включенных (included) выборок с наивысшим приоритетом. Создайте baseline (см. ниже раздел «Baselines»).

Список выборок#

Используйте функцию show_samples(), чтобы получить список существующих выборок в репозитории. Эта функция также покажет обнаруженное время сброса статистики.

Подробное описание функции show_samples() в документе «Список PL/SQL функций продукта», раздел «Отчет по нагрузке Pangolin».

Тайминги сбора выборок#

Расширение pg_profile будет собирать подробную статистику по времени сбора выборок, когда включен параметр pg_profile.track_sample_timings.

Baselines#

Baseline — это именованная последовательность выборок с собственными настройками хранения.

Baseline можно использовать в функциях построения отчетов как интервал выборки. Неопределенный baseline хранения означает бесконечное хранение.

Baselines можно использовать для сохранения информации о загруженности базы данных за определенный период времени. Например, можно сохранить выборки, собранные во время нагрузочного тестирования или во время регулярной нагрузки на систему для дальнейшего использования.

Отчеты#

Отчеты создаются в формате HTML функциями по работе с отчетами. В pg_profile есть два типа доступных отчетов:

  • регулярные отчеты — содержат статистическую информацию о загруженности экземпляра за период отчета;

  • отчеты по изменениям — содержат данные из двух интервалов со значениями статистики с одинаковых объектов, расположенных один за другим, что упрощает сравнение рабочей нагрузки.

Посмотреть отчет можно в любом веб-браузере.

Функции регулярных отчетов и отчетов по изменениям описаны в документе «Список PL/SQL функций продукта», раздел «Отчет по нагрузке Pangolin».

Построить отчет по изменениям можно также с помощью следующих комбинаций:

get_diffreport([server name,] baseline varchar(25), time_range tstzrange [, description text])

get_diffreport([server name,] time_range tstzrange, baseline varchar(25) [, description text])

get_diffreport([server name,] start1_id integer, end1_id integer, baseline varchar(25) [, description text])

get_diffreport([server name,] baseline varchar(25), start2_id integer, end2_id integer [, description text])

Описание и примеры разделов отчета по нагрузке представлены в отдельном документе «Описание структуры отчета по нагрузке Pangolin».

Примеры формирования отчетов#
psql -Aqtc "SELECT profile.get_report(480,482)" -o report_480_482.html

Для любых других серверов по их именам:

psql -Aqtc "SELECT profile.get_report('omega',12,14)" -o report_omega_12_14.html

Формирование отчета по временному промежутку:

psql -Aqtc "select profile.get_report(tstzrange('2020-05-13 11:51:35+03','2020-05-13 11:52:18+03'))" -o report_range.html

Формирование отчета за последние 24 часа:

psql -Aqtc "select profile.get_report(tstzrange(now() - interval '1 day',now()))" -o last24h_report.html

Отключение функциональности#

Отключение pg_stat_kcache#
  1. Удалите значение pg_stat_kcache из параметра shared_preload_libraries.

  2. Перезагрузите сервер.

Отключение подсчета точного размера отношений:#

Установите relnblocks_enable в off.

Отключение сбора статистика pg_profile (не требует перезагрузки#
  1. Определите jobid задачи для pg_profile с помощью запроса:

    SELECT * from cron.job;
    
  2. Отключите задачу запросом:

    SELECT cron.unschedule(jobid);
    

Отслеживание времени изменения объекта СУБД#

В целях повышения удобства сопровождения СУБД, при выявлении причин снижения ее производительности, вызванного выполнением DDL-операций над объектами БД, предоставляется инструмент в виде двух представлений psql_dba_objects и psql_all_objects.

Данные представления используются для отслеживания даты/времени последней модификации объектов СУБД psql_dba_objects и psql_all_objects.

Пример выполнения запроса представления psql_dba_objects:

select * from pg_catalog.psql_dba_objects;
-[ RECORD 1 ]-+------------------------------
oid           | 16384
name          | t1
namespace     | 2200
type          | table
owner         | postgres
ispredef      | f
created       | 2022-05-31 12:58:20.765479+03
last_ddl_time | 2022-05-31 12:58:20.765479+03
deleted       |

Пример выполнения запроса представления psql_all_objects:

select * from pg_catalog.psql_all_objects;
-[ RECORD 1 ]-+------------------------------
oid           | 16384
name          | t1
namespace     | 2200
type          | table
owner         | postgres
ispredef      | f
created       | 2022-05-31 12:58:20.765479+03
last_ddl_time | 2022-05-31 12:58:20.765479+03
deleted       |

Примечание:

Обновление поля last_ddl_time осуществляется в обработчиках DDL-команд, изменяющих логическую структуру объекта, а так же GRANT/REVOKE. В обработчиках остальных DDL-команд, не модифицирующих логическую структуру объекта, значение поля не меняется. К таким DDL-командам относятся:

  • REINDEX;

  • CLUSTER;

  • TRUNCATE;

  • VACUUM;

  • VACUUM FULL;

  • REFRESH MATERIALIZED VIEW [CONCURRENTLY].

Для очистки записей о датах изменения удаленных объектов используется функция purge_object_mod_dates([start_time timestamptz, end_time timestamptz]) void.

Функция принимает на вход начало и конец интервала времени, в пределах которого требуется очистить записи объектов, даты удаления которых попадают в этот интервал. Входные аргументы могут быть опущены, тогда функция удалит записи о всех удаленных объектах за все время существования БД.

В качестве неопределенной границы интервала времени может использоваться значение NULL. Вызов упрощенной вариации функции без аргументов purge_object_mod_dates() равнозначен вызову purge_object_mod_dates(NULL, NULL) и purge_object_mod_dates('-infinity', 'infinity').

Пример использования функции purge_object_mod_dates():

select purge_object_mod_dates('2022-06-08 09:24:51'::timestamptz, '2022-06-08 10:24:51'::timestamptz);
select purge_object_mod_dates('-infinity', '2022-06-08 10:24:51'::timestamptz);
select purge_object_mod_dates('2022-06-08 09:24:51'::timestamptz, 'infinity');
select purge_object_mod_dates('-infinity', 'infinity');
select purge_object_mod_dates(NULL, '2022-06-08 10:24:51'::timestamptz);
select purge_object_mod_dates('2022-06-08 09:24:51'::timestamptz, NULL);
select purge_object_mod_dates(NULL, NULL);
select purge_object_mod_dates();
select purge_object_mod_dates(now() - interval '1 day', now());

Для сохранения информации о датах изменения удаленных объектов, в течение некоторого интервала времени, введен параметр object_modification_date_keep_interval. В пределах этого интервала времени функции очистки запрещено удалять записи с датами изменения удаленных объектов, которые входят в этот интервал. Интервал отсчитывается от момента выполнения функции очистки psql_purge_object_mod_dates(). Параметр принимает неотрицательные значения типа interval. Если указан нулевой интервал (0), то ограничения на выполнение функции очистки не накладываются. Значение по умолчанию - 1 week (1 неделя). Для изменения параметра необходим перезапуск сервера Pangolin.

Внимание!

Может потребоваться увеличить параметр max_worker_processes, чтобы это число включало дополнительные рабочие процессы, обновляющие даты создания и модификации объектов в новой БД после ее создания.

Отключению функциональности#

Для включения/отключения функциональности предназначен конфигурационный параметр enable_monitor_object_modification_date (в файле postgresql.conf). Значение параметра по умолчанию - on. Для изменения параметра необходим перезапуск сервера Pangolin.

Управление планами запросов#

Для возможности ручной оптимизации планов запросов в Pangolin используются расширения pg_outline и pg_hint_plan.

Расширение pg_hint_plan#

Расширение pg_hint_plan управляет планом выполнения с помощью фраз-подсказок (hint), записываемых в виде простых описаний в SQL-комментариях особого вида.

Настроечные параметры pg_hint_plan#

Для Pangolin расширение pg_hint_plan модифицировано: запросы создания, изменения и удаления ролей не обрабатываются расширением pg_hint_plan и не попадают в лог даже при включенном детальном логировании расширения.

Наименование

Описание

Значение по умолчанию

Рекомендуемое значение

pg_hint_plan.enable_hint

Включает/выключает pg_hint_plan

on

on

pg_hint_plan.enable_hint_table

Разрешает/запрещает использование подсказок (hint) для запросов из таблицы подсказок

on

pg_hint_plan.parse_messages

Определяет уровень логирования, с которым в журнал будут попадать сообщения об ошибках разбора подсказок. Допустимые значения*: error, warning, notice, info, log, debug

info

warning

pg_hint_plan.debug_print

Указывает детализацию отладочных сообщений. Допустимые значения**: off, on, detailed, verbose

off

pg_hint_plan.message_level

Определяет уровень логирования для отладочных сообщений. Допустимые значения*: error, warning, notice, info, log, debug

info

* — Уровни важности сообщений ошибок синтаксического анализа и отладочных сообщений. Описание допустимых значений:

  • ERROR — сообщает об ошибке, из-за которой прервана текущая команда;

  • WARNING — предупреждения о возможных проблемах;

  • NOTICE — информация, которая может быть полезной пользователям;

  • INFO — неявно запрошенная пользователем информация;

  • LOG — информация, полезная для администраторов;

  • DEBUG — максимальный уровень детализации для разработчиков.

** – Детализация отладочных сообщений — количество информации, записываемой в журнал сервера для каждого сообщения. Каждое последующее значение добавляет больше полей в выводимое сообщение. Описание допустимых значений:

  • off — 0 (сообщения выключены);

  • on — 1;

  • detailed — 2;

  • verbose — 3.

Активация расширения#

Расширение pg_hint_plan по умолчанию выключено.

Чтобы включить расширение pg_hint_plan, используйте настроечные параметры pg_hint_plan.enable_hint и pg_hint_plan.enable_hint_table:

  • для применения ко всем сессиям — установите значение on в postgresql.conf;

  • для конкретных сессий — установите значение true через команды SET или ALTER USER SET/ALTER DATABASE SET.

Пример:

SET pg_hint_plan.enable_hint = TRUE;
SET pg_hint_plan.enable_hint_table = TRUE;

Установка в ручном режиме#

В некоторых случаях (например, создана новая база, или расширения не были установлены во время работы инсталлятора Pangolin) установку расширений необходимо произвести вручную, для этого:

  1. Добавьте значения pg_stat_statements, pg_hint_plan и pg_outline в настроечный параметр shared_preload_libraries в конфигурационном файле PostgreSQL.conf.

  2. Подключите расширения:

    create extension pg_stat_statements;
    create extension pg_hint_plan;
    create extension pg_outline;
    
  3. Включите расширения pg_outline и pg_hint_plan (см. «Руководство по системному администрированию», раздел «Сценарии администрирования», подраздел «Управление планами запросов»).

Отключение функциональности#

Чтобы отключить функциональность расширения, установите значение off для настроечных параметров pg_hint_plan.enable_hint и pg_hint_plan.enable_hint_table.

Для полного отключения функциональности исключите загрузку библиотеки для всего экземпляра Pangolin одним из следующих способов:

  • исключите библиотеку из параметра shared_preload_libraries;

  • измените настройки конкретных сессий через ALTER USER SET/ALTER DATABASE SET.

После отключения функциональности удалите расширение командой:

DROP EXTENSION pg_hint_plan

Включение журналирования#

Чтобы включить журналирование, в конфигурации сервера необходимо применить рекомендуемые настройки:

pg_hint_plan.parse_messages = warning
pg_hint_plan.debug_print = off
pg_hint_plan.message_level = debug

Методы доступа#

Чтобы вручную закрепить в запросе оптимальный метод доступа или отменить неоптимальный, применяются следующие подсказки:

Метод доступа

Узел в плане

Подсказка для включения

Подсказка для выключения

Последовательное сканирование таблицы

Seq Scan

SeqScan(таблица)

NoSeqScan(таблица)

Индексное сканирование таблицы

Index Scan
Index Scan Backward

IndexScan(таблица[ индекс…])
IndexScanRegexp(таблица[ POSIX Regexp…])

NoIndexScan(таблица)

Строгое индексное сканирование таблицы

Index Only Scan

IndexOnlyScan(таблица[ индекс…])
IndexOnlyScanRegexp(таблица[ POSIX Regexp…])

Любая подсказка из
NoIndexOnlyScan(таблица)
или NoIndexScan(таблица)

Сканирование таблицы по битовой карте индекса

Bitmap Index Scan →
Bitmap Heap Scan
BitmapAnd, BitmapOr

BitmapScan(таблица[ индекс…])
BitmapScanRegexp(таблица[ POSIX Regexp…])

NoBitmapScan(таблица)

Сканирование таблицы по TID

Tid Scan

TidScan(таблица)

NoTidScan(таблица)

Здесь POSIX Regexp... – список регулярных выражений, используемых для того, чтобы не перечислять поодиночке множество индексов с похожими названиями.

Чтобы зафиксировать метод доступа, в подсказке указывается псевдоним таблицы-источника и, если в методе используются индексы — их также нужно перечислить, разделяя список пробелами.

Внимание!

Подсказка NoIndexScan включает в себя действие подсказки NoIndexOnlyScan.

Наличие карты видимости таблицы (слой visibility map) необходимо для метода доступа Index Only Scan. Этот слой по умолчанию не создается при создании таблицы, поэтому до первого autovacuum / VACUUM / VACUUM FULL по новой таблице не получится осуществить доступ к таблице методом Index Only Scan.

Если индекс, указанный в подсказке IndexOnlyScan, недостаточен для поддержки строгого сканирования (например, не хватает полей до списка запрошенных), то индексное сканирование таблицы может неожиданно выполняться через другой индекс.

Примеры:

  • Указание использовать сканирование по конкретному индексу:

    /*+ IndexScan(t1 ix_table1_2ind_f1_f2) */ select ctid, * from table1_2ind t1 where f1 = 10;
    
  • Указание не использовать последовательное сканирование:

    /*+ NoSeqScan(t1) */ select * from table1 t1 where t1.f1 > 1;
    

Закрепить в запросе выбранный метод объединения можно при помощи подсказок:

Метод объединения источников

Узел в плане

Подсказка для включения

Подсказка для выключения

Nested Loop – вложенный цикл

Nested Loop

NestLoop(таблица таблица[ таблица…])

NoNestLoop(таблица таблица[ таблица…])

Hash Loin - хеш-соединение

Hash Join
Hash Semi Join
Hash Anti Join

HashJoin(таблица таблица[ таблица…])

NoHashJoin(таблица таблица[ таблица…])

Merge Join - соединение слиянием сортированных списков

Merge Join
Merge Left Join
Merge Right Join

MergeJoin(таблица таблица[ таблица…])

NoMergeJoin(таблица таблица[ таблица…])

Примеры:

  • Указание использовать объединение nested loop:

    /*+ NestLoop(t1 t2)*/ select t1.f2, t2.f2 from table1 t1, table2 t2 where t1.f1=t2.f1;
    
  • Указание не использовать объединение hash join:

    /*+ NoHashJoin(t1 t2) */ select t1.f2 from table1 t1 where t1.f2 in (select f2 from table2 t2 where f2 > '10000');
    

Список подсказок (hints)#

Подсказки подразделяются на шесть групп по видам объектов, на которые они могут воздействовать, и видам воздействия. Список доступных подсказок перечислен ниже:

Группа

Формат

Описание

Метод сканирования

SeqScan(таблица)

Принудительное последовательное сканирование таблицы

TidScan(таблица)

Принудительное сканирование таблицы по TID

IndexScan(таблица[ индекс...])

Принудительное сканирование таблицы по индексу. Сканирование ограничивается заданными индексами

IndexOnlyScan(таблица[ индекс...])

Принудительное сканирование таблицы по индексу. Сканирование ограничивается заданными индексами. Если сканирование только по индексу невозможно, может использоваться обычное сканирование по индексу

BitmapScan(таблица[ индекс...])

Принудительное сканирование таблицы по битовой карте. Сканирование ограничивается заданными индексами

IndexScanRegexp(таблица[ регулярное выражение POSIX...])

Принудительно выбирает сканирование таблицы по индексу. Сканирование ограничивается индексами с именами, соответствующими указанному регулярному выражению POSIX

IndexOnlyScanRegexp(table[ регулярное выражение POSIX...])

Принудительно выбирает сканирование таблицы только по индексу. Сканирование ограничивается индексами с именами, соответствующими указанному регулярному выражению POSIX

BitmapScanRegexp(table[ регулярное выражение POSIX...])

Принудительно выбирает сканирование таблицы по по битовой карте. Сканирование ограничивается индексами с именами, соответствующими указанному регулярному выражению POSIX

NoSeqScan(таблица)

Принудительное отключение выбора последовательного сканирования таблицы

NoTidScan(таблица)

Принудительное отключение выбора сканирования таблицы по TID

NoIndexScan(таблица)

Принудительное отключение выбора сканирования таблицы по индексу и сканирования только по индексу для заданной таблицы

NoIndexOnlyScan(таблица)

Принудительное отключение выбора сканирования только по индексу для заданной таблицы

NoBitmapScan(таблица)

Принудительное отключение выбора сканирования по битовой карте для таблицы

Метод соединения

NestLoop(таблица таблица[ таблица...])

Принудительный выбор вложенного цикла для соединений с заданными таблицами

HashJoin(таблица таблица[ таблица...])

Принудительный выбор соединения по хешу для соединений с заданными таблицами

MergeJoin(таблица таблица[ таблица...])

Принудительный выбор соединения слиянием для соединений с заданными таблицами

NoNestLoop(таблица таблица[ таблица...])

Принудительное отключение выбора вложенного цикла для соединений с заданными таблицами

NoHashJoin(таблица таблица[ таблица...])

Принудительное отключение выбора соединения по хешу для соединений с заданными таблицами

NoMergeJoin(таблица таблица[ таблица...])

Принудительное отключение выбора соединения слиянием для соединений с заданными таблицами

Порядок соединения

Leading(таблица таблица[ таблица...])

Принудительный выбор заданного порядка соединения

Leading(<соединяемая пара>)

Принудительный выбор заданного порядка и направления соединения. Соединяемая пара — это пара таблиц и/или других соединяемых пар, заключенная в скобки, что позволяет образовывать вложенные структуры

Корректировка числа строк

Rows(таблица таблица[ таблица...] корректировка)

Корректировка числа строк, получаемых в результате соединения указанных таблиц. Для корректировки можно задать абсолютное значение (#) или использовать сложение (+), вычитание (-) и умножение (*). — это строка, которую сможет прочитать функция strtod()

Настройка параллельных запросов

Parallel(таблица<число исполнителей> [soft/hard])

Принудительное включение или отключение параллельной обработки заданной таблицы. <число исполнителей> определяет желаемое количество параллельных исполнителей (значение 0 отключает параллельное выполнение). Если третий параметр равен soft (по умолчанию), меняется только значение параметра сервера max_parallel_workers_per_gather, а в остальном планировщику остается свобода выбора. Со значением hard заданное количество исполнителей устанавливается принудительно

GUC

Set(GUC-параметр значение)

Установка значения для GUC-параметра на время планирования запроса

Примечание:

Подробная информация о расширении pg_hint_plan приведена в официальной документации.

Особенности#

В данном разделе приведены особенности работы с расширением pg_hint_plan.

Использование с PL/pgSQL#

Расширение pg_hint_plan работает с запросами в PL/pgSQL блоках с некоторыми ограничениями:

  • подсказки (hint) действуют только на следующие типы запросов:

    • запросы, возвращающие одну запись (SELECT, INSERT, UPDATE и DELETE);

    • запросы, возвращающие множественные записи (RETURN QUERY);

    • динамические SQL-выражения (EXECUTE);

    • открытие курсора (OPEN);

    • итерация по результату запроса (LOOP FOR);

  • комментарий с подсказкой (hint) должен быть помещен после первого слова запроса, так как обработка выражений PL/pgSQL отбрасывает комментарии вне выражений (комментарий перед выражением также будет отброшен).

    CREATE FUNCTION hints_func(integer) RETURNS integer AS $$
    DECLARE
        id  integer;
        cnt integer;
    BEGIN
        SELECT /*+ NoIndexScan(a) */ aid
            INTO id FROM pgbench_accounts a WHERE aid = $1;
        SELECT /*+ SeqScan(a) */ count(*)
            INTO cnt FROM pgbench_accounts a;
        RETURN id + cnt;
    END;
    $$ LANGUAGE plpgsql;
    
Строчные и прописные символы в именах объектов#

Имена объектов в подсказках (hint) регистрозависимы.

Например, имя объекта TBL в подсказке соответствует только имени "TBL" в базе данных и не соответствует именам без кавычек TBL, tbl и Tbl.

Экранирование спецсимволов в именах объектов#

Объекты в параметрах подсказок pg_hint_plan, которые содержат скобки, двойные кавычки или пробелы, должны быть заключены в двойные кавычки. Правила экранирования символов в Pangolin аналогичны правилам PostgreSQL.

Конкретный вход таблицы при множественном использовании#

Расширение pg_hint_plan идентифицирует целевые объекты подсказок (hint) с использованием псевдонимов (alias), если они заданы.

Пример применения: необходимо указать на конкретное использование объекта в выражении, в котором объект используется множество раз.

/*+ HashJoin(t1 t1) */
EXPLAIN SELECT * FROM s1.t1
JOIN public.t1 ON (s1.t1.id=public.t1.id);
INFO:  hint syntax error at or near "HashJoin(t1 t1)"
DETAIL:  Relation name "t1" is ambiguous.
...
/*+ HashJoin(pt st) */
EXPLAIN SELECT * FROM s1.t1 st
JOIN public.t1 pt ON (st.id=pt.id);
                             QUERY PLAN
---------------------------------------------------------------------
 Hash Join  (cost=64.00..1112.00 rows=28800 width=8)
   Hash Cond: (st.id = pt.id)
   ->  Seq Scan on t1 st  (cost=0.00..34.00 rows=2400 width=4)
   ->  Hash  (cost=34.00..34.00 rows=2400 width=4)
         ->  Seq Scan on t1 pt  (cost=0.00..34.00 rows=2400 width=4)
Управление планом запроса в представлении или правиле перезаписи#

Подсказки (hint) не применимы к представлениям в выражениях, но могут влиять на поведение запросов, если находятся в тексте самих представлений.

Это возможно, если имена объектов в подсказках соответствуют именам объектов в представлениях.

Если имена не совпадают, объектам в представлениях можно назначить псевдонимы. Использование псевдонимов в запросах позволит обращаться к представлениям и влиять на поведение запроса.

CREATE VIEW v1 AS SELECT * FROM t2;
EXPLAIN /*+ HashJoin(t1 v1) */
          SELECT * FROM t1 JOIN v1 ON (c1.a = v1.a);
                            QUERY PLAN
------------------------------------------------------------------
 Hash Join  (cost=3.27..18181.67 rows=101 width=8)
   Hash Cond: (t1.a = t2.a)
   ->  Seq Scan on t1  (cost=0.00..14427.01 rows=1000101 width=4)
   ->  Hash  (cost=2.01..2.01 rows=101 width=4)
         ->  Seq Scan on t2  (cost=0.00..2.01 rows=101 width=4)
Наследование таблиц#

Подсказки (hint) могут указывать только на родителя наследования, и подсказка влияет на всех наследников. Подсказки, одновременно указывающие прямо на наследников, игнорируются.

Подсказки для множественных запросов#

У одного множественного выражения может быть ровно один комментарий с подсказкой, и подсказки влияют на все отдельные выражения в множественном выражении.

Примечание:

В интерактивном интерфейсе psql выполнение запросов выглядит как операция из множества шагов, однако внутренне представляет собой последовательность отдельных выражений, поэтому подсказки (hint) влияют только на следующее отдельное выражение.

Выражение VALUES#

Все выражения VALUES в предложении FROM имеют внутреннее имя VALUES, поэтому к ним можно обращаться, только если они единственные VALUES в запросе. По результатам выполнения EXPLAIN два или более выражения VALUES в запросе будут выглядеть по-разному, но это лишь визуальное улучшение, и они не различимы.

/*+ MergeJoin(*VALUES*_1 *VALUES*) */
      EXPLAIN SELECT * FROM (VALUES (1, 1), (2, 2)) v (a, b)
      JOIN (VALUES (1, 5), (2, 8), (3, 4)) w (a, c) ON v.a = w.a;
INFO:  pg_hint_plan: hint syntax error at or near "MergeJoin(*VALUES*_1 *VALUES*) "
DETAIL:  Relation name "*VALUES*" is ambiguous.
                               QUERY PLAN
-------------------------------------------------------------------------
 Hash Join  (cost=0.05..0.12 rows=2 width=16)
   Hash Cond: ("*VALUES*_1".column1 = "*VALUES*".column1)
   ->  Values Scan on "*VALUES*_1"  (cost=0.00..0.04 rows=3 width=8)
   ->  Hash  (cost=0.03..0.03 rows=2 width=8)
         ->  Values Scan on "*VALUES*"  (cost=0.00..0.03 rows=2 width=8)
Подзапросы#

Подзапросы в следующем контексте иногда можно указать в подсказке (hint), используя имя ANY_subquery.

IN (SELECT ... {LIMIT | OFFSET ...} ...)
= ANY (SELECT ... {LIMIT | OFFSET ...} ...)
= SOME (SELECT ... {LIMIT | OFFSET ...} ...)

Для такого синтаксиса при планировании объединений для таблиц, включающих подзапрос, планировщик внутренне присваивает этому подзапросу имя, поэтому подсказки объединения применимы к таким объединениям с использованием неявного имени, как показано ниже.

/*+HashJoin(a1 ANY_subquery)*/
EXPLAIN SELECT *
    FROM pgbench_accounts a1
    WHERE aid IN (SELECT bid FROM pgbench_accounts a2 LIMIT 10);
                                         QUERY PLAN

---------------------------------------------------------------------------------------------
 Hash Semi Join  (cost=0.49..2903.00 rows=1 width=97)
   Hash Cond: (a1.aid = a2.bid)
   ->  Seq Scan on pgbench_accounts a1  (cost=0.00..2640.00 rows=100000 width=97)
   ->  Hash  (cost=0.36..0.36 rows=10 width=4)
         ->  Limit  (cost=0.00..0.26 rows=10 width=4)
               ->  Seq Scan on pgbench_accounts a2  (cost=0.00..2640.00 rows=100000 width=4)
Использование подсказки IndexOnlyScan#

Сканирование индекса может неожиданно начать выполняться для другого индекса в том случае, если индекс, указанный в подсказке IndexOnlyScan, оказывается неподходящим для сканирования строго по индексу.

Поведение подсказки NoIndexScan#

Подсказка NoIndexScan включает NoIndexOnlyScan.

Подсказка Parallel и UNION#

UNION может работать в параллельном режиме, только если все базовые подзапросы безопасны для параллельного выполнения. И наоборот, принудительное параллельное выполнение любого из подзапросов позволяет параллельно исполняемому UNION работать параллельно.

Между тем, подсказка PARALLEL с нулевыми рабочими параметрами запрещает параллельное сканирование.

Установка значений параметров pg_hint_plan через подсказку Set#

Параметры pg_hint_plan изменяют поведение самих себя в указанном случае, поэтому некоторые параметры работают не так, как ожидалось:

  • подсказки по изменению enable_hint, enable_hint_tables игнорируются, хотя в логах отладки они указываются как примененные «used hints»;

  • установка debug_print и message_level начинает работать с середины обработки целевого запроса.

Ошибки#

Расширение pg_hint_plan прекращает синтаксический анализ при любой ошибке и в большинстве случаев использует подсказки (hint), уже проанализированные на момент ошибки. Далее приведены типичные ошибки.

  • Синтаксические ошибки — любые синтаксические ошибки или неправильные имена подсказок (hint) сообщаются как синтаксическая ошибка. Эти ошибки регистрируются в журнале сервера с уровнем сообщения, который указан в pg_hint_plan.message_level, при условии, что pg_hint_plan.debug_print имеет значение отличное от off.

  • Неверно указан объект — если объект указан неверно — подсказки (hint) будут тихо проигнорированы. Об этом виде ошибки сообщается в журнале сервера как «not used hints», при условии, что pg_hint_plan.debug_print имеет значение отличное от off.

  • Избыточные или конфликтующие подсказки — при повторяющихся или конфликтующих подсказках (hint), применяться будет последняя подсказка (hint). Об ошибках такого типа в журнале сервера сообщается как о «duplication hints» при условии, что pg_hint_plan.debug_print имеет значение отличное от off.

  • Вложенные комментарии — комментарий-подсказка (hint) не может включать в себя другой комментарий блока. При нахождении такого комментария pg_hint_plan, в отличие от других ошибок, прекращает синтаксический анализ и отбрасывает все уже проанализированные подсказки (hint). Об этой ошибке сообщается так же, как и о других ошибках.

Функциональные ограничения#

В данном разделе приведены функциональные ограничения для расширения pg_hint_plan.

  • Влияние некоторых GUC параметров планировщика — планировщик не учитывает порядок присоединения для предложений FROM, где количество элементов превышает from_collapse_limit. В таком случае расширение pg_hint_plan не может повлиять на порядок присоединения.

  • Подсказки, пытающиеся задать невыполнимые планы — в случае, когда указанный подсказкой (hint) план выполнить нельзя, планировщик выбирает любые исполнимые планы:

    • использовать вложенный цикл для FULL OUTER JOIN;

    • использовать индексы, столбцы которых не указаны в условиях;

    • выполнить сканирование по TID для запросов без условий по ctid.

  • Запросы в ECPGECPG удаляет комментарии в запросах, написанных как embedded SQL, поэтому подсказки (hint) не могут передаваться из этих запросов. Единственное исключение — команда EXECUTE передает заданную строку без изменений. Для таких случаев используйте таблицу подсказок.

  • Работа совместно с pg_stat_statements — расширение pg_stat_statements генерирует идентификатор запроса (query id), игнорируя комментарии. В результате одинаковые запросы с разными подсказками (hint) объединяются в один и тот же запрос.

Расширение pg_outline#

Расширение pg_outline устанавливается во время работы инсталлятора Pangolin и по умолчанию выключено.

Активация расширения#

Перед использованием расширения pg_outline рекомендуется настроить защиту от изменения таблицы outline.outlines и триггера предотвращения изменения таблицы (pg_outline_prevent_table_modification). Для этого нужно поместить таблицу outline.outlines под защиту при включенной защите от привилегированных пользователей.

Включить расширение pg_outline можно:

  • только для текущей сессии:

    SET pg_outline.enable = TRUE;
    
  • для всех сессий — в postgresql.conf пропишите:

    pg_outline.enable = on
    

Подмена подсказок#

Получение идентификатора запроса (query ID)#

Идентификатор запроса используется для сопоставления выполняемого запроса и правила фиксации и/или подмены этого запроса.

Получить идентификатор в ручном режиме можно через:

  • расширение pg_stat_statement;

  • функцию outline.identify (см. «Список PL/SQL функций продукта», раздел «Функциональные возможности расширения pg_outline»).

Получение идентификатора при помощи расширения pg_stat_statement#

Для получения идентификатора при помощи расширения pg_stat_statement выполните:

  1. Если запрос, для которого нужно узнать идентификатор, выполняется впервые, сначала выполните любой простой запрос, например:

    SELECT * FROM table1;
    
  2. Найдите идентификатор запроса (поле queryid) в таблице расширения pg_stat_statements:

    SELECT * FROM pg_stat_statements;
    

    Примечание:

    Идентификатор запроса (поле queryid) представляет собой целое положительное или отрицательное число.

Получение идентификатора при помощи функции outline.identify#

Для получения идентификатора передайте текст запроса в качестве аргумента:

SELECT outline.identify( 'SELECT * FROM mytable WHERE x=10;' );

Примечание:

В тексте запроса (queryText) обязательно укажите все константы. Это необходимо для определения типа данных этих констант (само значение констант неважно).

Особенности#

В данном разделе приведены особенности работы с расширением pg_outline.

Номера ссылок#

Не допускается указывать номер ссылки больший, чем количество констант в исходном запросе. В остальном на количество и порядок следования ссылок в подменяющем запросе ограничений нет.

Формирование идентификатора#

В зависимости от метода передачи параметров некоторые запросы могут иметь разный идентификатор (queryid). Например, два идентичных (в генерализованном виде) запроса будут иметь разные query_id:

PREPARE foo1(int) AS SELECT f1, f2 FROM table1 where f1 = $1
PREPARE foo2      AS SELECT f1, f2 FROM table1 where f1 = 123

Хранение планов запросов. Расширение pg_store_plans#

Расширение pg_store_plans предназначено для накапливания статистики по планам выполнения всех SQL-запросов, выполняемых в БД.

Для использования расширения необходимо дополнить список shared_preload_libraries файла postgresql.conf названием расширения, поскольку ему требуется доступ в разделяемую общую память. Для добавления или удаления расширения требуется перезапуск сервера.

Внимание!