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

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

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

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

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

Примечание:

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

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

В данном разделе приведены примеры команд для получения используемой версии продукта Platform V Pangolin. Примеры команд не отличаются для ОС Альт 8 СП и Rad Hat.

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

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

Команда:

pg_ctl --product_version

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

Platform V Pangolin 5.2.0

где:

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

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

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

Команда:

pg_ctl --version

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

pg_ctl (PostgreSQL) 13.4

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

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

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

    Команда:

    SELECT product_version();
    

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

        product_version
    ---------------------------
    Platform V Pangolin 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)
    

    Примечание:

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

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

Чтобы получить информацию о сборке продукта Platform V 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 АС Platform V Pangolin), так как вероятность изменения SQL интерфейса меньше.

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

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

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

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

  • cluster — в файле /etc/patroni/postgres.yml.

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

Внимание!

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

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

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

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

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

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

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

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

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

Включение механизма (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. Определите, на каком хосте был последний активный лидер. Это можно проверить по логам patroni:

    host1$ sudo journalctl --since "5 hours ago" -u patroni | grep "i am " | tail -1
    Aug 04 22:38:17 tkles-pprb00096.vm.esrt.cloud.sbrf.ru 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 patroni | grep "i am " | tail -1
    Aug 04 22:38:07 tkles-pprb00094.vm.esrt.cloud.sbrf.ru python3[21032]: 2020-08-04 22:38:07,814 INFO: no action. i am a secondary and i am following a leader
    

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

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

    host1$ sudo systemctl stop patroni
    
  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. Запустите службу Patroni:

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

    host1$ list
    + Cluster: clustername (6857170778029161231) ----------------------------------------+--------------+---------+----+-----------+
    |                 Member                |                    Host                    |     Role     |  State  | TL | Lag in MB |
    +---------------------------------------+--------------------------------------------+--------------+---------+----+-----------+
    | tkles-pprb00094.vm.esrt.cloud.sbrf.ru | tkles-pprb00094.vm.esrt.cloud.sbrf.ru:5433 | Sync Standby | running |  4 |         0 |
    | tkles-pprb00096.vm.esrt.cloud.sbrf.ru | tkles-pprb00096.vm.esrt.cloud.sbrf.ru: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 поддерживает несколько типов авторизации и аутентификации пользователей и сервисов (см. документ «Руководство по безопасности» разделы «Идентификация и аутентификация» и «Авторизация»).

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

[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] конфигурационного файла pgBouncer.

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

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

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

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

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

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

Пример конфигурации (содержит параметры, связанные с использованием секции [users] файла /etc/pgbouncer/pgbouncer.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, а аутентификация в базе данных будет выполняться только после аутентификации его в pgBouncer.

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

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

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

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

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

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

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

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

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

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

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

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

Примечание:

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

  • выставляемого значения должно хватить, чтобы запустить пул соединений между pgBouncer и 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 или pgBouncer. В каком логе и в какое время - зависит от значений параметров place и connect_time\auth_time.

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

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

Подробное описание команд в «Документация на публичные API: PL/pgSQL», раздел «Описание API функциональности сквозной аутентификации».

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

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

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

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

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

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

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

rm -f ~/.psql_history

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

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

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

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

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

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

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

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

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

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

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

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

      • authentication_proxy = on;

      • authentication_port = {AUTHPORT};

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

    • auth_port={AUTHPORT};

    • auth_proxy = on;

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

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

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

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

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

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

    • auth_proxy = off;

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

  • Аутентификация LDAP не поддерживается pgBouncer, поэтому 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
    

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

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

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

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

Ниже приведен пример конфигурации, когда защищенное соединение выполняется между клиентом и pgBouncer-ом, а между pgBouncer и 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

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

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

В файле pgbouncer.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

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

Для включения 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 = tkles-core00133.vm.esrt.cloud.sbrf.ru ## hostname with domain
      IP.1 = 10.53.115.151 ## host ip address
      
    3. Экспортируйте файл конфигурации:

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

      openssl req -new -key server.key -out server.csr -subj "/CN=tkles-core00133.vm.esrt.cloud.sbrf.ru" -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

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

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/sber_ca/server.crt'
    ssl_key_file = '/home/postgres/sber_ca/server.key'
    ssl_ca_file = '/home/postgres/sber_ca/rootCA.crt'
    ssl_crl_file = 'путь до файла со списком отозванных сертифкатов'
    
  2. В pgbouncer.ini добавьте секцию TLS-настроек. Между pgbouncer и postgresql настраивается обязательное SSL-соединение, между pgbouncer и клиентом — по требованию клиента. В обоих случаях минимальная версия 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/sber_ca/rootCA.crt
    server_tls_cert_file = /home/postgres/sber_ca/pgbouncer.crt
    server_tls_key_file = /home/postgres/sber_ca/pgbouncer.key
    client_tls_protocols = secure
    client_tls_ciphers = secure
    client_tls_sslmode = prefer
    client_tls_ca_file = /home/postgres/sber_ca/rootCA.crt
    client_tls_cert_file = /home/postgres/sber_ca/server.crt
    client_tls_key_file = /home/postgres/sber_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="https://tkles-core00133.vm.esrt.cloud.sbrf.ru:2379"
    ETCD_LISTEN_PEER_URLS="https://0.0.0.0:2380"
    ETCD_INITIAL_ADVERTISE_PEER_URLS="https://tkles-core00133.vm.esrt.cloud.sbrf.ru:2380"
    ETCD_INITIAL_CLUSTER_TOKEN="test"
    ETCD_INITIAL_CLUSTER="tkles-core00133=https://tkles-core00133.vm.esrt.cloud.sbrf.ru:2380,tkles-core00075=https://tkles-core00075.vm.esrt.cloud.sbrf.ru:2380,tkles-core00077=https://tkles-core00077.vm.esrt.cloud.sbrf.ru:2380"
    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/sber_ca/rootCA.crt"
    ETCD_CERT_FILE="/home/postgres/sber_ca/server.crt"
    ETCD_KEY_FILE="/home/postgres/sber_ca/server.key"
    ETCD_PEER_TRUSTED_CA_FILE="/home/postgres/sber_ca/rootCA.crt"
    ETCD_PEER_CERT_FILE="/home/postgres/sber_ca/server.crt"
    ETCD_PEER_KEY_FILE="/home/postgres/sber_ca/server.key"
    ETCD_PEER_CLIENT_CERT_AUTH="true"
    ETCD_PEER_CRL_FILE="путь до файла со списком отозванных сертифкатов"
    
  4. В файле конфигурации patroni 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: tkles-core00133.vm.esrt.cloud.sbrf.ru:8008
          allowlist: []
          allowlist_include_members: true
          verify_client: optional
          cafile: /home/postgres/sber_ca/rootCA.crt
          certfile: /home/postgres/sber_ca/server.crt
          keyfile: /home/postgres/sber_ca/server.key
          authentication:
              username: patroniyml
              password: $enc$gDr8F+Suzo3TToVigCBX2se9MJW3Ie0kqyJ+PClL5UA=
      
    2. В секции etcd добавьте параметры protocol, cacert, cert, key. Соединение с etcd будет осуществляться по протоколу HTTPS.

      etcd:
          hosts: tkles-core00077.vm.esrt.cloud.sbrf.ru:2379,tkles-core00133.vm.esrt.cloud.sbrf.ru:2379,tkles-core00075.vm.esrt.cloud.sbrf.ru:2379
          protocol: https
          cacert: /home/postgres/sber_ca/rootCA.crt
          cert: /home/postgres/sber_ca/patronietcd.crt
          key: /home/postgres/sber_ca/patronietcd.key
          username: patronietcd
          password: $enc$cVrbd96FvJJGAY5dUq6M2Mta1SciGLDvMZ4kJzh831Y=
      
  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: tkles-core00133.vm.esrt.cloud.sbrf.ru:5433
        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/sber_ca/patroni.key
                sslcert: /home/postgres/sber_ca/patroni.crt
                sslrootcert: /home/postgres/sber_ca/rootCA.crt
                sslcrl: "путь к файлу со списком отозванных сертификатов"
            superuser:
                username: patroni
                sslmode: verify-ca
                sslkey: /home/postgres/sber_ca/patroni.key
                sslcert: /home/postgres/sber_ca/patroni.crt
                sslrootcert: /home/postgres/sber_ca/rootCA.crt
                sslcrl: "путь к файлу со списком отозванных сертификатов"
    
            ssl: 'on'
            ssl_cert_file: /home/postgres/sber_ca/server.crt
            ssl_key_file: /home/postgres/sber_ca/server.key
            ssl_ca_file: /home/postgres/sber_ca/rootCA.crt
            ssl_crl_file: "путь к файлу со списком отозванных сертификатов"
    
  6. В секции pg_hba смените метод подключения для УЗ patroni с host на hostssl:

    hostssl all patroni 10.53.115.151/32 scram-sha-256
    hostssl all patroni 10.53.115.149/32 scram-sha-256
    hostssl replication patroni 10.53.115.151/32 scram-sha-256
    hostssl replication patroni 10.53.115.149/32 scram-sha-256
    
  7. haproxy.cfg - в haproxy активируется режим passthrough, добавляются проверки health-check по SSL (для patroni на порту 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 tkles-core00133.vm.esrt.cloud.sbrf.ru tkles-core00133.vm.esrt.cloud.sbrf.ru:6544 verify none maxconn 100 check check-ssl port 8008
        server tkles-core00075.vm.esrt.cloud.sbrf.ru tkles-core00075.vm.esrt.cloud.sbrf.ru:6544 verify none maxconn 100 check check-ssl port 8008
    
    listen stats
        mode http
        bind *:7000 ssl crt /home/postgres/sber_ca/haproxy.crt
        stats enable
        stats uri /
        stats auth login:password
        acl whitelist src 10.53.115.151
        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:

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

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

server.crt / server.key

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

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

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

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

pgbouncer.crt / pgbouncer.key

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

patroni.crt / patroni.key

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

patronietcd.crt / patronietcd.key

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

client.crt / client.key

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

root.crt

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

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

Примечание:

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

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

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

  • Корневой сертификат root.crt, которым подписаны сертификаты компонентов PostgreSQL, PgBouncer и Patroni.

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

  • в конфигурационном файле patroni 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;

  • в конфигурационном файле PgBouncer pgbouncer.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, если в конфигурационных файлах не прописаны прежние параметры для установки цепочки доверенных сертификатов:

  • в конфигурационном файле patroni 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);

  • в конфигурационном файле PgBouncer pgbouncer.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_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

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.db.dev.sbt

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 настраивается путем установки следующих параметров в конфигурационных файлах компонентов кластера:

  • в конфигурационном файле patroni 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;

  • в конфигурационном файле pgBouncer pgbouncer.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, предоставляется возможность использования существующих параметров для установки путей к файлам с полными цепочками доверенных сертификатов или введенных в текущей работе новых параметров для установки директории с доверенными сертификатами:

  • в конфигурационном файле Patroni 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';

  • в конфигурационном файле PgBouncer pgbouncer.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 с клиентской ключевой парой pgbouncer и цепочкой доверенных сертификатов для подключения к СУБД 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 с клиентской ключевой парой и цепочкой доверенных сертификатов для подключения Patroni к СУБД 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, pgbouncer, Patroni. Тогда потребуется указать путь до корневого сертификата в параметре 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-формате без перезапуска кластера. Достаточно выполнить перечитывание конфигурационных файлов.

Управление сертификатами для Platform V Pangolin с SecMan#

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

В Pangolin появляется несколько новых конфигурационных файлов. Эти файлы используются следующими компонентами кластера: СУБД Pangolin, pgBouncer и Patroni. Каждый компонент использует свой конфигурационный файл. Данные, указанные в файлах, используются для генерации контейнеров 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": ""
      }
    }
    
  • pgBouncer:

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

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

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

  • В случае кластера. В файле конфигурации patroni 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.

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

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

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

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

Генерация и установка постоянного пароля технологической УЗ#

Расширение 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;
    

    Рекомендуется установка для всех БД, для которых необходимо расширение.

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

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

К настройке предлагается два параметра postgres.conf:

  • rotate_password.num_rounds = '20' - количество попыток генерации пароля;

  • rotate_password.valid_roles = '' - список пользователей, которые могут быть указаны в параметре этой функции.

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

Входные параметры функции rotate_password:

  • (обязательный) Oid или имя пользователя;

  • (не обязательный) длина пароля (или пароль будет сгенерирован по минимальной длине пароля согласно парольным политикам +0-5 символов).

Выходной параметр: сгенерированный пароль.

Возможные ошибки:

  • исчерпано количество попыток генерации пароля;

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

  • пользователь не входит в rotate_password.valid_roles;

  • ошибка синтаксического анализа rotate_password.valid_roles;

  • не найден пользователь.

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

Отключение функциональности производится путем удаления расширения:

DROP EXTENSION psql_rotate_password;

Настройка подключения к SecMan для Platform V Pangolin#

Описываемая функциональность:

  • обеспечивает настройку параметров подключения к Хранилищу секретов SecMan;

  • упрощает процесс изменения параметров для работы с Хранилищем секретов;

  • обеспечивает возможность обнаружения ошибок в параметрах подключения к Хранилищу секретов на этапе конфигурирования доступа;

  • обеспечивает настройку системы для работы с Хранилищем сертификатов;

  • упрощает использование утилиты в автоматизированных скриптах.

  • обеспечивает настройку проверки серверного сертификата Хранилища секретов.

Дополнительные параметры для работы с Хранилищем секретов SecMan#

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

  • Доменное имя - добавляется возможность указания сервера хранилища через доменное имя, а не только через IP-адрес.

  • Префикс для пути хранения секретов - добавляется возможность указания префикса для пути хранения kv секретов, согласно иерархии секретов. Префикс должен содержать движок секретов. Путь, используемый для доступа к секретам: /v1/{prefix/}data/{domain/}{cluster id/}{subdomain/}secret_name. Пример заданного префикса: CI03170154_CI03214758/I/SERV/GLOB/SERV/KV.

  • Точка входа для urn аутентификации: /auth/точка_входа/login/. Указание точки входа позволяет авторизоваться по LDAP для типа авторизации Userpass (пример, auth/ad/sigma.sbrf.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
--cluster      [-c]     имя кластера
--host         [-h]     доменное имя или ip адрес хранилища
--port         [-p]     номер порта хранилища
--protocol     [-l]     протокол обмена данными: http (1) или https (2), протокол по умолчанию: https
--prefix       [-x]     путь до хранения секретов на сервере (префикс для пути хранения секретов, по умолчанию: kv)
--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.

Интерактивный режим добавления параметров#

/usr/pangolin-5.2.1/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

Режим просмотра добавленных параметров подключения#

/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 |
+---------------------------------------------------------------------------------------------------------------------------------------+

Режим редактирования добавленных параметров подключения#

В режиме просмотра необходимо определить номер записи, которую следует отредактировать. Например, нужно отредактировать первую запись - изменить тенант хранилища. Передаем аргументом индекс записи: 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 (резервная копия системы).

Подход к резервному копированию#

Data Protector выполняет резервное копирование экземпляров Pangolin и связанных файлов WAL, обеспечивая таким образом полное копирование данных. Такой тип резервного копирования позволяет использовать БД во время сеанса снятия резервной копии, в том числе вносить изменения в таблицы.

Поддерживаются следующие типы резервного копирования:

  • полная резервная копия, включающая все базы данных в экземпляре Pangolin;

  • резервное копирование транзакций в виде файлов WAL, сохраненных со времени предыдущего полного резервного копирования или резервного копирования транзакций.

Необходимая конфигурация параметров Pangolin для начала процесса резервного копирования:

wal_level = replica (или выше)
hot_standby = on
full_pages_writes = on
archive_mode = always
archive_command = 'pg_probackup-11 archive-push -B <локальный каталог копий> --instance <экземпляр> --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4'
archive_timeout = 180

Процедуру снятия резервной копии можно автоматизировать с помощью Python-скрипта, расположенного в директории /opt/omni/lbin/. Этот скрипт автоматизирует вызовы pg_start_backup() и pg_stop_backup() и управляет процессом снятия полной резервной копии. При запуске скрипта будет создан отдельный процесс с подключением libpq.

Примечание:

Одновременно можно выполнять только одно резервное копирование. Если существует старый сеанс резервного копирования, новое резервное копирование не будет запущено.

Ошибки, возникающие в процессе копирования, заносятся в журнал Pangolin, в приложение backup_session и в файл backup_manager.log в каталоге резервного копирования.

Подход к восстановлению данных#

Pangolin поддерживает различные способы восстановления данных. Перед восстановлением данных необходимо определить следующие аспекты процесса восстановления:

  • Область действия:

    • Восстановление всего экземпляра - в таком случае восстановление производится отдельно на каждый сервер, после чего выполняется синхронизация с помощью Patroni.

    • Восстановление ведомого сервера - в таком случае восстановление происходит из резервной копии на последний возможный момент времени.

  • Расположение восстанавливаемых данных:

    • Исходное расположение.

    • Другой путь на исходном клиенте.

    • Другой клиент (на него тоже потребуется установить Pangolin).

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

    • На время последней резервной копии транзакции (откат до последнего возможного состояния);.

    • На определенный момент времени по выбору (восстановление на момент времени с повтором).

    • На момент выбранного успешного полного или резервного копирования транзакции.

Необходимая точка восстановления задается через файл конфигурации Patroni, раздел recovery_conf:

  • recovery_target_time = <timestamp>;

  • recovery_target_inclusive = true (восстанавливать данные до указанной временной отметки включительно (true) или не доходя до нее (false));

  • restore_command = <путь к архиву WAL файлов>.

Пока идет процедура восстановления из резервной копии, СУБД должна быть остановлена.

Подход к мониторингу резервных копий#

Часть описанной функциональности реализована через расширение pgse_backup. Это расширение создает схему backup и все остальные объекты.

Для безопасного считывания файлов с историей (backup_state, wal_backup_state) используется функция Pangolin SECURITY DEFINER. Эта функция разрешает доступ к файлам с историей без прав суперпользователя, но в пределах строго фиксированного каталога, чтобы исключить доступ к чтению посторонних файлов.

Пример функции для backup.read_data_history:

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 := pg_read_file(filename);
    if json_data = '' 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;

Директория, в которой хранятся файлы истории и к которой предоставляется доступ через SECURITY DEFINER, задается через таблицу backup.settings. Эта таблица должна быть доступна только владельцу расширения (Администратору БД)

 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)));

Для контроля состояния резервных копий используются три представления: backup.data_history, backup.wal_history и backup.history. Представление backup.history сверяет data_history и wal_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

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 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;


        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;


        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;

Функция очистки истории (должна быть доступна только Администраторам БД):

        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;

Развертывание на КТС#

Ниже перечислены операции, которые должны быть выполнены при развертывании на КТС, на которых будут располагаться БД. Данные действия выполняются в автоматическом режиме при развертывании инсталлятором.

  1. Создайте директорию PGBACKUP: /pgbackup/11.

  2. Установите pg_probackup.

  3. Создайте локальный каталог резервных копий: pg_probackup-11 init -B $PGBACKUP. В случае, если каталог не пустой, операция завершится с ошибкой, поэтому перед установкой каталог должен быть очищен.

  4. Определите копируемый экземпляр резервных копий: pg_probackup-11 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-11 archive-push -B <локальный каталог копий> --instance <инстанс> --wal-file-path=%p --wal-file-name=%f --compress --overwrite -j 4'
    archive_timeout = 180
    
  6. Добавьте параметры работы pg_probackup: pg_probackup-11 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. Остановите сервис patroni сначала на Standby, потом на Active:

    sudo systemctl stop patroni
    
  2. Очистите каталоги data и tablespaces на Standby и Active:

    rm -rf /pgdata/04/data
    rm -rf /pgdata/04/tablespaces
    
  3. Очистите хранилище etcd (clustername замените на действительное имя кластера):

    etcdctl rm -r /service/clustername
    
  4. Исправьте конфигурационный файл patroni (clustername и new_clustername замените на действительные Active и Standby, добавьте секцию recovery_conf на Active):

    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. Запустите сервис patroni на Active и убедитесь, что БД запущена и загружаются файлы журналов:

    sudo systemctl start patroni
    less /pgerrorlogs/clustername/postgresql.log
    
  8. Запустите сервис patroni на Standby, дождитесь синхронизации и убедитесь, что кластер перешел в синхронный режим:

    sudo systemctl start patroni
    patronictl -c /etc/patroni/postgresql.yml list
    

Восстановление типа инсталляции standalone-patroni-etcd-pgbouncer#

  1. Остановите сервис patroni:

    sudo systemctl stop patroni
    
  2. Очистите каталоги data и tablespaces:

    rm -rf /pgdata/05/data
    rm -rf /pgdata/05/tablespaces
    
  3. Очистите хранилище etcd (clustername замените на действительное имя кластера):

    etcdctl rm -r /service/clustername
    
  4. Исправьте конфигурационный файл patroni (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. Запустите сервис patroni и убедитесь, что БД запустилась и загружаются файлы журналов (в логах отсутствуют ошибки проигрывания WAL-файлов):

    sudo systemctl start patroni
    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
    

Восстановление Standby-сервера из резервной копии#

  1. Остановите сервис patroni на Standby:

    sudo systemctl stop patroni
    
  2. Очистите каталоги data и tablespaces на Standby:

    rm -rf /pgdata/04/data
    rm -rf /pgdata/04/tablespaces
    
  3. Исправьте конфигурационный файл patroni (добавьте секцию 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. Запустите сервис patroni и убедитесь, что БД запустилась и загружаются файлы журналов, дождитесь синхронизации и убедитесь, что кластер перешел в синхронный режим:

    sudo systemctl start patroni
    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 )}}

Снятие резервной копии со standby-базы#

Функция резервного копирования позволяет снять с базы данных архивную копию, которую в дальнейшем можно использовать для восстановления. PostgreSQL поддерживает создание резервной копии как с Active, так и с Standby.

Резервное копирование выполняется следующей командой:

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#

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

Защита от привилегированных пользователей#

В Platform V Pangolin используется механизм защиты данных от привилегированных пользователей, построенный на принципе разделения ролей.

В стандартном PostgreSQL привилегированные пользователи имеют доступ к объектам БД и настройкам подключения:

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

  • администраторы ОС могут менять настройки БД таким образом, чтобы получать доступ к пользовательским данным, что тоже ведет к утечкам.

В Platform V Pangolin Администраторы БД и ОС теряют возможность самостоятельно управлять некоторыми параметрами и перестают иметь полный доступ ко всем объектам БД.

В дополнение к роли суперпользователя, которая есть в стандартной версии PostgreSQL, в Pangolin можно создать специальную роль Администратора безопасности (АБ).

АБ – независимый администратор, не обладающий особыми правами в операционной системе (в том числе не имеющий прав Linux-пользователя postgres) и не имеющий доступа к объектам БД. Внутри БД роль Администратора безопасности является особенной — она не может быть изменена суперпользователем. Таким образом, ни один из пользователей не может единолично получить доступ к конфиденциальным данным или изменить важные для безопасности настройки БД и права доступа.

Администратор безопасности создается при инициализации кластера, либо существующим администратором безопасности через функцию pm_grant_security_admin.

Примечание:

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

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

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

Внимание!

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

Ниже описаны основные функции, подробнее о функциях в «Список 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.

Внимание!

Маскирование параметров функций, принимающих на вход конфиденциальную информацию, таких как pm_create_security_admin, pm_set_security_admin_password и add_auth_record_to_storage, будет выполняться только при значении full параметра masking_mode.

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

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

  • disabled - механизм отключен, маскирование запросов не производится;

  • full - механизм маскирования работает по всем обрабатываемым запросам SELECT/INSERT/UPDATE/DELETE и их параметрам, а также запросам CREATE/ALTER ROLE/USER и параметру пароля в их составе.

По умолчанию механизм выключен (disabled), параметр хранится в postgresql.conf, а при защищенном конфигурировании (настроенное соединение с KMS + значение параметра secure_config = on) берется из хранилища секретов (KMS), из параметра кластера с именем masking_mode.

Для изменения значения параметра masking_mode выполните перезапуск СУБД Pangolin.

Автоматическое завершение неактивных соединений#

Соединения, остающиеся неактивными определенное время, подлежат принудительному завершению. Для завершения таких соединений используется фоновый процесс, осуществляющий мониторинг и завершение бездействующих клиентских сеансов. Этот процесс запускается при старте сервера Pangolin и завершается вместе с остановкой сервера.

Процесс регулируется двумя параметрами:

  • check_idle_time_delay - интервал мониторинга в миллисекундах;

  • backend_idle_alive_time - допустимое время бездействия в секундах.

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

Прозрачное шифрование#

В Platform V Pangolin используется прозрачное шифрование данных (TDE). С его помощью шифруются данные, хранящиеся в файлах данных, журналах изменений, резервных копиях и временных файлах баз данных, а также данные, передаваемые по каналам связи в ходе физической и логической репликации. Решение HashiCorp Vault используется в качестве защищенного хранилища ключей шифрования и настроек, а также как система управления ключами.

Алгоритм, процессы и концептуальная архитектура Pangolin при реализации прозрачного шифрования описаны в разделе «Прозрачное шифрование (Transparent Data Encryption)», документа «Детальная архитектура».

Настройка прозрачного шифрования хранимых данных (TDE) в Pangolin возможна с использованием хранилища секретов в HashiCorp Vault или с использованием хранилища KMS-заменителя. Инструкции по настройке находятся в разделе «Настройки параметров безопасности» документа «Руководство по безопасности».

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

Ротация (смена) мастер-ключа кластера высокой доступности также может инициироваться и выполняться посредством выполнения функции смены мастер-ключа на узле Active БД, входящем в кластер.

Функции для поддержки ротации и изменения мастер-ключей на стороне БД:

  • 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 — ситуация, при которой данные таблиц будут храниться неэффективно. Они фрагментируются, что приводит к ухудшению производительности и нерациональному использованию места на диске.

Механизм работы с данными в 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#

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

Пример использования:

Реорганизовать таблицу «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 — запустить несколько параллельных процессов для ускорения обработки.

Инструмент pgcompacttable#

Скрипт реорганизации данных в «раздутых» таблицах (bloated tables), восстановления индексов и возврата дискового пространства.

Запуск скрипта#

Для запуска скрипта требуются права 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 — пароль для указанного пользователя.

    • asdfwads

Примечание:

Инструмент pgcompacttable использует Perl модуль DBI для соединения с базой данных.

Если настройки соединения не передаются в ключах, то инструмент использует переменные окружения PGHOST, PGPORT, имя текущего пользователя и PGPASSWORD.

Если пароль не задан, инструмент попробует применить пароль (в порядке обращения):

  1. Из файла, указанного в переменной окружения PGPASSFILE.

  2. Из файла HOME/.pgpass.

Ключи работы с БД:

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

Все ключи, кроме --all, можно использовать несколько раз.

  • -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 – имя исключаемой из обработки схемы.

Ключи настройки поведения инструмента:

  • -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.

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

Реорганизовать таблицу bloated_table:

pgcompacttable  --dbname -t bloated_table

Аналитика производительности 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.

Подробное описание функций в «Документация на публичные API: PL/pgSQL», раздел «Аналитика производительности 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     pgbouncer 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 для подключения к виртуальной БД pgbouncer для сбора статистики использования pgbouncer.

    Значение по умолчанию отсутствует.

  • --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 (конфигурационный файл patroni, проверить в том числе секцию 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_profile, установленное на один кластер, может собирать также статистику с других кластеров, именуемых servers (далее — серверы).

Для этого:

  • создайте необходимые серверы (функция create_server()), указав имя и строку подключения (подробнее о функции см. «Документация на публичные API», раздел «Отчетность по нагрузке 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() в «Документация на публичные API», раздел «Отчет по нагрузке Pangolin».

Тайминги сбора выборок#

Расширение pg_profile будет собирать подробную статистику по времени сбора выборок, когда включен параметр pg_profile.track_sample_timings.

Baselines#

Baseline — это именованная последовательность выборок с собственными настройками хранения.

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

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

Отчеты#

Отчеты создаются в формате HTML функциями по работе с отчетами. В pg_profile есть два типа доступных отчетов:

  • регулярные отчеты — содержат статистическую информацию о загруженности экземпляра за период отчета;

  • отчеты по изменениям — содержат данные из двух интервалов со значениями статистики с одинаковых объектов, расположенных один за другим, что упрощает сравнение рабочей нагрузки.

Посмотреть отчет можно в любом веб-браузере.

Функции регулярных отчетов и отчетов по изменениям описаны в «Документация на публичные API», раздел «Отчет по нагрузке 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])

Описание и примеры разделов отчета по нагрузке представлены в отдельном документе.

Примеры формирования отчетов#
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#

Для Platform V 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;

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

Чтобы отключить функциональность расширения, установите значение 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');
    

Особенности#

В данном разделе приведены особенности работы с расширением 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 (см. «Документация на публичные API», раздел «Функциональные возможности расширения 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

Шифрование и хранение параметров подключения#

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

  • pg_auth_config — утилита шифрования/хранения параметров подключения к БД. Располагается в каталоге $PGHOME/bin (пример: /usr/pgsql-se-04/bin/), доступна только владельцу (postgres);

  • pg_auth_password — утилита шифрования паролей. Позволяет получить пароль в зашифрованном виде после ввода исходного пароля. Располагается в каталоге $PGHOME/bin (пример: /usr/pgsql-se-04/bin/), доступна только владельцу (postgres).

Внимание!

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

Как следствие, пароли в зашифрованном виде и файл хранилища:

  • применимы только в рамках сервера, где выполнялось шифрование;

  • уникальные/свои для каждого узла кластера.

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

Схема процесса и формат шифрования представлены в документе «Детальная архитектура», раздел «Поведение», подраздел «Шифрование и хранение параметров подключения».

Утилита шифрования и хранения параметров подключения к БД (pg_auth_config)#

Утилиты, выполняющие автоматизированное подключение к БД, должны выполнить получение параметров подключения из защищенного хранилища для дальнейшего подключения к БД.

Утилита pg_auth_config формирует зашифрованное хранилище, которое хранится в файле /etc/postgres/enc_utils_auth_settings.cfg. Ключи, используемые при шифровании, уникальны в рамках хоста. Они не хранятся, а вычисляются в процессе.

Примечание:

В качестве ключа шифрования используется фраза, конструируемая из параметров:

  • парольная фраза - CPU manufacturer ID CPU, CPU stepping, CPU model, CPU family, CPU feature flags, список MAC адресов постоянных сетевых интерфейсов, список IP постоянных сетевых интерфейсов

  • соль - тип credentials, machineId из /etc/machine-id, UUID корневой файловой системы, домен для использования credentials (сейчас 'POSTGRESQL' - для шифрования конфигов компонент HA кластера или 'KMS' - для шифрования параметров доступа к KMS)

Алгоритм определяется сконфигурированным плагином шифрования (по умолчанию AES-256). Хранилище может быть расшифровано только на хосте где было создано. Оно автоматически формируется на этапе установки дистрибутива Pangolin.

Запуск утилиты pg_auth_config отображает параметры использования:

Usage:
    ./pg_auth_config show | add | remove | check | reset [options...]
Options:
    --help              This help
    --host     [-h]     host for which password will be used
    --port     [-p]     port for which password will be used
    --user     [-U]     user name for which password will be used
    --database [-d]     database for which password will be used
The './pg_auth_config' utility is used to securely save password information
for internal PostgreSQL SE utilities
the concept is simular to .pgpass, except this utility encrypts pasword information

Параметры host и port необходимы для того, чтобы пароль нельзя было использовать для подключения к произвольным БД, в том числе к модифицированным версиям postgres, показывающим, с каким паролем пыталось произойти подключение. Запись в хранилище можно перезаписать только целиком. Например, нельзя поменять отдельно только host.

  • add — команда добавляет в хранилище пароль пользователя name. По умолчанию утилита дважды просит ввести пароль. Передача пароля через командную строку отсутствует.

    Внимание!

    В момент добавления пароля в хранилище его корректность не проверяется (т.е. не проводится сверка с паролем, хранящимся в БД).

    Пример использования:

    ./pg_auth_config add -h 127.0.0.1 -p 5432 -d postgres -U test
    enter password:
    ****
    confirm password:
    ****
    

    Опция --skip-confirm позволяет не запрашивать второго ввода пароля. Данную опцию рекомендуется использовать в автоматизированных системах, когда ввод пароля автоматизирован.

    ./pg_auth_config add -h 127.0.0.1 -p 5432 -d postgres -U test -skip-confirm
    enter password:
    ****
    confirm password:
    ****
    
  • show — команда выводит в консоль содержимое хранилища (за исключением паролей).

    Пример использования:

    $ pg_auth_config show
    |               host |      port |   database |   username |
    |----------------------------------------------------------|
            localhost |      5433 |   postgres |    patroni |
    |          localhost |      5433 |replication |    patroni |
    | srv-1-1.db.dev.sbt |      5433 |   postgres |    patroni |
    | srv-1-2.db.dev.sbt |      5433 |replication |    patroni |
    | srv-1-1.db.dev.sbt |      5433 |   database |       user |
    | srv-1-1.db.dev.sbt |      5433 |   database |      user1 |
    

    Команда show позволяет выборочно выводить в консоль данные, используя конкретные параметры подключения: host, port, database или user.

    Пример использования:

    -- Пример просмотра данных с параметрами host и port
    
    $ pg_auth_config show -h 127.0.0.1 -p 5433
    |      host |      port |  database |   username |
    |------------------------------------------------|
    | 127.0.0.1 |      5433 |  postgres |backup_user |
    
    -- Пример просмотра данных с параметрами database
    
    $ $ pg_auth_config show -d replication
    |              host |      port |   database |  username |
    |--------------------------------------------------------|
    |         localhost |      5433 |replication |   patroni |
    |srv-1-1.db.dev.sbt |      5433 |replication |   patroni |
    |srv-1-2.db.dev.sbt |      5433 |replication |   patroni |
    
  • check — команда проверяет актуальность данных в хранилище с данными БД. При подключении к БД используются параметры подключения из хранилища.

    Пример использования:

    $ pg_auth_config check
    Connection settings for host: "localhost", port "5433", database "postgres", user "patroni" are OK
    Connection settings for host: "localhost", port "5433", database "replication", user "patroni" are OK
    Connection settings for host: "srv-1-1.db.dev.sbt", port "5433", database "postgres", user "patroni" are OK
    Connection settings for host: "srv-1-1.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
    Could not connect with host: "srv-1-1.db.dev.sbt", port "5433", database "postgres", user "test"...
    
    -- Сообщение "Connection settings for host..." говорит о пройденной успешной проверке
    -- Сообщение "Could not connect with host:..." говорит о неуспешной проверке
    

    Если не удалось установить соединение с сервером по причине «исчерпан лимит подключений», формируется соответствующее сообщение с подсказкой: too many clients, try again.

    Команда check позволяет выборочно проверять актуальность данных, используя конкретные параметры подключения: host, port, database или user.

    Пример использования:

    -- Пример проверки данных с параметрами host и port:
    
    $ pg_auth_config check -h 127.0.0.1 -p 5433
    Connection settings for host: "127.0.0.1", port "5433", database "postgres", user "backup_user" are OK
    
    -- Пример проверки данных с параметрами database:
    $ pg_auth_config check -d replication
    Connection settings for host: "localhost", port "5433", database "replication", user "patroni" are OK
    Connection settings for host: "srv-1-1.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
    Connection settings for host: "srv-1-2.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
    
    -- Пример проверки данных с параметрами user:
    $ pg_auth_config check -U patroni
    Connection settings for host: "localhost", port "5433", database "postgres", user "patroni" are OK
    Connection settings for host: "localhost", port "5433", database "replication", user "patroni" are OK
    Connection settings for host: "srv-1-1.db.dev.sbt", port "5433", database "postgres", user "patroni" are OK
    Connection settings for host: "srv-1-1.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
    Connection settings for host: "srv-1-2.db.dev.sbt", port "5433", database "postgres", user "patroni" are OK
    Connection settings for host: "srv-1-2.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
    
    -- Пример проверки данных с параметрами host, port, database, user:
    $ pg_auth_config check -h 127.0.0.1 -p 5433 -d replication -U patroni
    Connection settings for host: "127.0.0.1", port "5433", database "replication", user "patroni" are OK
    

    Примечание:

    Во всех режимах работы утилиты проверяется введенное значения порта. Значение порта должно находиться в диапазоне от 1 до 65535 (включительно).

  • remove — команда удаляет запись, связанную с host, port, database, user. Команда выводит запрос на подтверждение операции удаления.

    Пример использования:

    $ pg_auth_config remove -h srv-1-1.db.dev.sbt -p 5433 -U user -d database
    Do you want to remove auth record? (yes/no)?:
    yes
    Going to remove auth record for user: "user", host: "srv-1-1.db.dev.sbt", port: "5433", database: "database"
    record removed
    
  • reset — команда очищает хранилище. Команда выводит запрос на подтверждение очистки хранилища. После выполнения команды файл /etc/postgres/enc_utils_auth_settings.cfg переименовывается в /etc/postgres/enc_utils_auth_settings.cfg.reset. Утилита не имеет команды для восстановления файла. Для восстановления необходимо самостоятельно переименовать файл /etc/postgres/enc_utils_auth_settings.cfg.reset в /etc/postgres/enc_utils_auth_settings.cfg.

    Пример использования:

    -- Очистка хранилища
    
    $ pg_auth_config reset
    Do you want to reset auth config? (yes/no)?:
    yes
    Auth config was reset
    
    -- Просмотр содержимого хранилища после очистки
    $ pg_auth_config show
    |      host |      port |  database |  username |
    |-----------------------------------------------|
    
    -- Восстановление файла хранилища
    $ mv /etc/postgres/enc_utils_auth_settings.cfg.reset /etc/postgres/enc_utils_auth_settings.cfg
    
    -- Просмотр содержимого хранилища после восстановления
    $ pg_auth_config show
    |              host |      port |   database |   username |
    |---------------------------------------------------------|
    |         localhost |      5433 |   postgres |    patroni |
    |         localhost |      5433 |replication |    patroni |
    |srv-1-1.db.dev.sbt |      5433 |   postgres |    patroni |
    |srv-1-1.db.dev.sbt |      5433 |replication |    patroni |
    |srv-1-2.db.dev.sbt |      5433 |   postgres |    patroni |
    |srv-1-2.db.dev.sbt |      5433 |replication |    patroni |
    ...
    
  • edit — позволяет редактировать существующие записи в хранилище, без необходимости пересоздавать их. Поиск записей для редактирования осуществляется с использованием ключа, состоящего из имени хоста, номера порта, имени пользователя, названия базы данных.

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

    --host [-h] — имя хоста
    --port [-p] — номер порта
    --user [-U] — имя пользователя
    --database [-d] — название базы данных
    

    Пример запуска утилиты в режиме редактирования (поиск по ключу: имя пользователя patroni, название базы данных postgres):

    pg_auth_config edit -U patroni -d postgres
    

    При этом, если:

    • не задано ни одного поля, то работа утилиты завершится, и будет выведено предупреждение:

      At least one field must be defined: host, port, username, database
      
    • записи, соответствующие ключу поиска, не найдены, то работа утилиты завершится, и будет выведено предупреждение:

      Nothing to update: records not found
      
    • записи, соответствующие ключу поиска, найдены, то утилита перейдет в интерактивный режим ввода новых значений (см. ниже раздел «Ввод новых значений для редактируемых полей»).

Функция добавления пароля в зашифрованное хранилище#

Возможны ситуации когда администратору АС требуется завести задание в pg_cron. Для выполнения задания, pg_cron должен подключаться к БД, используя параметры подключения из зашифрованного хранилища. То есть зашифрованное хранилище должно содержать запись для выполнения задания pg_cron. Администратор АС не может использовать утилиту pg_auth_config для самостоятельного добавления записи в зашифрованное хранилище и не может раскрыть пароль администратору БД, чтобы последний добавил запись. Для решения данной ситуации в Pangolin добавлена функция - add_auth_record_to_storage.

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

Ввод новых значений для редактируемых полей#

Ввод новых значений для редактируемых записей осуществляется в интерактивном режиме с помощью команды edit. Для всех полей будет предложено ввести новые значения. Например, предложение на ввод новых значений для поля port (номер порта):

enter port or leave empty to skip update:

Примечание:

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

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

Пример обновления двух записей. Обновляются поля port (номер порта) и username (имя пользователя»):

Going to update 2 records:

|      host |        port |  database |      username |
|-----------------------------------------------------|
| 127.0.0.1 |9000 -> 9001 |   somedb1 |user1 -> user4 |
| 127.0.0.2 |9000 -> 9001 |   somedb1 |user1 -> user4 |

В случае, если при запуске не указан ключ -s (--skip-confirm), то будет запрошено подтверждение операции редактирования записей:

Do you want to update auth records? (yes/no)?:

Для продолжения требуется ввести:

  • «y» или «yes» — для подтверждения операции редактирования;

  • «n» или «no» — для отмены операции редактирования.

Предупреждения и ошибки#

В случае, если:

  • не ввести ни одного нового значения для запрашиваемых полей, то работа утилиты завершится, и будет выведено предупреждение:

    Nothing to update: no new values provided
    
  • новые значения совпадают со старыми (например, найдена одна запись), то работа утилиты завершится, и будет выведено предупреждение:

    Nothing to update: new values for the records are the same as the old ones
    
  • в процессе обновления полей возникают дублирующие друг друга записи, то такие записи будут удалены.

    Примечание:

    Если записи дублируют друг друга, то сохраняется первая запись в списке.

    Для удаляемых записей будет указан признак «< rm» в конце записи. Пример удаления двух дублирующих записей (обновляется поле «название базы данных», уже существуют записи, совпадающие с обновляемыми):

    Going to update 2 records:
    
    |                host |      port |               database |  username |
    |----------------------------------------------------------------------|
    |           localhost |      5433 |replication -> postgres |   patroni | < rm
    |srv-0-153.db.dev.sbt |      5433 |replication -> postgres |   patroni | < rm
    

Описание процессов использования утилиты pg_auth_config#

Процесс добавления пароля (параметров подключения к БД) в зашифрованное хранилище#

Не имеет значения с какого узла кластера начинать изменение пароля. Файл конфигурации созданный на одном узле, например Active, не может быть расшифрован на Standby и наоборот.

  1. Выполняется проверка сотрудником сопровождения либо автоматически при первичной инсталляции Pangolin: будет настраиваться standalone или cluster. В случае типа конфигурации: standalone - переход к шагу 2; cluster - переход к шагу 3.

  2. Выполняется добавление параметров подключения к БД в зашифрованное хранилище через утилиту pg_auth_config на standalone:

    • вызывается утилита с параметрами подключения к БД: pg_auth_config add --h <host> p <port> --U <user> --d <dbname>;

    • вводится пароль пользователя;

    • в результате параметры подключения добавлены в зашифрованное хранилище.

  3. Выполняется добавление параметров подключения к БД в зашифрованное хранилище через утилиту pg_auth_config на cluster:

    • вызывается утилита с параметрами подключения к БД: pg_auth_config add --h <host> p <port> --U <user> --d <dbname> на первом узле кластера;

    • вводится пароль пользователя;

    • в результате параметры подключения добавлены в зашифрованное хранилище на первом узле кластера;

    • вызывается утилита с параметрами подключения к БД: pg_auth_config add --h <host> p <port> --U <user> --d <dbname> на втором узле кластера;

    • вводится пароль пользователя;

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

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

Процесс добавления пароля (параметров подключения к БД) в зашифрованное хранилище Администратором АС#

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

  1. Выполняется проверка администратором АС: будет настраиваться standalone или cluster. В случае типа конфигурации: standalone — переход к шагу 2; cluster — переход к шагу 3.

  2. Выполняется добавление параметров подключения к БД в зашифрованное хранилище с помощью функции add_auth_record_to_storage на standalone:

    • вызывается функция add_auth_record_to_storage с указанием параметров подключения, например:

      select  add_auth_record_to_storage('127.0.0.1', 5433, 'db_name', 'user', 'password');
      
    • в результате параметры подключения добавлены в зашифрованное хранилище.

  3. Выполняется добавление параметров подключения к БД в зашифрованное хранилище через утилиту pg_auth_config на cluster:

    • вызывается функция add_auth_record_to_storage с указанием параметров подключения на первом узле кластера, например:

      select  add_auth_record_to_storage('127.0.0.1', 5433, 'db_name', 'user', 'password');
      
    • в результате параметры подключения добавлены в зашифрованное хранилище на первом узле кластера;

    • вызывается функция add_auth_record_to_storage с указанием параметров подключения на втором узле кластера, например:

      select  add_auth_record_to_storage('127.0.0.1', 5433, 'db_name', 'user', 'password');
      
    • в результате параметры подключения добавлены в зашифрованное хранилище на втором узле кластера.

  4. Рекомендуется выполнить проверку актуальности данных в зашифрованном хранилище на корректность введенных паролей командой pg_auth_config check.

Утилита шифрования паролей, представленных в открытом виде (pg_auth_password)#

Для исключения хранения паролей в открытом виде и предотвращения компрометации паролей командой развития Platform V Pangolin разработана утилита для шифрования паролей pg_auth_password. Утилита pg_auth_password располагается в каталоге $PGHOME/bin, доступна только владельцу (postgres).

Утилита pg_auth_password выполняет только одно действие - шифрование паролей.

На вход утилита pg_auth_password принимает пароль, результат выполнения выводится в консоль. Зашифрованный пароль используется в конфигурационных файлах.

Формат зашифрованного пароля:

$enc$<encrypted_password_in_base64>

    - $enc$ — признак зашифрованного пароля;
    - <encrypted_password_in_base64> — зашифрованный пароль в формате base64.

Зашифрованный пароль используется:

  • patroni для выполнения запросов по REST API и взаимодействия с etcd (прописывается в конфигурации patroni);

  • postgre для выполнения ldap binding (прописывается в ldap записи pg_hba.conf файла).

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

Запуск утилиты pg_auth_passwordс опцией --help отображает параметры использования:

$ pg_auth_password --help
The 'pg_auth_password' is utility to encrypt the password

Usage:
        pg_auth_password enc [OPTION]

Options:
         -s, --skip-confirm          manual input without confirmation
         -W, --password <password>   password is entered as an argument

Other options:
         -V, --version               output version information, then exit
         -h, --help                  show this help, then exit

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

Report bugs to <postgresql_sbt@sberbank.ru>.

Утилита имеет одну команду - enc и несколько опций (--skip-confirm, --password <password>), которые упрощают действия по шифрованию пароля.

  • enc — команда шифрует пароль, который может быть введен или передан в виде аргумента. По умолчанию утилита дважды просит ввести пароль. Результат выводится в консоль.

    Пример использования:

    $ pg_auth_password enc
    enter password:
    **********************
    enter password:
    **********************
    $enc$srfPu47aKUK2k+9ZCMoFDAMyd6ltSHBxOjcIXN8EpmM=
    

Использование утилиты с опциями:

  • --skip-confirm / -s: подтверждение пароля не требуется. Данную опцию рекомендуется использовать в автоматизированных системах, когда ввод пароля автоматизирован.

    Пример использования:

    $ pg_auth_password enc -s
    enter password:
    ***************
    $enc$BlHR2dOnMoGsDwqoWveLag==
    
    -- либо
    pg_auth_password enc --skip-confirm
    enter password:
    ***************
    $enc$BlHR2dOnMoGsDwqoWveLag==
    
  • --password / -W: пароль передается в виде аргумента. При указании данной опции — запрос пароля из консоли не производится.

    Пример использования:

    $ pg_auth_password enc -W test
    $enc$xmZrbJFMvzu51EYZIWckyg==
    
    -- либо
    $ pg_auth_password enc --password test
    $enc$xmZrbJFMvzu51EYZIWckyg==
    

Описание процессов использования утилиты pg_auth_password#

Процесс добавления зашифрованного пароля в конфигурационной файл#

Примечание:

Параметры хранятся в файле в зависимости от типа конфигурации сервера: если тип конфигурации standalone: в файле $PGDATA/pg_hba.conf, в случае типа конфигурации cluster или standalone+patroni: в файле /etc/patroni/postgres.yml в секции pg_hba.

  1. Выполняется проверка сотрудником сопровождения либо автоматически при первичной инсталляции Pangolin: будет настраиваться standalone или cluster. В случае типа конфигурации: standalone — переход к шагу 2; cluster — переход к шагу 3.

  2. Выполняется формирование зашифрованного пароля через утилиту pg_auth_password на standalone:

    • вызывается утилита pg_auth_password enc;

    • вводится пароль для получения его в зашифрованном виде;

    • полученный зашифрованный пароль в формате base64 копируется и вносится для нужного пользователя в конфигурационный файл путем редактирования;

    • для вступления в силу выполняется перечитывание конфигурации командой reload.

  3. Выполняется формирование зашифрованного пароля через утилиту pg_auth_password на первом узле кластера:

    • вызывается утилита pg_auth_password enc на первом узле кластера;

    • вводится пароль для получения его в зашифрованном виде;

    • полученный зашифрованный пароль в формате base64 копируется и вносится для нужного пользователя в конфигурационный файл путем редактирования;

    • для вступления в силу выполняется перечитывание конфигурации командой reload.

  4. Выполняется формирование зашифрованного пароля через утилиту pg_auth_password на втором узле кластера:

    • вызывается утилита pg_auth_password enc на втором узле кластера;

    • вводится пароль для получения его в зашифрованном виде;

    • полученный зашифрованный пароль в формате base64 копируется и вносится для нужного пользователя в конфигурационный файл путем редактирования;

    • для вступления в силу выполняется перечитывание конфигурации командой reload.

Аутентификация утилит через зашифрованный пароль#

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

Пароль ищется по ключу: <host>#<port>#<db>#<user>.

  1. Выполняется старт подключения утилиты к БД, создается сессия в БД.

  2. Из конфигурации утилиты зачитываются параметры подключения к БД: host, port, db, user.

  3. Выполняется расшифровка файла /etc/postgres/enc_utils_auth_settings.cfg с паролями для подключения.

  4. Выполняется поиск пароля по полученным параметрам подключения по ключу host#port#db#user#.

  5. В случае успешной расшифровки найденного пароля выполняется подключение к БД с передачей хеша пароля, происходит авторизация по паролю в БД.

  6. В случае отсутствия файла /etc/postgres/enc_utils_auth_settings.cfg или невозможности его расшифровать, в лог журнала формируется сообщение с типом WARNING.

  7. В случае, если пароль не найден, в лог журнала формируется сообщение с типом WARNING.

Аутентификация пользователя, использующего зашифрованный пароль от ТУЗ для подключения к ldap/AD#
  1. Выполняется подключение пользователя к БД, создается сессия в БД.

  2. Зачитываются параметры для подключения к ldap/AD из конфигурационного файла.

  3. Выполняется анализ поля ldapbindpasswd: является ли пароль зашифрованным или пароль представлен в открытом виде.

  4. Если пароль зашифрован, то выполняется его расшифровка и выполняется аутентификация с ldap/AD.

  5. В случае, если пароль представлен в открытом виде, то выполняется аутентификация с ldap/AD.

  6. Далее выполняется анализ результата аутентификации с ldap/AD.

  7. Если аутентификация пройдена, то выполняется подключение пользователя к БД.

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

Дополнительные доработки в инсталляторе в рамках интеграции утилиты хранения пароля#

  • Для корректной работы manage_backup.bin в скрипт запуска необходимо добавить следующие переменные окружения:

    LD_LIBRARY_PATH="/usr/pgsql-se-04/lib"
    PG_PLUGINS_PATH="/usr/pgsql-se-04/lib"
    PYTHONPATH="/usr/pgsql-se-04/postgresql_venv/lib/python3.6/site-packages/"
    PGHOME="/usr/pgsql-se-04/"
    
  • Для механизма отката необходимо учесть, что для отката etcd старой версии (в версиях Pangolin до 4.4.1) необходим пароль в открытом виде (который нужно восстановить). Данный пароль брался из старого конфигурационного файла patroni. Теперь нужно хранить все старые пароли etcd в зашифрованном с помощью ansible-vault виде, а способ получения пароля должен быть переписан.

Восстановление работоспособности узла кластера при смене параметров сервера#

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

После установки Pangolin утилита доступна в каталоге /opt/pangolin-common/pg_auth_reencrypt.

Утилита запускается в двух режимах:

  • автоматический — запуск настраивается при установке Pangolin;

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

Автоматический запуск утилиты (службой systemd)#

Установщик Pangolin создает новую службу/службы systemd (зависит от конфигурации кластера) для запуска и отслеживания состояния демона утилиты.

В автоматическом режиме утилита в процессе работы создает файл enc_params.cfg + '.' + 'имя_пользователя' в каталоге /etc/postgres. Файл создается с правами -rw-rw-r-- владельцем, от имени которого был запущен демон. Содержимое файла зашифровано. Утилита используется для хранения текущих параметров сервера. Изменение параметров сервера детектируется на основе данного файла.

Служба/службы запускаются при старте ОС и запускают демонов утилиты перешифрования, которые периодически (с периодом 5 секунд) проверяют параметры оборудования и, если они поменялись, обновляют файлы с шифрованной информацией. В зависимости от конфигурации кластера файлы могут принадлежать:

  • пользователю — Администратору СУБД (postgres). В данном случае запускается один демон утилиты от имени пользователя postgres;

  • или пользователям — Администратору СУБД (postgres) и Администратору безопасности (kmadmin_pg). В этом случае запускаются два демона: от имени пользователя postgres и от имени пользователя kmadmin_pg.

Список файлов для разных пользователей определяется конфигурацией утилиты (тег «owner», см. ниже «Конфигурационный файл утилиты»).

Для управления демоном утилиты служба создает каталог /var/run/pangolin_reencrypt/, где демон создает файл pangolin_reencrypt_<имя_пользователя_запустившего_утилиту>, содержащий идентификатор процесса pid. Отсутствие каталога не приводит к завершению работы утилиты с ошибкой, но будет выведено предупреждение в журнал: Create pid file failed. Сигналы для управления утилитой приводятся ниже в подразделе «Управление утилитой».

Ручной запуск утилиты#

Для запуска утилиты в ручном режиме требуется:

  • подготовить конфигурационный файл утилиты;

  • запустить бинарный файл утилиты с требуемыми параметрами (см. ниже «Параметры запуска утилиты»):

    /etc/postgres/pg_auth_reencrypt [OPTION]
    

При ручном запуске утилита также создает файл enc_params.cfg + '.' + 'имя_пользователя' с правами -rw-rw-r-- в каталоге /etc/postgres. Владельцем файла в данном случае будет пользователь, от имени которого была запущена утилита. Если у пользователя нет прав на создание файла в каталоге /etc/postgres, работа утилиты будет завершена с ошибкой.

Ручной запуск утилиты перешифрования на кластере#

На версиях кластера от 4.4.0 (где внедрено шифрование файлов с параметрами подключения) возможна ручная установка утилиты, для этого:

  1. Расположите исполняемый файл утилиты в каталоге /opt/pangolin-common/bin/pg_auth_reencrypt (владелец: root, группа: root, права: -rwxr-xr-x). Исполняемый файл утилиты располагается в дистрибутиве по пути pg_auth_reencrypt/opt/pangolin-common/bin/pg_auth_reencrypt.

  2. Расположите файл конфигурации утилиты /etc/postgres/enc_util.cfg (владелец: root, группа: root, права: rw-r--r–). Зависит от конфигурации кластера (см. ниже «Шаблон конфигурации утилиты перешифрования»).

  3. Создайте службу-шаблон с запуском демона в systemd (см. ниже «Шаблон спецификации службы для утилиты перешифрования»):

    • имя службы pangolin_reencrypt@.service;

    • служба запускается от пользователя переданного с помощью параметра (пример: pangolin_reencrypt@postgres.service);

    • служба должна создавать каталог /var/run/pangolin_reencrypt для pid файла(ов). Владелец postgres, группа kmadmin\_pg, g+rw;

    • служба должна запускать утилиту перешифрования паролей /opt/pangolin-common/bin/pg_auth_reencrypt;

    • служба должна автоматически запускаться при каждой загрузке Linux и в случае сбоев (Restart=on-failure);

  4. Обновите службы systemd (sudo systemctl daemon-reload).

  5. Запустите новую службу/службы (в зависимости от конфигурации кластера) и установите принудительный запуск при каждой загрузке ОС (sudo systemctl enable --now pangolin_reencrypt.service).

Шаблон конфигурации утилиты перешифрования#

{
    "files" :
    [
        ### файл 1: включается, если на кластере активирован tde или admin_protection
        {
            "name" : "{{ KMS_CONFIG }}",
            "owner" : "kmadmin_pg",
            "domain" : "kms"
        },
        ### файл 2: включается на всех конфигурациях
        {
            "name" : "{{ pg_encrypt_cfg }}",
            "owner" : "postgres",
            "domain" : "postgres"
        },
        ### файл 3: включается для конфигураций с patroni
        {
            "name" : "/etc/patroni/postgres.yml",
            "owner" : "postgres",
            "secrets" :
            [
                {
                    "type" : "tag",
                    "name" : "restapi/authentication/password",
                    "domain" : "postgres"
                },
                {
                    "type" : "tag",
                    "name" : "etcd/password",
                    "domain" : "postgres"
                },
                {
                    "type" : "text",
                    "name" : "ldapbindpasswd",
                    "domain" : "postgres"
                }
            ]
        }
        ### файл 4: включается для конфигураций без patroni
        {
            "name" : "pg_hba.conf",
            "owner" : "postgres",
            "secrets" :
            [
                {
                    "type" : "text",
                    "name" : "ldapbindpasswd",
                    "domain" : "postgres"
                }
            ]
        }
    ]
}

Примечание:

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

Шаблон спецификации службы для утилиты перешифрования#

[Unit]
Description=Runners Pangolin reencrypt service (%i)
After=syslog.target network.target

[Service]
Type=forking
User=%i
Group=%i

Environment="PGDATA=<path>/data"
Environment="PG_PLUGINS_PATH=<path>/lib"
PermissionsStartOnly=true
ExecStartPre=/bin/mkdir -p /var/run/pangolin_reencrypt
ExecStartPre=/bin/chown postgres:kmadmin_pg /var/run/pangolin_reencrypt
ExecStartPre=/bin/chmod g+rw /var/run/pangolin_reencrypt
ExecStartPost=/bin/sleep 1

ExecStart=/opt/pangolin-common/bin/pg_auth_reencrypt -l2 -d

PIDFile=/var/run/pangolin_reencrypt/pangolin_reencrypt_%i.pid
Restart=on-failure

[Install]
WantedBy=multi-user.target

Примечание:

<path> — домашняя директория Pangolin

Конфигурационный файл утилиты#

Установщик Pangolin создает конфигурационный файл утилиты enc_util.cfg, который расположен в каталоге /etc/postgres. Файл создается с правами -rw-r--r-- и владельцем root:root. Вносить изменения в файл может только привилегированный пользователь.

Конфигурационный файл хранится в формате JSON. Файлы с шифрованными параметрами подключения к БД задаются ключом files.

Для каждого файла указывается:

  • имя, через ключ name. Если указано неполное имя файла, то поиск файла происходит в каталоге, определенном через переменную окружения PGDATA;

  • владелец файла, через ключ owner. Утилита проверяет пользователя, который ее запустил: если в конфигурации утилиты для файла указан другой владелец, то утилита пропускает этот файл;

  • домен шифрования, через ключ domain. В случае, если файл шифруется полностью, то кроме имени и владельца требуется указать домен через ключ domain, для которого производится шифрование. Когда требуется зашифровать отдельные пароли в файлах, то с помощью ключа secrets указывается массив с описанием метода поиска пароля в файле. Метод поиска задается с помощью ключей:

    • type — указывает тип поиска;

    • name — указывает идентификатор пароля.

      Примечание:

      Если в type установлено значение «tag» — файл разбирается по формату yml. Поиск пароля происходит по тегам, указанным в поле name в порядке записи (теги разделены символом '/').

      Если в type установлено значение «text», то поиск пароля в файле происходит по строке name=<искомый_пароль>.

Для файла можно указать булевый признак опциональности через ключ opt. Если признак задан и равен true, то отсутствие файла на диске не приводит к ошибке в работе утилиты. Если признак не задан или задан и равен false, то отсутствие файла приведет к ошибке в работе утилиты, если не задан параметр -f (см. Параметры запуска утилиты).

Пример конфигурационного файла утилиты для конфигурации без patroni, но с tde:

    {
        "files" :
        [
            {
                "name" : "/etc/postgres/enc_connection_settings.cfg",
                "owner" : "kmadmin_pg",
                "domain" : "kms",
                "opt" : true
            },
            {
                "name" : "/etc/postgres/enc_utils_auth_settings.cfg",
                "owner" : "postgres",
                "domain" : "postgres"
            },
            {
                "name" : "pg_hba.conf",
                "owner" : "postgres",
                "secrets" :
                [
                    {
                        "type" : "text",
                        "name" : "ldapbindpasswd",
                        "domain" : "postgres"
                    }
                ]
            }
        ]
    }

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

  • -c --conf — необязательный параметр. Задает файл конфигурации утилиты, который требуется проверить на наличие ошибок. Утилита проверит файл на наличие ошибок и завершит работу с кодом 0, если конфигурация не содержит ошибок, и 1, если указанный файл невалиден.

    Параметр может быть комбинирован с параметром -l, при этом будет выведено диагностическое сообщение о результате проверки конфигурации. Рекомендуется проверить конфигурационный файл на наличие ошибок в процессе обновления файла /etc/postgres/enc_util.cfg, который используется утилитой при перешифровании.

    Если задан параметр -c, то параметры -f -r -s будут проигнорированы.

  • -l --log — необязательный параметр. Включает лог утилиты. Совместим со всеми остальными параметрами.

  • -f --force — необязательный параметр. Запускает утилиту в режиме игнорирования ошибок. Совместим со всеми параметрами.

    Если указан параметр -c, параметр -f учитываться не будет.

  • -r, --roll — необязательный параметр. Запускает утилиту в режиме отката операции перешифрования. Может задавать файл, для которого требуется применить процесс отката. Если файл не задан, то процесс отката перешифрования применяется ко всем файлам, указанным в конфигурации утилиты. Совместим со всеми параметрами.

    Если указан параметр -c, параметр -r учитываться не будет.

  • -s, --stable — необязательный параметр. Учитывается только в режиме перешифрования. Запрещает обновление/создание файла с параметрами оборудования. Используется при запуске утилиты для файлов с шифрованной информацией, принадлежащих разным пользователям.

    Примечание:

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

  • -e, --enc — необязательный параметр. Задает отдельный файл для перешифрования, который должен быть описан в конфигурации утилиты. Если этот параметр задан — перешифрование осуществляется только для данного файла, остальные файлы из конфигурации не перешифровываются.

  • -d, --daemon — необязательный параметр. Запускает утилиту в виде службы Linux (демона) для непрерывного отслеживания изменения параметров оборудования сервера (проверка изменения происходит с периодом 5 секунд).

    Примечание:

    Ключи -d, -c (проверка конфигурации), -e (перешифрование отдельного файла), -r (откат операции перешифрования) несовместимы: если используются два и более ключа, то утилита не запускается.

Управление службой утилиты#

Управлять утилитой pg_auth_reencrypt, запущенной в виде службы, можно с помощью следующих сигналов Linux:

  • SIGTERM - отправка запроса на завершение работы;

  • SIGUSR1 - отправка запроса на внеочередную проверку параметров оборудования;

  • SIGRTMIN - отправка запроса на проверку параметров (формируется таймером с периодом 5 секунд).

Режим игнорирования ошибок#

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

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

Режим отката операции перешифрования#

Перед началом процесса перешифрования утилита создает резервные копии файла с параметрами оборудования и файлов с шифрованными параметрами подключения к БД. Резервная копия создается в том же каталоге, где и исходный файл. Имя резервной копии файла формируется по принципу: .имя_оригинала_с_расширением.bak (пример для файла enc_params.cfg: .enc_params.cfg.bak).

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

Код завершения работы утилиты#

В случае успеха утилита возвращает ноль. Если работа утилиты завершилась с ошибкой — утилита возвращает код ошибки:

  • 0 — операция перешифрования, откат операции перешифрования завершились с успехом (файл конфигурации не содержит ошибок для параметра -c);

  • 1 — ошибка в файле конфигурации утилиты;

  • 2 — работа завершена с ошибкой (подробности указаны в логе).

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

Для отключения функциональности:

  1. Остановите службу/службы systemd Linux, запускающие демон утилиты.

    Для службы, запущенной от имени пользователя kmadmin_pg:

    sudo systemctl stop pangolin_reencrypt@kmadmin_pg
    

    Для службы, запущенной от имени пользователя postgres:

    sudo systemctl stop pangolin_reencrypt@postgres
    
  2. Переведите состояние служб в disable.

    Для службы, запущенной от имени пользователя kmadmin_pg:

    sudo systemctl disable --now pangolin_reencrypt@kmadmin_pg
    

    Для службы, запущенной от имени пользователя postgres:

    sudo systemctl disable --now pangolin_reencrypt@postgres
    

    Если демон утилиты запущен вручную, то требуется отправить процессу демона сигнал SIGTERM, для этого:

    1. Определите идентификаторы процессов демона:

      ps aux | grep -i pg_auth_reencrypt
      
    2. Для всех найденных процессов демона отправьте сигнал:

      kill -SIGTERM <pid>
      

    <pid> — найденный идентификатор процесса демона.

Лог утилиты#

Утилита формирует лог в стандартный поток вывода Linux. Журнал (log) содержит информацию о процессе работы утилиты. Журнал (log) утилиты может быть перенаправлен в файл средствами ОС. Включение журналирования задается параметром -l или --log. По умолчанию утилита выводит сообщения только в случае ошибок.

В режиме работы демона записи (log) переводятся в системный журнал Linux syslog. В этом режиме дополнительно в записи журнала поступает информация о результате инициализации демона. В случае успешного запуска демона утилиты в логе появится строка Reencrypt daemon was started for <имя_пользователя_запустившего_утилиту>.

В утилите предусмотрена возможность задать уровни логирования:

  • уровень 1 (-l1 или --log=1) — показывать только ошибки;

  • уровень 2 (-l2 или --log=2) — показывать записи (log) по перешифрованию данных и ошибки;

  • уровень 3 (-l3 или --log=3) — показывать лог по проверке параметров оборудования, перешифрованию данных и ошибки.

По умолчанию (без указания уровня: -l или --log) используется 3 уровень логирования.

Примечание:

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

Примеры:

  • Ошибка в конфигурационном файле:

        2022-06-06 17:33:52.870752130 [18572] ERROR: Configuration file content (json) error: /etc/postgres/enc_util.cfg
        2022-06-06 17:33:52.870818918 [18572] LOG: Load configuration /etc/postgres/enc_util.cfg FAIL
    
  • Запуск утилиты первый раз:

        2022-06-06 17:29:33.914889769 [18200] LOG: Load configuration /etc/postgres/enc_util.cfg ok
        2022-06-06 17:29:33.916778674 [18200] LOG: Start saving current encrypting params
        2022-06-06 17:29:33.923238749 [18200] LOG: Saving current encrypting params ok
    
  • Повторный запуск утилиты при неизменных параметрах сервера:

        2022-06-06 17:29:46.226502410 [18264] LOG: Load configuration /etc/postgres/enc_util.cfg ok
        2022-06-06 17:29:46.228432243 [18264] LOG: Check encrypting params in file
        2022-06-06 17:29:46.234465754 [18264] LOG: Encrypting params in file are equal to the current
    

Включение/отключение функциональности шифрования паролей#

Новая функциональность позволяет развернуть СУБД Pangolin без шифрованного хранилища.

Описание решения#

  1. Реализация решения в части инсталлятора.

    В скриптах развертывания и обновления создание шифрованного хранилища и шифрование паролей в конфигурационных файлах (postgres.yml и pg_hba.conf) определено под условие, которое контролируется параметром auth_encrypt в пользовательском конфигурационном файле. Значение по умолчанию: true. В конфигурационный файл patroni (postgres.yml) добавлены следующие параметры: postgresql.pgpass - путь до файла со строкой подключения, если шифрованное хранилище отсутствует. Значение по умолчанию: /home/postgres/.pgpass.

     postgres.yml
     postgresql:
        {%- if not auth_encrypt %}
         pgpass: "{{ PGUSERHOME }}/.pgpass"
        {%- endif %}
    

    postgresql.authentication.replication.password - пароль суперпользователя для репликации. Значение по умолчанию: patroni_password.

    postgres.yml
    postgresql:
        authentication:
        replication:
            {%- if not auth_encrypt %}
             password: '{{ patroni_user_pass }}'
            {%- endif %}
    

    postgresql.authentication.superuser.password - пароль для суперпользователя. Значение по умолчанию: patroni_password.

    postgres.yml
    postgresql:
        authentication:
            superuser:
            {%- if not auth_encrypt %}
            password: '{{ patroni_user_pass }}'
            {%- endif %}
    

    Внесены изменения в конфигурацию службы pangolin_reencrypt. Следующий блок не будет записан, если файл /etc/postgres/enc_utils_auth_settings.cfg не был найден.

    enc_util.cfg
    {% if pgar_encrypt_config_exists.stat.exists -%}
    {
        "name" : "/etc/postgres/enc_utils_auth_settings.cfg",
        "owner" : "postgres",
        "domain" : "postgres"
        },
    {% endif -%}
    

    Реализована возможность задать индивидуальный пароль для пользователя patroni в пользовательском конфигурационном файле. Регулируется параметром patroni_password(опциональный). Если пароль не задан, будет сгенерирован случайный. В процессе обновления была реализована проверка на наличие шифрованного хранилища. При наличии файла /etc/postgres/enc_utils_auth_settings.cfg параметр auth_encrypt выставляется в true.

  2. Реализация решения в части patroni.

    Patroni автоматически создает файл .pgpass, если зашифрованное хранилище паролей отсутствует. Создание файла происходит, если не проинициализирован контекст(отсутствует плагин шифрования) или отсутствует файл /etc/postgres/enc_utils_auth_settings.cfg. Данные о том, где создать файл patroni определяет из конфигурационного файла postgres.yml, секция postgresql.pgpass. Скорректирована запись в логе patroni при работе без шифрованного хранилища. Сообщение лога «using password from encrypted store for …» заменено на «using password from the config for …». Утилита pg_auth_config создает файл /etc/postgres/enc_utils_auth_settings.cfg только при добавлении записи в файл(аргумент add). Если файл не существовал, аргументы remove, show, check и edit создавали файл нулевого размера. Логика работы этих команд изменена. При отсутствии файла они будут выдавать ошибку \x1B[0mCannot load auth config (file is not found), где \x1B[0m - спец. цветовой символ (белый).

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

Есть ограничения в работе службы pangolin_reencrypt. Отсутствие файла или пароля внутри файла, которые прописаны в конфигурации службы pangolin_reencrypt, приведет к ошибке в работе перешифрования. Поэтому служба включается в процессе инсталляции только тогда, когда auth_encrypt: true и auth_reencrypt: true. Перед стартом инсталляции нельзя задать перечень ролей, пароли которых будут включены в шифрование или блоки конфигурационных файлов, содержащие пароли, которые нужно зашифровать.

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

Автоматическая установка#

Значение true для параметра auth_encrypt позволит включить использование решения.

Автоматическое обновление#

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

Ручное включение#

Примечание:

Действия производятся на ранее установленном стенде без шифрованного хранилища паролей.

Процесс включения шифрованного хранилища условно можно разделить на два этапа:

  1. Первый этап заключается в переводе не зашифрованных паролей в конфигурационных файлах postgres.yml и pg_hba.conf в зашифрованный вид с помощью утилиты шифрования паролей pg_auth_password.

    1. Для стенда в кластерной конфигурации зашифруйте пароли следующих секций в файле postgres.yml:

      postgres.yml
      
      restapi:
          authentication:
              username: patroniyml
              password: 'TestPasswordPatroniYml1029)'
      etcd:
          username: patronietcd
          password: 'TestPasswordPatroniEtcd1029)'
      postgresql:
          pg_hba:
             ... ldapbindpasswd="TestPassword4556@!"...
      
    2. Действие по шифрованию нужно производить поочередно на каждом узле. Произведите шифрование паролей на Active:

      TestPasswordPatroniYml1029)
      
      sudo su - postgres
      pg_auth_password enc
      
      *Ожидаемый результат:*
      
      enter password:
      ***************************
      enter password:
      ***************************
      $enc$0OGvuDcN3OGvOJ0rWuWHUPnLUi2KHB0pXN7qwdOslWQ=$sys$1rYgVwagOzQAtgRdQkTPa7VuSQBqRxSDGZTgzNU7MsRbgqWYmq1hKMZ+DJ4KVh0z 
      
      TestPasswordPatroniEtcd1029)
      
      sudo su - postgres
      pg_auth_password enc
      
      *Ожидаемый результат:*
      
      enter password:
      ***************************
      enter password:
      ***************************
      $enc$FPXR02NNWvpBXBWAE2hGLf/h651PazUo74fMmuU+m54=$sys$La7Kg5kJI6EURc86vGa2y7kAyOSeRyHy6bNKBJJdAZCvz83n+kcmHWbx4TqOynQB 
      
      
      TestPassword4556@!
      
      sudo su - postgres
      pg_auth_password enc
      
      *Ожидаемый результат:*
      
      enter password:
      ***************************
      enter password:
      ***************************
      $enc$LuwiEsacN+HGUbS0Jq5xPy/q1PKJRvrRD0Sjsodolvc=$sys$p58nbXXZGe89HLU3bPOiT9Kjlf7fuwnzyl3fsSi25lRF5QIaRm2SgJo3mLGX5SdV
      
    3. Замените открытые пароли на Active на полученный результат шифрования:

      *Ожидаемый результат:*
      postgres.yml
      
      restapi:
          authentication:
              username: patroniyml
              password: '$enc$2sWVW/CcM9Xg5pqXTvUNwF0wLKcgoV9nYZQh2B8J2PM=$sys$ofOrezSeQpXa5rx+dgyLg7VuSQBqRxSDGZTgzNU7MsRbgqWYmq1hKMZ+DJ4KVh0z'
      etcd:
          username: patronietcd
          password: '$enc$FPXR02NNWvpBXBWAE2hGLf/h651PazUo74fMmuU+m54=$sys$La7Kg5kJI6EURc86vGa2y7kAyOSeRyHy6bNKBJJdAZCvz83n+kcmHWbx4TqOynQB'
      postgresql:
          pg_hba:
              ... ldapbindpasswd="$enc$LuwiEsacN+HGUbS0Jq5xPy/q1PKJRvrRD0Sjsodolvc=$sys$p58nbXXZGe89HLU3bPOiT9Kjlf7fuwnzyl3fsSi25lRF5QIaRm2SgJo3mLGX5SdV"...
      
    4. Перечитайте конфигурацию на Active:

      sudo su - postgres
      reload
      
      *Ожидаемый результат:*
      
      + Cluster: clustername (7205282150766022368) ------+--------------+---------+----+-----------+
      | Member               | Host                      | Role         | State   | TL | Lag in MB |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      | srv-0-172.db.dev.sbt | srv-0-172.db.dev.sbt:5433 | Leader       | running |  2 |           |
      | srv-0-182.db.dev.sbt | srv-0-182.db.dev.sbt:5433 | Sync Standby | running |  2 |         0 |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      Are you sure you want to reload members srv-0-182.db.dev.sbt, srv-0-172.db.dev.sbt? [y/N]: y
      Reload request received for member srv-0-182.db.dev.sbt and will be processed within 10 seconds
      Reload request received for member srv-0-172.db.dev.sbt and will be processed within 10 seconds
      
    5. Произведите действия с пункта 2 по 4 на Standby.

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

    1. Для корректной работы компонента patroni добавьте следующие строки в хранилище с помощью утилиты pg_auth_config, где -h - хост, для которого будет использоваться пароль; -p - порт, для которого будет использоваться пароль; -U - имя пользователя, для которого будет использоваться пароль; -d - база данных, для которой будет использоваться пароль. Действие нужно произвести на обоих узлах:

      sudo su - postgres
      pg_auth_config add -s -h localhost -p 5433 -U patroni -d postgres
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "localhost", port: "5433", database: "postgres"
      New record added 
      
      sudo su - postgres
      pg_auth_config add -s -h localhost -p 5433 -U patroni -d replication
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "localhost", port: "5433", database: "replication"
      New record added 
      
      sudo su - postgres
      pg_auth_config add -s -h srv-0-172.db.dev.sbt -p 5433 -U patroni -d postgres
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "srv-0-172.db.dev.sbt", port: "5433", database: "postgres"
      New record added    
      
      sudo su - postgres
      pg_auth_config add -s -h srv-0-172.db.dev.sbt -p 5433 -U patroni -d replication
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "srv-0-172.db.dev.sbt", port: "5433", database: "replication"
      New record added 
      
      sudo su - postgres
      pg_auth_config add -s -h srv-0-182.db.dev.sbt -p 5433 -U patroni -d postgres
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "srv-0-182.db.dev.sbt", port: "5433", database: "postgres"
      New record added    
      
      sudo su - postgres
      pg_auth_config add -s -h srv-0-182.db.dev.sbt -p 5433 -U patroni -d replication
      
      *Ожидаемый результат:*
      
      Enter password:
      *******************
      Going to add auth record for user: "patroni", host: "srv-0-182.db.dev.sbt", port: "5433", database: "replication"
      New record added   
      
    2. Проверьте работоспособность хранилища паролей:

      sudo su - postgres
      pg_auth_config check
      
      *Ожидаемый результат:*
      
      Connection settings for host: "localhost", port "5433", database "postgres", user "patroni" are OK
      Connection settings for host: "localhost", port "5433", database "replication", user "patroni" are OK
      Connection settings for host: "srv-0-172.db.dev.sbt", port "5433", database "postgres", user "patroni" are OK
      Connection settings for host: "srv-0-172.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
      Connection settings for host: "srv-0-182.db.dev.sbt", port "5433", database "postgres", user "patroni" are OK
      Connection settings for host: "srv-0-182.db.dev.sbt", port "5433", database "replication", user "patroni" are OK
      
    3. Произведите удаление из конфигурационного файла patroni следующих параметров: postgresql.pgpass: /home/postgres/.pgpass, postgresql.authentication.replication.password: 'TestPasswordPatroni5647*&', postgresql.authentication.superuser.password: 'TestPasswordPatroni5647*&'.

    4. Произведите удаление файла /home/postgres/.pgpass на обоих узлах.

    5. Перечитайте конфигурацию и перезапустите сервер на Active:

      sudo su - postgres
      reload
      
      *Ожидаемый результат:*
      
      + Cluster: clustername (7205282150766022368) ------+--------------+---------+----+-----------+
      | Member               | Host                      | Role         | State   | TL | Lag in MB |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      | srv-0-172.db.dev.sbt | srv-0-172.db.dev.sbt:5433 | Leader       | running |  2 |           |
      | srv-0-182.db.dev.sbt | srv-0-182.db.dev.sbt:5433 | Sync Standby | running |  2 |         0 |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      Are you sure you want to reload members srv-0-182.db.dev.sbt, srv-0-172.db.dev.sbt? [y/N]: y
      Reload request received for member srv-0-182.db.dev.sbt and will be processed within 10 seconds
      Reload request received for member srv-0-172.db.dev.sbt and will be processed within 10 seconds
      
      sudo su - postgres
      restart --force
      
      *Ожидаемый результат:*
      
      + Cluster: clustername (7205282150766022368) ------+--------------+---------+----+-----------+
      | Member               | Host                      | Role         | State   | TL | Lag in MB |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      | srv-0-172.db.dev.sbt | srv-0-172.db.dev.sbt:5433 | Leader       | running |  2 |           |
      | srv-0-182.db.dev.sbt | srv-0-182.db.dev.sbt:5433 | Sync Standby | running |  2 |         0 |
      +----------------------+---------------------------+--------------+---------+----+-----------+
      Success: restart on member srv-0-172.db.dev.sbt
      Success: restart on member srv-0-182.db.dev.sbt
      
    6. Аналогичным образом производится добавление паролей для других пользователей БД в шифрованное хранилище паролей.

    7. Подключите службу перешифрования на обоих узлах:

      sudo su 
      systemctl start pangolin_reencrypt@postgres.service
      systemctl status pangolin_reencrypt@postgres.service
      
      *Ожидаемый результат:*
      
      ● pangolin_reencrypt@postgres.service - Runners Pangolin reencrypt service (postgres)
      Loaded: loaded (/etc/systemd/system/pangolin_reencrypt@.service; enabled; vendor preset: disabled)
      Active: active (running) since Tue 2023-01-31 11:30:43 MSK; 5h 48min ago
      Process: 3316 ExecStartPost=/bin/sleep 1 (code=exited, status=0/SUCCESS)
      Process: 3311 ExecStart=/opt/pangolin-common/bin/pg_auth_reencrypt -l2 -d (code=exited, status=0/SUCCESS)
      Process: 3310 ExecStartPre=/bin/chmod g+rw /var/run/pangolin_reencrypt (code=exited, status=0/SUCCESS)
      Process: 3305 ExecStartPre=/bin/chown postgres:kmadmin_pg /var/run/pangolin_reencrypt (code=exited, status=0/SUCCESS)
      Process: 3303 ExecStartPre=/bin/mkdir -p /var/run/pangolin_reencrypt (code=exited, status=0/SUCCESS)
      Main PID: 3315 (pg_auth_reencry)
      CGroup: /system.slice/system-pangolin_reencrypt.slice/pangolin_reencrypt@postgres.service
      └─3315 /opt/pangolin-common/bin/pg_auth_reencrypt -l2 -d
      
      Jan 31 11:30:42 srv-0-172.db.dev.sbt systemd[1]: Starting Runners Pangolin reencrypt service (postgres)...
      Jan 31 11:30:42 srv-0-172.db.dev.sbt pg_auth_reencrypt[3315]: Reencrypt daemon was started for postgres
      Jan 31 11:30:42 srv-0-172.db.dev.sbt pg_auth_reencrypt[3315]: Load configuration /etc/postgres/enc_util.cfg ok
      Jan 31 11:30:43 srv-0-172.db.dev.sbt systemd[1]: Started Runners Pangolin reencrypt service (postgres).
      Jan 31 11:30:47 srv-0-172.db.dev.sbt pg_auth_reencrypt[3315]: Start saving current encrypting params
      Jan 31 11:30:47 srv-0-172.db.dev.sbt pg_auth_reencrypt[3315]: Saving current encrypting params ok
      

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

Автоматическая установка#

Значение false для параметра auth_encrypt позволит отключить использование решения.

Автоматическое обновление#

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

Ручное отключение#

Примечание:

Действия производятся на ранее установленном стенде с шифрованным хранилищем паролей. Также необходимо заранее знать пароли пользователей БД, которые находятся в шифрованном хранилище паролей.

Произвести выключение шифрованного хранилища можно следующим образом:

  1. Произведите создание файла /home/postgres/.pgpass на Standby, назначьте права 0600 и владельца/группу postgres:

    sudo su - postgres
    mkdir /home/postgres/.pgpass
    chown postgres:postgres /home/postgres/.pgpass
    chmod 0600 /home/postgres/.pgpass
    ls -la /home/postgres/.pgpass
    
    *Ожидаемый результат:*
     
    -rw------- 1 postgres postgres 2152 Mar  1 17:40 .pgpass 
    
  2. Добавьте строку подключения в файл /home/postgres/.pgpass для пользователя patroni:

    echo "srv-0-172.db.dev.sbt:5433:*:patroni:TestPasswordPatroni5647*&" > /home/postgres/.pgpass
    
  3. Получите список серверов расширения pg_profile, если оно используется:

    select pgse_profile.show_servers();
    
    *Ожидаемый результат:*
                                                       show_servers
    ---------------------------------------------------------------------------------------------------------------------
    (master,"dbname=First_db host=srv-0-172.db.dev.sbt port=5433 user=profile_tuz",t,)
    (replica,"dbname=First_db host=srv-0-182.db.dev.sbt port=5433 user=profile_tuz",t,)
    (2 rows)
    
  4. Скорректируйте строки подключения/добавьте параметр password ко всем существующим серверам, полученным на предыдущем шаге, в расширении pg_profile, если используется:

    sudo su - postgres
    psql
    SELECT pgse_profile.set_server_connstr('master', 'dbname=First_db host=srv-0-172.db.dev.sbt pprb_dev port=5433 user=profile_tuz password=TestProfileUser56&*');
    SELECT pgse_profile.set_server_connstr('replica', 'dbname=First_db host=srv-0-182.db.dev.sbt pprb_dev port=5433 user=profile_tuz password=TestProfileUser56&*');
    
    *Ожидаемый результат:*
    
     set_server_connstr 
    --------------------
                       1
    (1 row)
    
  5. Скорректируйте конфигурационный файл patroni, добавив следующие параметры: postgresql.pgpass: /home/postgres/.pgpass, postgresql.authentication.replication.password: 'TestPasswordPatroni5647*&', postgresql.authentication.superuser.password: 'TestPasswordPatroni5647*&' на обоих узлах.

  6. Остановите службу перешифрования на обоих узлах:

    sudo su
    systemctl stop pangolin_reencrypt@postgres.service
    systemctl status pangolin_reencrypt@postgres.service
    
    *Ожидаемый результат:*
    
    ● pangolin_reencrypt@postgres.service - Runners Pangolin reencrypt service (postgres)
    Loaded: loaded (/etc/systemd/system/pangolin_reencrypt@.service; disabled; vendor preset: disabled)
    Active: inactive (dead)
      
    Feb 06 12:51:21 srv-1-7.db.dev.sbt systemd[1]: [/etc/systemd/system/pangolin_reencrypt@.service:19] Unknown lvalue 'TimeoutStopFailureMode' in section 'Service'
    Feb 06 16:22:28 srv-1-7.db.dev.sbt systemd[1]: [/etc/systemd/system/pangolin_reencrypt@.service:19] Unknown lvalue 'TimeoutStopFailureMode' in section 'Service'
    
  7. Произведите удаление всех записей из шифрованного хранилища паролей на обоих узлах:

    sudo su - postgres
    pg_auth_config reset
    pg_auth_config show
    
    *Ожидаемый результат:*
     
    Cannot load auth config (file is not found)
    
  8. Перечитайте конфигурацию и перезапустите сервер на Active:

    sudo su - postgres
    reload
    
    *Ожидаемый результат:*
    
    + Cluster: clustername (7205282150766022368) ------+--------------+---------+----+-----------+
    | Member               | Host                      | Role         | State   | TL | Lag in MB |
    +----------------------+---------------------------+--------------+---------+----+-----------+
    | srv-0-172.db.dev.sbt | srv-0-172.db.dev.sbt:5433 | Leader       | running |  2 |           |
    | srv-0-182.db.dev.sbt | srv-0-182.db.dev.sbt:5433 | Sync Standby | running |  2 |         0 |
    +----------------------+---------------------------+--------------+---------+----+-----------+
    Are you sure you want to reload members srv-0-182.db.dev.sbt, srv-0-172.db.dev.sbt? [y/N]: y
    Reload request received for member srv-0-182.db.dev.sbt and will be processed within 10 seconds
    Reload request received for member srv-0-172.db.dev.sbt and will be processed within 10 seconds
    
    sudo su - postgres
    restart --force
    
    *Ожидаемый результат:*
    
    + Cluster: clustername (7205282150766022368) ------+--------------+---------+----+-----------+
    | Member               | Host                      | Role         | State   | TL | Lag in MB |
    +----------------------+---------------------------+--------------+---------+----+-----------+
    | srv-0-172.db.dev.sbt | srv-0-172.db.dev.sbt:5433 | Leader       | running |  2 |           |
    | srv-0-182.db.dev.sbt | srv-0-182.db.dev.sbt:5433 | Sync Standby | running |  2 |         0 |
    +----------------------+---------------------------+--------------+---------+----+-----------|
    Success: restart on member srv-0-172.db.dev.sbt
    Success: restart on member srv-0-182.db.dev.sbt
    

Нативное интервальное партицирование#

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

Автопартицирование может быть вложенным. При вложенном автопартицировании все создаваемые таблицы, кроме самой последней по уровню вложенности, являются партицированными таблицами. Реальные данные в такой схеме хранятся только в самой последней таблице. Автопартицирование создаст необходимые таблицы на всех уровнях вложенности.

Внимание!

При удалении или перемещении данных пустые партиции не удаляются.

Автопартицирование не исключает возможности управлять партициями вручную. При этом все стандартные механизмы в СУБД продолжают работать. Однако нужно учитывать потенциальное пересечение интервалов партиций, если партиции, создаваемые вручную, частично пересекаются с диапазонами автоматически создаваемых партиций. Для исключения пересечения необходимо убедиться, что настройки автопартицирования не приведут к созданию партиций, имеющих пересекающиеся диапазоны данных с существующими партициями.

Автопартицирование работает следующим образом. При создании партицированной таблицы (корневой таблицы) указываются параметры автопартицирования. При вставке или изменении данных СУБД пытается найти подходящую партицию. Если подходящая партиция не найдена, то происходит поиск правила автопартицирования для таблицы. Если правило найдено, то происходит создание новой таблицы и затем повторная попытка вставки данных. Данный процесс может повторяться рекурсивно для вложенного автопартицирования.

Синтаксис команды создания таблицы с включенным автопартицированием#

При создании таблицы через CREATE TABLE вместо стандартной конструкции PARTITION BY можно использовать новую конструкцию AUTO PARTITION BY:

CREATE * TABLE * auto_partition_spec [ ... ] *

Где auto_partition_spec:

{ AUTO PARTITION BY RANGE ( key [, ... ] ) PERIOD  ( period [, ... ]  ) [ OFFSET ( offset [, ... ] ) ] |
  AUTO PARTITION BY HASH  ( key [, ... ] ) MODULUS ( modulus [, ... ] ) |
  AUTO PARTITION BY LIST  ( key [, ... ] ) }

Где * — любые допустимые стандартные конструкции запроса.

Параметры:

  • key — ключ партицирования. Допустимы те же значения, что и в стандартной конструкции PARTITION BY;

  • period — значение периода партиций (разности значений между FROM и TO в создаваемых партициях);

  • offset — значение смещения периода партиций. По умолчанию равен 0 (для числовых интервалов) либо эпохе (для дат);

  • modulus — значение модуля (MODULUS) создаваемых партиций.

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

Подряд может быть указано несколько AUTO PARTITION. Это задействует вложенное партицирование в указанном порядке. Первым следует описание автопартицирования для таблицы верхнего уровня, последним — для таблицы нижнего уровня.

Примечание:

Примеры задания команд для различных правил автопартицирования приведены в подразделе «Примеры задания команд для различных правил автопартицирования» текущего раздела.

Правила автопартицирования#

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

Правила автопартицирования для стратегии RANGE#

Для интервальных (RANGE) партиций указываются следующие параметры:

  • PERIOD — период партицирования, определяющий размер диапазона значений, которые будет содержать каждая партиция. Это значение будет соответствовать разности между параметрами TO и FROM для автоматически создаваемой партиции;

  • OFFSET — смещение значений, определяющее смещение значений TO и FROM относительно условного нуля.

Так, при создании таблицы с параметрами PERIOD (10) OFFSET (3), партиции будут создаваться для диапазонов значений «… (-7 3) (3 13) (13 23) …».

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

  • для числовых значений — со смещением 0;

  • для значений даты или времени — со смещением от эпохи (1970-01-01 00:00:00).

Формулы, по которым вычисляется диапазон партиции для значения value:

FROM = value - ( (value - OFFSET) % PERIOD )
TO   = FROM + PERIOD

. где % — оператор вычисления остатка от деления левого операнда на правый. Для дат и времени под делением понимается количество интервалов времени, прошедших с момента эпохи (для дат и меток времени) или начала дня (для времен).

Для данной стратегии доступны следующие типы данных:

  • INTEGER (все варианты);

  • NUMERIC (все варианты);

  • DATE;

  • TIMESTAMP;

  • TIMESTAMPTZ (используется часовой пояс, установленный на сервере);

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

Примечание:

Технически имеется возможность использовать типы данных с плавающей запятой (REAL), однако эта возможность, вероятно, будет отключена, поскольку может вызывать неожиданное поведение.

Правила автопартицирования для стратегии HASH#

Для хеш (HASH) партиций должен быть указан модуль (MODULUS).

Модуль определяет количество возможных партиций. При вставке или изменении данных рассчитывается хеш-значение для данных. Далее производится вычисление остатка от деления от этого значения по указанному модулю. Этот остаток (REMAINDER) определяет партицию, в которую попадут данные.

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

Правила автопартицирования для стратегии LIST#

Для перечисляемых (LIST) партиций параметры отсутствуют.

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

Именование партиций#

Новые партиции создаются с именем, состоящим из:

  • имени вышестоящей по уровню вложенности таблицы;

  • символов «_p»;

  • числа — условного номера партиции, в типичной ситуации равному порядковому номеру в порядке создания партиций, начиная с 0.

Просмотр параметров автопартицирования#

Просмотр при помощи утилиты psql#

В утилите psql в вывод команд /dP и /dPn добавлен столбец Autopartition parameters, который содержит в текстовом виде параметры автопартицирования для перечисленных таблиц.

Просмотр при помощи функции pg_autopartition_params#

Функция pg_autopartition_params принимает в качестве аргумента идентификатор (OID) таблицы и возвращает текст — параметры автопартицирования для указанной таблицы.

  • Если таблица с указанным OID отсутствует, то выполнение прекратится с соответствующей ошибкой.

  • Если таблица с указанным OID не является автопартицированной, то функция вернет пустую строку.

Просмотр через системный каталог#

Допускается просматривать текущие параметры автопартицирования, расположенные в системном каталоге pg_catalog.pg_autopartition.

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

Блокировки при автопартицировании#

В момент автоматического создания партиции устанавливается блокировка уровня AccessExclusive для партицированной таблицы. Это влечет установку блокировок уровня ShareRowExclusive на зависимые ограничения (constraints) таблицы и может привести к взаимоблокировкам (deadlock) транзакций либо возникновению ресурсного голодания и сильному снижению производительности.

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

Также возможна ручная установка эксклюзивной блокировки при помощи SQL-запроса LOCK TABLE в начале транзакции, перед вставкой или изменением данных, для того, чтобы момент взаимоблокировки был обнаружен и потенциально разрешен до начала операции создания партиции.

Отключение автопартицирования#

Функция создания таблиц с автопартицированием не может быть отключена.

На таблицы, созданные без указания схемы автопартицирования, функции автопартицирования не распространяются.

Примеры задания команд для различных правил автопартицирования#

Автопартицирование RANGE#

-- Партиции будут создаваться с интервалом в 10 единиц, начиная с 0.

CREATE TABLE table1( col1 int ) AUTO PARTITION BY RANGE (col1) PERIOD(10);

INSERT INTO table1(col1) VALUES (1);  -- автоматически будет создана партиция table1_p0 с диапазоном FROM (0) TO (10)
INSERT INTO table1(col1) VALUES (2);  -- попадет в table1_p0
INSERT INTO table1(col1) VALUES (5);  -- попадет в table1_p0
INSERT INTO table1(col1) VALUES (15); -- автоматически будет создана партиция table1_p1 с диапазоном FROM (10) TO (20)
INSERT INTO table1(col1) VALUES (20); -- автоматически будет создана партиция table1_p2 с диапазоном FROM (20) TO (30)

Автопартицирование HASH#

CREATE TABLE table1( col1 int ) AUTO PARTITION BY HASH (col1) MODULUS (16);

INSERT INTO table1(col1) VALUES (1);  -- автоматически будет создана партиция table1_p0 для значений MODULUS (16) REMAINDER (X)
INSERT INTO table1(col1) VALUES (1);  -- попадет в table1_p0
INSERT INTO table1(col1) VALUES (2);  -- автоматически будет создана партиция table1_p1 для значений MODULUS (16) REMAINDER (X)
INSERT INTO table1(col1) VALUES (17); -- попадет в table1_p1

Автопартицирование LIST#

-- Партиции будут создаваться для каждого значения.

CREATE TABLE table1( col1 int ) AUTO PARTITION BY LIST (col1);

INSERT INTO table1(col1) VALUES (1);  -- автоматически будет создана партиция table1_p0 для значений VALUES (1)
INSERT INTO table1(col1) VALUES (1);  -- попадет в table1_p0
INSERT INTO table1(col1) VALUES (2);  -- автоматически будет создана партиция table1_p1 для значений VALUES (2)
INSERT INTO table1(col1) VALUES (15); -- автоматически будет создана партиция table1_p2 для значений VALUES (15)

Автопартицирование RANGE со смещением#

-- Партиции будут создаваться с интервалом в 3 единицы, со смещением 2.

CREATE TABLE table1( col1 INTEGER ) AUTO PARTITION BY RANGE (col1) PERIOD(3) OFFSET(2);

INSERT INTO table1(col1) VALUES (1); -- автоматически будет создана партиция table1_p0 для диапазона FROM (-1) TO (2)
INSERT INTO table1(col1) VALUES (2); -- автоматически будет создана партиция table1_p1 для диапазона FROM (2)  TO (5)
INSERT INTO table1(col1) VALUES (3); -- попадет в table1_p1
INSERT INTO table1(col1) VALUES (4); -- попадет в table1_p1
INSERT INTO table1(col1) VALUES (5); -- автоматически будет создана партиция table1_p2 для диапазона FROM (5)  TO (8)

Автопартицирование по сложному ключу партицирования#

-- Партиции будут создаваться с интервалами 10 (для поля col1) и 25 (для поля col2) со смещением 5 для поля col2.

CREATE TABLE table1( col1 int, col2 int ) AUTO PARTITION BY RANGE (col1, col2) PERIOD(10, 25) OFFSET(0, 5);

INSERT INTO table1(col1, col2) VALUES (0,0);   -- автоматически будет создана партиция table1_p0 для диапазона FROM (0,-20) TO (10,5)
INSERT INTO table1(col1, col2) VALUES (5,0);   -- попадет в table1_p0
INSERT INTO table1(col1, col2) VALUES (0,5);   -- автоматически будет создана партиция table1_p1 для диапазона FROM (0,5)   TO (10,30)
INSERT INTO table1(col1, col2) VALUES (10,10); -- автоматически будет создана партиция table1_p2 для диапазона FROM (10,5)  TO (20,30)
INSERT INTO table1(col1, col2) VALUES (3,25);  -- попадет в table1_p1
INSERT INTO table1(col1, col2) VALUES (15,29); -- попадет в table1_p2

Автопартицирование для типа данных TIMESTAMP#

-- Партиции будут создаваться с интервалом в 1 день, начиная в 10:30 дня и заканчивая в 10:30 (не включительно) следующего дня.

CREATE TABLE table1( col1 TIMESTAMP ) AUTO PARTITION BY RANGE (col1) PERIOD ( INTERVAL '1 day' ) OFFSET ( INTERVAL '10 hours 30 minutes' );

INSERT INTO table1(col1) VALUES ('2022-01-01 15:13:00'); -- автоматически будет создана партиция table1_p0 для диапазона FROM ('2022-01-01 10:30:00') TO ('2022-01-02 10:30:00')
INSERT INTO table1(col1) VALUES ('2022-01-01 10:31:00'); -- попадет в table1_p0
INSERT INTO table1(col1) VALUES ('2022-01-01 10:29:00'); -- автоматически будет создана партиция table1_p1 для диапазона FROM ('2021-12-31 10:30:00') TO ('2022-01-01 10:30:00')

Автопартицирование для типа данных DATE#

-- Партиции будут создаваться с интервалом в 1 месяц, начиная с 5-го числа

CREATE TABLE table1( f DATE ) AUTO PARTITION BY RANGE (f) PERIOD ( INTERVAL '1 month' ) OFFSET ( INTERVAL '4 days' );

INSERT INTO table1(col1) VALUES ('2022-01-01'); -- автоматически будет создана партиция table1_p0 для диапазона FROM ('2021-12-05') TO ('2022-01-05')
INSERT INTO table1(col1) VALUES ('2022-01-04'); -- попадет в table1_p0
INSERT INTO table1(col1) VALUES ('2022-01-05'); -- автоматически будет создана партиция table1_p1 для диапазона FROM ('2022-01-05') TO ('2022-02-05')
INSERT INTO table1(col1) VALUES ('2022-01-29'); -- попадет в table1_p1
INSERT INTO table1(col1) VALUES ('2022-02-04'); -- попадет в table1_p1

Вложенное (каскадное) автопартицирование#

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

CREATE TABLE table1( col1 INTEGER , col2 INTEGER ) AUTO PARTITION BY RANGE (col1) PERIOD(10) AUTO PARTITION BY HASH (col2) MODULUS (16);

INSERT INTO table1(col1) VALUES (5,10);  -- автоматически будет создана партиция table1_p0 для диапазона FROM (0) TO (10) с автопартицированием AUTO PARTITION BY HASH (col2) MODULUS (16)
                                         -- и автоматически будет создана партиция table1_p0_p0 для таблицы table1_p0 c MODULUS (16) REMAINDER(X)
INSERT INTO table1(col1) VALUES (8,11);  -- автоматически будет создана партиция table1_p0_p1 для таблицы table1_p0 c MODULUS (16) REMAINDER(X)
INSERT INTO table1(col1) VALUES (8,26);  -- попадет в table1_p0_p1
INSERT INTO table1(col1) VALUES (12,10); -- автоматически будет создана партиция table1_p1 для диапазона FROM (10) TO (20) с автопартицированием AUTO PARTITION BY HASH (col2) MODULUS (16)
                                         -- и автоматически будет создана партиция table1_p1_p0 для таблицы table1_p1 c MODULUS (16) REMAINDER(X)
INSERT INTO table1(col1) VALUES (18,26); -- попадёт в table1_p1_p1

Поддержка подготовленных запросов для транзакционного режима кластера высокой доступности Pangolin#

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

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

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

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

Исходя из указанного, менеджер пула соединений кластера высокой доступности эксплуатируется в транзакционном режиме, при котором формируются разделенные пулы соединений:

  • со стороны клиентских приложений к менеджеру пула соединений;

  • со стороны менеджера пула соединений к PostgreSQL.

А также происходит выделение соединений из пула соединений к PostgreSQL на время выполнения транзакции, инициированной со стороны клиентского приложения.

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

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

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

Также возможно возникновение коллизий, связанных с изменением драйверами режима транзакций на стороне клиентских приложений read-only/read-write, в соответствии с логикой работы драйверов, и несоответствия ожидаемого режима транзакций фактически установленному в контексте процесса PostgreSQL, что приводит к ошибкам при выполнении запросов к PostgreSQL.

Реализованные функции#

  • для клиентских приложений:

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

    • прозрачное переключение режимов транзакций read-only/read-write при включенном транзакционном режиме менеджера пула соединений кластера высокой доступности;

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

    • прозрачное переключение сессионных и текущих ролей при включенном транзакционном режиме менеджера пула соединений кластера высокой доступности;

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

  • отсутствие необходимости дополнительной настройки параметров драйверов на стороне клиентских приложений.

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

  • решение не обеспечивает прозрачности работы с подготовленными запросами при переключении клиентского приложения между серверами кластера высокой доступности Pangolin, то есть запрос, подготовленный на одном сервере не будет доступен к выполнению на другом;

  • решение накладывает ограничение на количество одновременно обслуживаемых клиентских сессий и на количество единовременно хранящихся подготовленных запросов в рамках сессии. Ограничение регулируется настроечными параметрами экземпляров Pangolin;

  • решение не позволяет хранить и обрабатывать для клиентских сессий значения search_path длиной более чем 1023 байта (задается настроечным параметром);

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

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

Описание ролей пользователей#

Управление параметрами настройки функциональности выполняется пользователями с правами Администраторов СУБД.

Вызов функций мониторинга и получения статистики по реализованной функциональности выполняется пользователями с правами Администратора СУБД или пользователями, которым делегированы права на вызов таких функций.

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

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

Сохраняется реализованный ранее в PostgreSQL интерфейс работы с подготовленными запросами:

  • выполнение SQL-запросов PREPARE, EXECUTE, DESCRIBE и DEALLOCATE;

  • выполнение драйверами запросов расширенного протокола PostgreSQL, в том числе через драйвера jdbc.

Инициализация, условия выполнения программы, завершение программы#

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

  • настройку параметров в postgresql.conf (или postgres.yml Patroni) экземпляров БД кластера высокой доступности;

  • настройки идентификаторов региона и обработчика в pgbouncer.ini экземпляров pgBouncer кластера высокой доступности;

  • включение транзакционного режима в pgbouncer.ini экземпляров pgBouncer кластера высокой доступности;

  • перезапуск экземпляров PostgreSQL кластера высокой доступности;

  • перезапуск экземпляров pgBouncer кластера высокой доступности.

Описание настроечных параметров функциональности#

В pgBouncer:

  • session_region_id - region ID snowflake для идентификаторов клиентских сессий, 0-23;

  • session_worker_id - worker ID snowflake для идентификаторов клиентских сессий, 0-102.

Примечание:

Необходимость отдельного session_worker_id обусловлена возможностью запуска на одном узле нескольких процессов pgBouncer. Для разделения множества идентификаторов между такими процессами используется параметр session_worker_id - свой для каждого процесса pgBouncer узла (session_region_id).

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

В PostgreSQL

  • shared_prepared_statements - управляет включением/выключением функциональности разделяемых подготовленных запросов, BOOLEAN;

  • max_client_sessions - максимальное количество клиентских сессий. Рекомендуется устанавливать с двухкратным запасом для демпфирования асинхронности удаления данных отключенных сессий;

  • max_prepared_statements_per_session - максимальное количество именованных запросов на клиентскую сессию;

  • max_shared_prepared_statements_names - предел количества хранимых в shared memory уникальных подготовленных запросов;

  • max_local_prepared_statements_names - предел количества локально хранимых в памяти процессов бэкенда картированных наименований подготовленных запросов;

  • max_local_prepared_statements - предел количества локально хранимых в памяти процессов бэкенда подготовленных запросов;

  • shared_prepared_statements_search_path_length - максимальная длина значения search_path клиентской сессии, включая нулевой байт окончания строки (по умолчанию 128, минимум 16, максимум 1024).

Описание принципов работы и особенностей функциональности#

Решение построено на следующих базовых принципах:

  • решение предназначено только для работы в транзакционном режиме pgBouncer;

  • pgBouncer производит присваивание открываемым клиентским сессиям идентификаторов (используется алгоритм Snowflake ID). Присваиваемые идентификаторы уникальны среди всего множества pgBouncer, работающих в кластере;

  • при закрытии клиентского соединения на PostgreSQL с pgBouncer по первому свободному соединению передается сообщение о закрытии клиентской сессии для удаления ее информации из карт контекста;

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

  • при получении сообщения с идентификатором клиентских сессий процесс бэкенда PostgreSQL сохраняет контекст (значения сессионных переменных клиентской сессии, см. функцию get_client_sessions в документе «Документация на публичные API: PL/pgSQL») в общей памяти и поднимает значения сессионных переменных новой клиентской сессии, если они есть в общей памяти;

  • подготовленный запрос на базовом уровне идентифицируется хешем, вычисленным из указанных выше параметров, и на уровне привязки к клиентским сессиям — сочетанием идентификатора клиентской сессии и имени подготовленного запроса в клиентской сессии, в привязке к хешу запроса;

  • при выполнении подготовки запроса по SQL-запросу или сообщению расширенного протокола происходит поиск ранее сохраненного в общей памяти (и на диске) подготовленного запроса с таким же текстом, набором параметров и search_path. Это нужно для избегания многократного хранения больших объемов одинаковой информации о запросах. При отсутствии такого ранее сохраненного запроса происходит его сохранение в файл на диске в директории pg_prep_stats базы данных. Это необходимо, так как тексты запросов могут быть потенциально очень большими. Также происходит регистрация привязки сочетания идентификатора клиентской сессии с именем подготовленного запроса к хешу подготовленного запроса в карте в общей памяти. Для неименованных запросов имя запроса принимается равным плейсхолдеру;

  • при необходимости выполнения подготовленного запроса в процессе бэкенда производится следующий порядок действий (предполагается, что в бэкенде уже установлен контекст нужной клиентской сессии):

    1. Производится поиск подготовленного запроса, сохраненного в локальном кэше процесса, для текущей клиентской сессии и указанного имени. Если такой находится, то используется этот запрос. Параметры, влияющие на локальный кэш подготовленных запросов процессов бэкендов:

      • max_local_prepared_statements_names — для карты «клиентская сессия+имя=хеш»;

      • max_local_prepared_statements — для непосредственно уникальных подготовленных запросов;

    2. Если запрос не находится локально, то производится поиск в общей памяти, по карте клиентская сессия+имя=хеш и по хешу — сам подготовленный запрос. Если не находится, то на этом выполнение подготовленного запроса завершается, т.к. его нет.

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

    4. Если запрос не был найден локально и нашелся только в общей памяти — готовится подготовленный запрос в процессе бэкенда с синтаксическим анализом его структуру. В кэш ложится уже проанализированный и подготовленный запрос. Желательно минимизировать вытеснения уникальных подготовленных запросов, поэтому значения параметра max_local_prepared_statements рекомендуется делать больше, чем ожидаемое количество уникальных подготовленных запросов.

    5. Производится выполнение подготовленного запроса.

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

Примечание:

Описание API функциональности подготовленных запросов приведено в документации по API.

Функциональность FOREIGN DATA WRAPPER для БД Oracle#

Расширение oracle_fdw — это внешняя оболочка данных, которая позволяет получать доступ к таблицам и представлениям базы данных Oracle через сторонние таблицы. Когда клиент СУБД Pangolin обращается к внешней таблице, расширение oracle_fdw обращается к соответствующим данным во внешней базе данных Oracle через библиотеку интерфейса вызовов Oracle (OCI) на сервере PostgreSQL в СУБД Pangolin. Это расширение PostgreSQL предоставляет доступ к базам данных Oracle из СУБД Pangolin, включая отображение условий WHERE и требуемых столбцов, а также всестороннюю поддержку EXPLAIN.

Для обработки и проверки создаваемого расширения oracle_fdw используются функции oracle_fdw_handler и oracle_fdw_validator. Описание всех функций расширения в разделе «Функциональность FOREIGN DATA WRAPPER для БД Oracle» документа «Документация на публичные API».

Установка расширения oracle_fdw описана в подразделе «Расширение oracle_fdw» документа «Руководство по установке».

Внутреннее устройство описано в подразделе «Расширение oracle_fdw» документа «Детальная архитектура».

В данном разделе описаны параметры (опции), варианты и пример использования oracle_fdw.

Параметры#

Параметры оболочки внешних данных (FOREIGN DATA WRAPPER)#

Внимание!

Рекомендуем всегда создавать новую оболочку внешних данных (SQL CREATE FOREIGN DATA WRAPPER), если необходимо, чтобы параметры были постоянными. Если вы измените обертку внешних данных oracle_fdw, созданную по умолчанию, любые изменения будут потеряны при сбросе или восстановлении.

Для расширения oracle_fdw используется необязательный параметр nls_lang.

Когда клиент СУБД Pangolin обращается к внешней таблице базы данных Oracle, oracle_fdw обращается к соответствующим данным во внешней базе данных Oracle через библиотеку интерфейса вызовов Oracle (OCI) на сервере СУБД Pangolin.

Для того, чтобы получить доступ к библиотеке OCI из oracle_fdw, установите переменную окружения NLS_LANG для Oracle в параметр nls_lang. Параметр NLS_LANG находится в форме language_territory.charset (например, AMERICAN_AMERICA.AL32UTF8). Этот параметр должен соответствовать кодировке вашей базы данных. Если это значение не задано, расширение oracle_fdw автоматически определит правильную кодировку либо выдаст предупреждение, если определить кодировку не удалось.

Параметры сервера - источника внешних данных (foreign server options)#

Ниже перечислены параметры для работы с внешним сервером (foreign server):

  • dbserver (обязательный параметр) – строка подключения к сторонней БД Oracle может быть в любой из форм, поддерживаемых Oracle.

    Например:

    CREATE SERVER ora_test FOREIGN DATA WRAPPER oracle_fdw
    OPTIONS (dbserver 'host_ora:1521/EPXDB01');
    CREATE SERVER
    

    где:

    • host_ora:1521 – имя:номер порта сервера Oracle;

    • EPXDB01 – имя сервера базы данных.

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

  • isolation_level (необязательно) – уровень изоляции транзакций используемый в БД Oracle. Допустимые значения serializable (по умолчанию), read_committed или read_only.

    Примечание:

    Обратите внимание, что таблица Oracle может быть запрошена более одного раза во время одной транзакции СУБД Pangolin (например, во время объединения (JOIN) таблиц). Чтобы убедиться, что не может возникнуть несоответствий, вызванных конкурентными транзакциями, уровень изоляции транзакций должен гарантировать стабильность чтения. Это возможно только с помощью уровней изоляции Oracle SERIALIZABLE или READ ONLY.

    Реализация наиболее строгого уровня изоляции SERIALIZABLE в Oracle довольно нестабильна и вызывает ошибки сериализации ORA-08177 в неожиданных ситуациях, например, вставки в таблицу. Использование READ COMMITTED позволяет обойти эту проблему, но существует риск возникновения несоответствий. В случае его использования рекомендуем узнать, может ли внешнее сканирование выполняться более одного раза. Для этого нужно проверить планы выполнения запросов (EXPLAIN).

  • nchar (boolean, необязательно, значение по умолчанию off):

    • Установка этого параметра в значение on позволяет выбрать более дорогостоящее преобразование символов на стороне Oracle. Это необходимо, если используется однобайтовый набор символов базы данных Oracle, но при этом присутствуют столбцы NCHAR или NVARCHAR2, содержащие символы, которые не могут быть представлены в наборе символов базы данных.

    • Установка nchar в on оказывает заметное влияние на производительность и вызывает ошибки ORA-01461 с операторами UPDATE, которые устанавливают строки более 2000 байт (или 16383, если у вас MAX_STRING_SIZE = EXTENDED). Эта ошибка, по-видимому, является ошибкой Oracle.

Параметры прав доступа (USER MAPPING)#

  • user (обязательно). Имя пользователя Oracle для подключения.

  • password (необязательно). Пароль пользователя Oracle для подключения. В СУБД Pangolin возможно использование шифрованного хранилища паролей (утилита pg_auth_config). Если пароль не задан в параметре password, он будет взят из хранилища паролей по соответствию имени хоста, порта и имени БД из строки подключения, указанной в используемом foreign server.

Параметры внешней таблицы (FOREIGN TABLE)#

  • table (обязательно):

    Имя таблицы Oracle. Должно быть написано точно так же, как оно было сохранено в системном каталоге Oracle. Как правило, имя содержит только символы в верхнем регистре.

    Чтобы определить внешнюю таблицу на основе произвольного запроса Oracle, установите этот параметр для запроса, заключенного в круглые скобки, например:

    OPTIONS (table '(SELECT col FROM tab WHERE val = ''string'')')
    

    Параметр schema в данном случае указывать не нужно.

    Инструкции INSERT, UPDATE и DELETE будут работать со сторонней таблицей, основанной на таких запросах, если вы хотите избежать этого (или путаницы с сообщениями об ошибках Oracle для более сложных запросов), используйте опцию readonly.

  • dblink (необязательно):

    Oracle database link, через который доступна таблица. Должно быть написано точно так же, как оно было сохранено в системном каталоге Oracle. Как правило, оно содержит только символы в верхнем регистре.

  • schema (необязательно):

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

  • max_long (необязательно, значение по умолчанию «32767»):

    Максимальный размер полей с типом LONG, LONG RAW и XMLTYPE в таблице Oracle. Возможными значениями являются целые числа от 1 до 1073741823 (максимальный размер bytea в PostgreSQL). Этот объем памяти будет выделен как минимум дважды, поэтому большие значения будут занимать много памяти. Если max_long меньше размера самого большого из полученных значений, вы получите ошибку ORA-01406: fetched column value was truncated.

  • readonly (необязательно, значение по умолчанию «false»):

    Операции INSERT, UPDATE и DELETE доступны только для таблиц, где данный параметр не равен yes/on/true.

  • sample_percent (необязательно, значение по умолчанию «100»):

    Данный параметр влияет только на выполнение операции ANALYZE и может пригодиться для выполнения ANALYZE очень больших таблиц за разумное время. Значение должно быть в диапазоне от 0,000001 до 100, оно определяет процент блоков таблицы Oracle, которые будут выбраны случайным образом для вычисления статистики таблицы базы данных Pangolin. Это достигается с помощью выражения SAMPLE BLOCK(x) в Oracle. Построение ANALYZE завершится с ошибкой ORA-00933 для таблиц, определенных с помощью запросов Oracle, и может завершиться с ошибкой ORA-01446 для таблиц, определенных со сложными представлениями (view) Oracle.

  • prefetch (необязательно, значение по умолчанию «200»):

    Задает количество строк, которые будут извлечены с помощью одного кругового перехода между СУБД Pangolin и Oracle во время сканирования внешней таблицы. Реализовано с помощью предварительной выборки строк Oracle. Значение должно находиться в диапазоне от 0 до 10240, где нулевое значение отключает предварительную выборку. По умолчанию строки выбираются порциями по 200 штук. Высокие значения могут повысить производительность, но будут использовать больше памяти сервера СУБД Pangolin.

    Примечание:

    Если запрос Oracle включает столбец BLOB, CLOB или BFILE, предварительная выборка строк не будет работать (ограничения Oracle). Как следствие, запросы к таким столбцам во внешней таблице будут выполняться долго при извлечении большого количества строк.

Параметры полей#

  • key (необязательно, значение по умолчанию «false»):

    Если значение равно yes/on/true, соответствующее поле в таблице Oracle является первичным ключом. Чтобы работали операции UPDATE и DELETE, установите этот параметр для всех столбцов, относящихся к первичному ключу таблицы.

  • strip_zeros (необязательно, значение по умолчанию "false"):

    Если значение равно yes/on/true, ASCII 0 символы будут удалены из строки перед передачей. Такие символы допустимы в Oracle, но не в PostgreSQL, поэтому они вызовут ошибку при чтении oracle_fdw. Данная опция актуальна только для типов character, character varying и text.

Использование расширения oracle_fdw#

Привилегии Oracle#

Учетная запись в Oracle должна иметь привилегию CREATE SESSION и права на чтение таблиц или представлений в запросе.

Для выполнения EXPLAIN VERBOSE пользователь также должен обладать привилегией SELECT на представлениях V$SQL и V$SQL_PLAN.

Подключение к внешней БД#

Расширение oracle_fdw кэширует соединения Oracle, поскольку создание сеанса Oracle для каждого отдельного запроса обходится дорого. Все соединения автоматически закрываются по окончании сеанса со стороны СУБД Pangolin.

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

Поля и столбцы внешних таблиц#

Когда вы определяете внешнюю таблицу, столбцы таблицы базы данных Oracle сопоставляются столбцам СУБД Pangolin в порядке, в котором они указаны.

Расширение oracle_fdw будет включать в запрос Oracle только те столбцы, которые действительно необходимы для запроса СУБД Pangolin.

Таблица СУБД Pangolin может содержать больше или меньше столбцов, чем таблица базы данных Oracle. Если в ней больше столбцов, и эти столбцы используются, появится предупреждение и будут возвращены значения NULL.

Если необходимо выполнить операцию UPDATE или DELETE, убедитесь, что параметр key установлен для всех столбцов, принадлежащих первичному ключу таблицы. Невыполнение этого требования приведет к ошибкам.

Типы данных#

Необходимо определить столбцы таблиц СУБД Pаngolin с типами данных, которые может преобразовать oracle_fdw (см. таблицу преобразования ниже). Это ограничение применяется только в том случае, если столбец действительно используется, поэтому можно определять «фиктивные» столбцы для непереводимых типов данных до тех пор, пока к ним не будет получен доступ (этот трюк работает только с SELECT, а не при изменении внешних данных). Если значение из Oracle превышает размер столбца СУБД Pаngolin (например, длину столбца varchar или максимальное целочисленное значение), будет выведено сообщение об ошибке во время выполнения.

Данные преобразования типов автоматически выполняются расширением oracle_fdw:

Oracle type

Possible PostgreSQL types

CHAR

char, varchar, text

NCHAR

char, varchar, text

VARCHAR

char, varchar, text

VARCHAR2

char, varchar, text, json

NVARCHAR2

char, varchar, text

CLOB

char, varchar, text, json

LONG

char, varchar, text

RAW

uuid, bytea

BLOB

bytea

BFILE

bytea (read-only)

LONG RAW

bytea

NUMBER

numeric, float4, float8, char, varchar, text

NUMBER(n,m) with m<=0

numeric, float4, float8, int2, int4, int8, boolean, char, varchar, text

FLOAT

numeric, float4, float8, char, varchar, text

BINARY_FLOAT

numeric, float4, float8, char, varchar, text

BINARY_DOUBLE

numeric, float4, float8, char, varchar, text

DATE

date, timestamp, timestamptz, char, varchar, text

TIMESTAMP

date, timestamp, timestamptz, char, varchar, text

TIMESTAMP WITH TIME ZONE

date, timestamp, timestamptz, char, varchar, text

TIMESTAMP WITH LOCAL TIME ZONE

date, timestamp, timestamptz, char, varchar, text

INTERVAL YEAR TO MONTH

interval, char, varchar, text

INTERVAL DAY TO SECOND

interval, char, varchar, text

XMLTYPE

xml, char, varchar, text

MDSYS.SDO_GEOMETRY

geometry (see "PostGIS support" below)

Если тип NUMBER привести к boolean, тогда "0" превратится в "false", все остальное в "true".

Вставка или обновление XMLTYPE работает только со значениями, которые не превышают максимальную длину типа данных VARCHAR2 (4000 или 32767, в зависимости от параметра MAX_STRING_SIZE).

Тип данных NCLOB в настоящее время не поддерживается, поскольку Oracle не может автоматически преобразовать его в кодировку клиента. Если нужны преобразования, отличающиеся от вышеуказанных, определите соответствующее представление (view) в Oracle или Pangolin.

Инструкции WHERE и ORDER BY#

СУБД Pаngolin будет использовать все применимые части предложения WHERE в качестве фильтра для проверки. Запрос Oracle, который создает oracle_fdw, будет содержать предложение WHERE, соответствующее этим критериям фильтрации, всякий раз, когда такое условие может быть безопасно переведено в Oracle SQL. Эта функция, также известная как выдвижение предложений WHERE, может значительно сократить количество строк, извлекаемых из Oracle, и может позволить оптимизатору Oracle выбрать подходящий план доступа к требуемым таблицам.

Аналогично, предложения ORDER BY будут перенесены в Oracle там, где это возможно. Обратите внимание, что ORDER BY, сортирующее по символьной строке, будет пропущено, поскольку нет гарантий, что порядок сортировки в СУБД Pаngolin и Oracle будет одинаковым.

Для использования попробуйте писать простые условия для внешней таблицы. Выберите типы данных столбцов СУБД Pаngolin, соответствующие типам Oracle, поскольку в противном случае условия не могут быть переведены.

Выражения now(), transaction_timestamp(), current_timestamp, current_date и localtimestamp будут переведены правильно.

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

Объединения (JOIN) между внешними таблицами#

Начиная с версии PostgreSQL 9.6 расширение oracle_fdw может передавать инструкцию join на сервер Oracle, то есть join между двумя внешними таблицами приведет к одному запросу Oracle, который выполняет join на стороне Oracle.

Необходимые условия:

  • обе таблицы должны относиться к одному внешнему серверу Oracle;

  • JOIN между 3 и более таблицами не произойдет;

  • JOIN должен использоваться в выражении SELECT;

  • oracle_fdw должен быть способен выполнить все JOIN и условия WHERE;

  • перекрестный JOIN без условий не будет выполнен;

  • если выполнен JOIN, ORDER BY выполнен не будет.

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

Изменение внешних данных#

Расширение oracle_fdw поддерживает операции INSERT, UPDATE и DELETE на внешних таблицах. Данные операции доступны по умолчанию (также и в БД, обновленной с ранних версий PostgreSQL) и могут быть отключены опцией readonly на внешней таблице.

Чтобы операции UPDATE и DELETE работали, столбцы, относящиеся к первичному ключу в таблице Oracle, должны иметь установленную опцию key. Значения данных столбцов используются для идентификации строк внешней таблицы, поэтому убедитесь, что опция установлена на ВСЕХ столбцах, относящихся к первичному ключу.

Если во время вставки один из столбцов внешней таблицы пропущен, этому столбцу присваивается значение, определенное в предложении DEFAULT для внешней таблицы СУБД Pangolin (или NULL, если предложение DEFAULT отсутствует). Предложения DEFAULT в соответствующих столбцах Oracle не используются. Если внешняя таблица СУБД Pangolin не включает все столбцы таблицы Oracle, для столбцов, не включенных в определение внешней таблицы, будут использоваться предложения DEFAULT в Oracle.

Директива RETURNING в операцих INSERT, UPDATE или DELETE поддерживается, кроме столбцов Oracle с типами данных LONG или LONG RAW (сам Oracle не поддерживает данные типы данных в RETURNING).

Триггеры для внешних таблиц поддерживаются, начиная с версии PostgreSQL 9.4. Триггеры, определенные с использованием AFTER и FOR EACH ROW, требуют, чтобы во внешней таблице не было столбцов с типом данных Oracle LONG или LONG RAW. Это происходит потому, что такие триггеры используют предложение RETURN, упомянутое выше.

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

Транзакции пересылаются в Oracle, поэтому BEGIN, COMMIT, ROLLBACK и SAVEPOINT работают должным образом. Подготовленные запросы, относящиеся к Oracle, не поддерживаются. Подробности см. в подразделе «Расширение oracle_fdw» документа «Детальная архитектура».

Поскольку oracle_fdw по умолчанию использует сериализованные транзакции, возможно, что запросы на изменение данных приведут к сбою сериализации:

ORA-08177: can't serialize access for this transaction

Это может произойти, если несколько транзакций одновременно изменяют таблицу и вероятность этого возрастает на длинных транзакциях. Такие ошибки могут быть идентифицированы по статусу SQLSTATE(40001). Приложение, использующее oracle_fdw, должно повторить транзакции, которые завершаются с этой ошибкой.

По возможности используйте другие уровни изоляции транзакций (READ COMMITTED или READ ONLY), чтобы избежать данной ошибки.

Планы запросов (EXPLAIN)#

Команда EXPLAIN в СУБД Pаngolin покажет запрос, который фактически отправлен в Oracle. EXPLAIN VERBOSE покажет план выполнения Oracle (но это не будет работать с версиями Oracle 9i и ниже).

Сбор статистики (ANALYZE)#

Можно использовать ANALYZE для сбора статистики внешней таблицы. oracle_fdw поддерживает такую возможность.

Без статистики СУБД Pаngolin не может оценить количество строк для запросов по внешней таблице, что может привести к выбору неправильных планов выполнения. СУБД Pаngolin не будет автоматически собирать статистику для внешних таблиц с помощью демона autovacuum, как это делается для обычных таблиц, поэтому особенно важно запускать ANALYZE для внешних таблиц после создания и всякий раз, когда внешняя таблица значительно изменилась.

Примечание

Для внешней таблицы Oracle выполнение ANALYZE приведет к полному последовательному сканированию таблицы. Для того, чтобы ускорить процесс, можно использовать параметр таблицы sample_percent.

Поддержка геоданных PostGIS#

Тип данных geometry доступен только если установлено расширение PostGIS.

Поддерживаются только такие геометрические типы, как: POINT, LINE, POLYGON, MULTIPOINT, MULTILINE и MULTIPOLYGON в двух и трех измерениях. Пустые значения PostGIS не поддерживаются, поскольку они не имеют аналогов в Oracle Spatial.

Значения NULL для Oracle SRID будут преобразованы в 0 и наоборот. Для других преобразований между Oracle SRID и PostGIS SRID создайте файл srid.map в каталоге общего доступа PostgreSQL. Каждая строка этого файла должна содержать SRID Oracle и соответствующий SRID PostGIS, разделенные пробелами. Сохраняйте размер файла небольшим для обеспечения хорошей производительности.

Импорт определения сторонних таблиц (IMPORT FOREIGN SCHEMA)#

Расширение oracle_fdw имеет функцию, которая позволяет массово создавать сторонние таблицы. Можно создать внешнюю таблицу, используя CREATE FOREIGN TABLE. При этом необходимо определить каждый столбец в соответствии с его определением на стороне БД Oracle. Это достаточно трудоемко, если количество таблиц велико.

С помощью IMPORT FOREIGN SCHEMA есть возможность создавать сторонние таблицы для каждой из таблиц, определенных в импортированной схеме, с возможностью импорта только некоторых из этих таблиц.

Примечание

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

В дополнение к документации по IMPORT FOREIGN SCHEMA, учитывайте следующее:

  • IMPORT FOREIGN SCHEMA создаст внешние таблицы для всех объектов, найденных в ALL_TAB_COLUMNS, включая таблицы, представления и материализованные представления, но не синонимы.

  • Поддерживаемые параметры для IMPORT FOREIGN SCHEMA:

  • case – управляет регистром имен таблиц и столбцов при импорте; Возможные значения:

    • keep: оставить имена такими как в Oracle, как правило в верхнем регистре.

    • lower: преобразовать имена всех таблиц и столбцов в нижний регистр.

    • smart: преобразовать только имена, записанные полностью в верхнем регистре в Oracle (значение по умолчанию).

  • collation: порядок сортировки, используемый при преобразовании регистра при выборе значения lower или smart для параметра case. По умолчанию используется порядок сортировки используемый в БД. Поддерживаются только значения, которые есть в схеме pg_catalog. Доступные параметры сортировки указаны в таблице pg_collation, значения collname.

  • dblink: dblink на базу данных Oracle, через которую осуществляется доступ к схеме. Имя должно быть написано точно так же, как оно было сохранено в системном каталоге Oracle. Как правило, оно содержит только символы в верхнем регистре.

  • readonly: устанавливает опцию readonly для всех импортируемых таблиц(см. описание опций таблиц).

  • max_long: устанавливает опцию max_long для всех импортируемых таблиц (см. описание опций таблиц).

  • sample_percent: устанавливает опцию sample_percent для всех импортируемых таблиц (см. описание опций таблиц).

  • prefetch: устанавливает опцию prefetch для всех импортируемых таблиц (см. описание опций таблиц).

  • Имя схемы должно быть написано точно так же, как оно сохранено в системном каталоге Oracle. Как правило, имя содержит только символы в верхнем регистре. Поскольку PostgreSQL переводит имена в нижний регистр перед обработкой, необходимо обернуть имя схемы двойными кавычками (например, "SCOTT").

  • Имена таблиц в выражениях, использующих LIMIT TO или EXCEPT, должны быть написаны так, как они будут отображаться в PostgreSQL после преобразования регистра (см. параметр case).

Обратите внимание, что IMPORT FOREIGN SCHEMA не работает с СУБД Oracle версии 8i и ниже.

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

Ниже приведен простейший пример использования расширения oracle_fdw. Более детальная информация описана в разделах «Параметры» и «Использование расширения oracle_fdw». Пример предполагает, что работа ведется под пользователем ОС postgres и он может подключиться к БД Oracle:

sqlplus orauser/orapwd@//dbserver.mydomain.com:1521/ORADB

Проверка подключения к БД необходима, чтобы убедиться, что Oracle клиент и окружение настроены корректно и все работает правильно. Кроме этого необходимо, чтобы расширение oracle_fdw присутствовало в инсталляции Pangolin (убедитесь, что версия Pangolin используется не ниже 4.5.0).

Предположим, что необходимо получить доступ к таблице Oracle, которая имеет вид:

SQL> DESCRIBE oratab
 Name                            Null?    Type
 ------------------------------- -------- ------------
 ID                              NOT NULL NUMBER(5)
 TEXT                                     VARCHAR2(30)
 FLOATING                        NOT NULL NUMBER(7,2)

Для этого:

  1. Сконфигурируйте oracle_fdw под администратором СУБД Pangolin:

    CREATE EXTENSION oracle_fdw;
    CREATE SERVER oradb FOREIGN DATA WRAPPER oracle_fdw
            OPTIONS (dbserver '//dbserver.mydomain.com:1521/ORADB');
    
  2. Выдайте права на использование стороннего сервера пользователю:

    GRANT USAGE ON FOREIGN SERVER oradb TO pguser;
    
  3. Подключитесь к БД пользователем pguser и выполните:

    CREATE USER MAPPING FOR pguser SERVER oradb OPTIONS (user 'orauser');
    
  4. Пароль пользователя Oracle должен быть сохранен в шифрованном хранилище паролей, утилита pg_auth_config;

  5. Создайте внешнюю таблицу:

    CREATE FOREIGN TABLE oratab (
            id integer OPTIONS (key 'true') NOT NULL,
            text character varying(30),
            floating double precision NOT NULL
        ) SERVER oradb OPTIONS (schema 'ORAUSER', table 'ORATAB');
    

Теперь вы можете обращаться к данной таблице, как к обычной таблице PostgreSQL в СУБД Pangolin.

Поддержка 1С#

Новая функциональность позволяет использовать Pangolin в качестве СУБД для «Платформы 1С: Предприятие версии 8.2 и 8.3».

Функциональность заключается в возможности активирования ряда оптимизаций планировщика запросов, оптимизаций внутренних алгоритмов, изменений поведения СУБД и новых расширений.

Описание решения#

Добавлен отключаемый (параметром optimize_for_1c) набор оптимизаций изменений в поведении алгоритмов:

  • сбор статистики для мульти-столбцовых индексов для лучшего предсказания избирательности мульти-столбцовых JOIN;

  • оптимизация выполнения некоторых планов, в случае если достоверно известно, что часть этих планов возвращает пустые множества;

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

  • оптимизация копирования внутренних структур памяти в ядре СУБД;

  • добавлена периодическая проверка активности клиентских подключений;

  • анализ условий выборки WHERE и оптимизация условия, если это позволит использовать индексное сканирование;

  • улучшение расчёта избирательности на основе статистики мульти-столбцовых ключей;

  • улучшен расчет стоимости для выражений COALESCE;

  • изменен расчет стоимости выборки одной строки;

  • оптимизация JOIN самих на себя по уникальным столбцам. Отдельно отключается при помощи параметра enable_self_join_removal;

  • оптимизация путем перестановки последовательности группировки по GROUP BY;

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

  • оптимизирован алгоритм построения плана в части поиска уникальных слияний;

  • изменен путь поиска функций like_escape и similar_to_escape при парсинге выражений для возможности использования расширения mchar;

  • добавлена поддержка операций над Mchar строками;

  • оптимизирован внутренний алгоритм подбора уникального названия столбца;

  • доработаны алгоритмы оценки избирательности на основе гистограмм для мульти-столбцовых ключей;

  • установка параметра default_with_oids приводит не к фатальной ошибке, а к предупреждению.

Команда CREATE EXTENSION была расширена в части возможности указать старую версию расширения, когда необходимо произвести обновление расширения с версии расширения, которая была разработана «по старому стилю» в виде отдельно созданных объектов. Актуально только при миграции базы данных с версий PostgreSQL до 9.1.

Добавлены новые расширения:

  • fastrun – добавляет функцию fasttruncate для быстрой, но транзакционно небезопасной очистки временных таблиц;

  • fulleq – добавляет оператор == сравнения типов данных, который возвращает true если значения равны, либо оба NULL;

  • mchar – добавляет операторы для работы с типом данных Mchar, используемый в Microsoft SQL Server;

  • online_analyze – осуществляет анализ данных сразу после вызовов INSERT/UPDATE/DELETE/SELECT INTO;

  • plantuner – упрощенное расширение по управлению планами запросов.

Установка этих расширений осуществляется во всех случаях, однако автоматическое включение и активация только при выборе установки с поддержкой 1С.

Внимание!

Работа баз данных, созданных с включённым параметром optimize_for_1c на старых версиях продукта не гарантируется.

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

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

Включение функциональности осуществляется через новый параметр enable_1c_support в custom_config_initial.yml. Данный параметр определяет значение параметров для СУБД, управляющих расширениями, оптимизациями и изменениями поведения алгоритмов. При установке параметра enable_1c_support в значение true меняются следующие параметры СУБД:

  • pg_stat_track_io_timing: 'off' - но только если не задан конфигурационный файл pg_stat_track_io_timing, иначе будет использоваться значение заданное в нем;

  • optimize_for_1c: 'on';

  • включаются (добавляются в параметр shared_preload_libraries) и активируются расширения fasttrun, fulleq, mchar в схеме public;

  • autovacuum: 'on';

  • synchronous_commit: 'off';

  • max_locks_per_transaction = '256';

  • row_security: 'False';

  • temp_buffers: '256MB';

  • bgwriter_delay: '20ms';

  • bgwriter_lru_multiplier: '4.0';

  • bgwriter_lru_maxpages: '400';

  • autovacuum_max_workers: <количество ядер/2, но не менее 4>;

  • autovacuum_naptime: '20s';

  • from_collapse_limit: '8';

  • join_collapse_limit: '8';

  • geqo: 'on';

  • geqo_threshold: '12';

  • standard_conforming_strings: 'off';

  • escape_string_warning: 'off';

  • plantuner.fix_empty_table: 'on';

  • online_analyze.enable: 'off';

  • online_analyze.table_type: 'temporary';

  • online_analyze.verbose: 'off';

  • online_analyze.threshold: '50';

  • online_analyze.scale_factor: '0.1';

  • online_analyze.local_tracking: 'on';

  • online_analyze.min_interval: '10000'.

Схема процесса приведена в документе «Детальная архитектура», раздел «Схема активирования поддержки 1С».

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

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

Параметр

Описание

Значения

optimize_for_1c

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

on – включить оптимизации и новое поведение. Рекомендуется использовать при использовании продукта при совместной работе с 1С. off – выключить оптимизации и новое поведение. Значение по умолчанию. Рекомендуется использовать во всех остальных случаях

enable_self_join_removal

Контролирует оптимизацию JOIN самих на себя по уникальным столбцам. Не влияет на работу при выключенном параметре optimize_for_1c

off – выключить оптимизацию. Значение по умолчанию. on – включить оптимизацию. Может приводить к некоторым проблемам при выполнении запросов

Индекс RUM#

Индексный метод доступа RUM является одним из инструментов оптимизации доступа к данным. RUM основан на GIN-подобном индексном методе и, кроме того, включает дополнительную методику оценки релевантности результата поиска («дистанцией»).

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

Установка расширения производится в выбранной БД следующим способом:

SET ROLE db_admin;
CREATE EXTENSION IF NOT EXISTS rum WITH SCHEMA ext;
RESET ROLE;

RUM имеет качественное преимущество в возможности ранжирования результатов поиска по «дистанции»/«схожести». При этом «дистанция»/«схожесть» имеют другой алгоритм обработки, чем существующие функции ts_rank, ts_rank_cd.

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

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

  1. Запрос SQL должен иметь условие поиска по дистанции. В случае FTS - tsquery должен использовать оператор дистанции «<=>»,«<2>»,«<3>» и тому подобные.

  2. Запрос SQL, содержащий условие поиска по дистанции, должен оперировать термами низкой или средней селективности (при возможности их оценки).

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

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

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

Удаление расширения производится следующим способом:

SET ROLE db_admin;
DROP EXTENSION IF EXISTS rum CASCADE;
RESET ROLE;

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

Утилита расчета хеш-суммы в формате PostgreSQL предназначена для вычисления хеш-суммы переданной в нее текстовой строки. Используется для вычисления хеш-сумм для использования в сценариях автоматизации, например, для заполнения пользовательского конфигурационного файла инсталлятора, в котором задаются имена учетных записей и их пароли, в том числе в виде хеш-сумм scram-sha-256 или md5. Делается это для того, чтобы пароль в открытом виде не попадал в логи СУБД при создании пользователя.

Утилита поставляется как есть, в виде python-скрипта и работает на любой платформе, где есть Python.

Утилита одинаково работает на python2 и python3.

Утилита расположена в директории utils в дистрибутиве продукта и не попадает в финальную инсталляцию кластера. Для использования утилиты необходимо извлечь ее из дистрибутива и запустить в среде исполнения python:

tar -zxvf pangolin_5_3_0.tar.gz utils/psql_get_password_hash/psql_get_password_hash.py
python ./utils/psql_get_password_hash/psql_get_password_hash.py --help

Утилита принимает на вход следующие параметры (в случае, если параметр не задан, используется значение по умолчанию):

  • -h, --help - выводит справку по использованию утилиты;

  • -t TYPE, --type TYPE - тип вычисляемого хеша. Возможные варианты: scram-sha-256, md5, linux-sha-512 (значение по умолчанию - scram-sha-256);

  • -P PASSWORD, --password PASSWORD - параметр password (пароль, для которого вычисляется хеш-сумма). Если не задан, утилита запросит интерактивно;

  • -U USERNAME, --username USERNAME - параметр username (необходим для вычисления хеша md5 или sha-512). Если не задан и необходим (тип вычисляемого хеша md5 или sha-512), утилита запросит интерактивно.

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

  • Вычисление хеша scram-sha-256 (пароль можно как передать параметром, так и ввести в ответ на запрос утилиты):

    $ python3 psql_get_password_hash.py -t scram-sha-256 -P password
    SCRAM-SHA-256$4096:rvPI7j0HTxgxAqW1lCGifA==$OrTN09KVqBA6fpT/EOT4S0W3VH0k4Fuye6LMYNtiS/k=:ddiQjzHNY0X9zXVlBri8DQTIbRkCwvhvOaOH+JHrpVA=
    $ python3 psql_get_password_hash.py -t scram-sha-256
    Password:
    SCRAM-SHA-256$4096:XGI8E5PEm0feXlCvo/YK5A==$TK6u0sWYH+LvRcKsP95z/m20qP6K1GnE6WfrwBXOfYw=:Swh0UixWfJimW+7XjOMZuaY9cMOH/aIhImex3oOZrss=
    
  • Вычисление хеша md5 (пароль можно как передать параметром, так и ввести в ответ на запрос утилиты, для расчета md5 в postgresql также используется имя пользователя):

    $ python3 psql_get_password_hash.py -t md5 -P password -U user
    md54d45974e13472b5a0be3533de4666414
    $ python3 psql_get_password_hash.py -t md5
    Password:
    Username:
    md54d45974e13472b5a0be3533de4666414
    $ python3 psql_get_password_hash.py -t md5 -P 'password' -U 'user'
    md54d45974e13472b5a0be3533de4666414
    
  • Вычисление хеша sha-512 (для заведения пользователей Linux пароль можно как передать параметром, так и ввести в ответ на запрос утилиты):

    $ python3 psql_get_password_hash.py -t linux-sha-512 -P password -U postgres
    postgres:$6$EvwbrlgjZc8neqdE$vOKjo6npaL6kv055Qan4Xh3zUWTJ0yJxvHPTd948n2Mx4cR6HTFSPVf/dd/1TBTSq3418WkSeR3HyfE57ClEt.
    $ python3 psql_get_password_hash.py -t linux-sha-512
    Password:
    Username:
    postgres:$6$mxdF1yYWtwiMS8vT$a2nFRoXu1PBH56/ejQhh.5G0OoxgW7aKEXpXUaH0gTcrqqCYjeLy2zVNVwXtAWmV7rMemCiodkNxmhOIp8wu0.
    $ python3 psql_get_password_hash.py -t linux-sha-512 -P 'password' -U 'postgres'
    postgres:$6$Hw0Zt4v+sZGOag5C$lKnLZ1lqmUhZEJQNe6oHIlFycxjMIlZwwWyRac59D8kpUI95ivvSJ0u9JxHuaCtD4fV/5B/Tv.N9qgyw5YMI81
    

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

# qwerty'
# admin
$ python3 psql_get_password_hash.py -t md5
Password:
Username:
md5d8fd40d277741197a0a25ea10529e67b
# При передаче пароля параметром любой символ можно экранировать обратным слэшем
$ python3 psql_get_password_hash.py -t md5 -U admin -P qwerty\'
md5d8fd40d277741197a0a25ea10529e67b
$ python3 psql_get_password_hash.py -t md5 -U admin -P \q\w\e\r\t\y\'
md5d8fd40d277741197a0a25ea10529e67b
# Обратный слэш тоже можно экранировать
$ python3 psql_get_password_hash.py -t md5 -U admin -P \\qwerty\'
md5989af44547db1322f6e633d2ab68f75e