Прозрачное защитное преобразование данных (TDE)
Прозрачное защитное преобразование данных (Transparent Data Encryption, TDE) — это технология, предназначенная для защиты данных на уровне файловой системы. Данные засекречиваются перед записью на диск и декодируются при чтении в память. TDE позволяет защитить данные от несанкционированного доступа, со стороны системных администраторов и других лиц, имеющих доступ к файловой системе.
Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.
В СУБД Pangolin при помощи TDE преобразование данные:
- хранящиеся в журналах предварительной записи (WAL), файлах отношений, резервных копиях и временных файлах БД;
- передаваемые по каналам связи в ходе физической и логической репликаций.
Описание
Для преобразования данных применяется алгоритм AES, который реализован в рамках модуля Encryption support. Эта технология обеспечивает прозрачность для приложений — засекречивание и декодирование данных происходят без необходимости внесения изменений в код приложений.
TDE интегрируется с системами управления ключами (Key Management System/KMS, хранилище секретов): HashiCorp Vault или KMS-заменителем. Эти решения обеспечивают хранение ключей засекречивания, используемых в механизме Transparent Data Encryption.
При прерывании процесса преобразования WAL-файлов (первоначальном включении TDE) в СУБД Pangolin на диске могут оставаться файлы $PGDATA/global/enc_keys.json и $PGDATA/global/enc_settings.cfg. Из-за данных файлов появляются ошибки чтения WAL-файлов утилитой pg_waldump. Необходимо удалить файлы вручную, если в дальнейшем не планируется повторный запуск включения TDE сразу после аварийного прерывания процесса преобразования WAL-файлов. Если запустить повторное засекречивание, то удалять файлы необязательно.
Настройка
Настройка прозрачного защитного преобразования данных
Настройка прозрачного защитного преобразования данных доступна с хранилищем секретов либо с использованием KMS-заменителя. Активация функциональности доступна ручным и автоматизированным способом. Инструкция с шагами действий данных вариаций представлена в разделе «Подключение СЗИ» данного документа.
Ключи засекречивания и мастер-ключ
Ключи засекречивания организованы в двухуровневую иерархию:
- мастер-ключ регулярно изменяется и используется для засекречивания ключей второго уровня;
- ключи второго уровня засекречивают объекты базы данных и не подлежат ротации, что позволяет избежать перекодирования данных при обновлении мастер-ключа.
Пример структуры хранения ключей в Hashicorp Vault:

actual_master_key– метка актуального мастер-ключа;actual_master_key_created– параметр, содержащий дату и время установки/ротации мастер-ключа в форматеYYYYMMDD_HHMMSS_MMM, гдеYYYY– год,MM– месяц,DD– день,HH– часы в формате 24 часа,MM– минуты,SS– секунды,MMM- миллисекунды;master_key_value_<timestamp>— значение мастер-ключа, где<timestamp>в имени параметра — дата и время в форматеYYYYMMDD_HHMMSS_MMM, гдеYYYY– год,MM– месяц,DD– день,HH– часы в формате 24 часа,MM– минуты,SS– секунды,MMM- миллисекунды;wal_key– значение ключа засекречивания WAL-журналов;secret_dump_key– значение ключа кодирования ключей для создания дампа с помощью расширения secret_dump. Ключ генерируется автоматически в хранилище секретов при выполнении команды установки расширения (при условии включенного механизма защиты параметровsecure_config = on).
Мастер-ключ
Мастер-ключ устанавливается при первом запуске базы данных (БД). Если новый мастер-ключ не задан, он генерируется автоматически.
Мастер-ключ хранится в хранилище секретов в папке keys.
Ротация (смена) мастер-ключа также может инициироваться и выполняться посредством выполнения функции смены мастер-ключа на узле Active БД, входящем в кластер.
После выполнения ротации мастер-ключа в хранилище секретов добавляется метка предыдущего мастер-ключа, а также новое значение мастер-ключа master_key_value_<timestamp>:
prev_master_key— параметр, содержащий метку предыдущего мастер-ключа.
В случае включенной функциональностизащиты данных от привилегированных пользователей ротация мастер-ключа доступна только администратору безопасности.
Функции для поддержки ротации и изменения мастер-ключей на стороне БД:
block_rotate_master_key()— захватывает блокировку изменения мастер-ключа, служит для исключения ротации мастер-ключа TDE на кластере при работе таких утилит, какpg_rewind;unblock_rotate_master_key()— снимает блокировку изменения мастер-ключа на кластере;set_master_key(new_master_key TEXT)— устанавливает новое значение мастер-ключа;rotate_master_key()— генерирует и устанавливает новое значение мастер-ключа;reencrypt_keys()— перекодирует хранилище ключей актуальным мастер-ключом, опираясь на информацию о предыдущем использованном мастер-ключе;restore_keys()— перекодирует хранилище ключей актуальным мастер-ключом, в том числе поддерживает нахождение мастер-ключа из истории в хранилище секретов, которым был засекречен конкретный ключ объекта. Также используется в восстановлении резервных копий, снятых во время действия предыдущих мастер-ключей;get_last_master_key_rotation_time()– возвращает дату и время установки мастер-ключа.
Подробнее о данных функциях в разделе «Функции для поддержки ротации и изменения ключей кодирования на стороне БД» документа «Справочная информация».
Ключи второго уровня
Ключи второго уровня засекречивают объекты базы данных и не подлежат ротации, что позволяет избежать перекодирования данных при обновлении мастер-ключа.
Ключи второго уровня хранятся на сервере БД в виде файла enc_keys.json, который:
- входит в резервные копии БД;
- также находится в директории
$PGDATA/global, владельцем является пользователь postgres; - содержит ключи засекречивания для табличных пространств и объектов БД;
Пример файла enc_keys.json:
-rw------- 1 postgres postgres 108916 Sep 28 10:59 enc_keys.json
{
"controlBlock" : "{hash}",
"dataBaseId" : 16403,
"encryptionKey" : "{encryptionKey}",
"objectId" : 16774,
"pgObjectType" : "R"
},
{
"controlBlock" : "{hash}",
"dataBaseId" : 0,
"encryptionKey" : "{encryptionKey}",
"objectId" : 17988,
"pgObjectType" : "T"
}
Содержит следующие данные:
controlBlock— контрольный блок, состоящий из метки мастер-ключа,oidбазы данных объекта, типа объекта иoidсамого объекта, засекреченный ключом;dataBaseId—oidбазы данных объекта;encryptionKey— ключ кодирования объекта в засекреченном виде;objectId—oidобъекта, которому назначен соответствующий ключ засекречивания;pgObjectType— тип объекта, которому назначен соответствующий ключ засекречивания, гдеT— табличное пространство,R— отношение.
Ключи второго уровня зашифрованы мастер-ключом. Метки актуального и предыдущего ключа (при наличии) хранятся в виде файла enc_settings.cfg, который:
- входит в резервные копии БД;
- хранится в директории
$PGDATA/global, владельцем является пользовательpostgres; - создан при первом запуске БД;
- указаны метка текущего и предыдущего мастер-ключей засекречивания.
Пример файла enc_settings.cfg:
-rw------- 1 postgres postgres 84 Sep 28 10:59 enc_settings.cfg
active_master_key_id = master_key_value_00000000_000000_000
Ключ засекречивания журнала упреждающей записи
Для возможности оперировать ключами журнала WAL без доступа к хранилищу секретов, ключи wal_key сохраняются не только в хранилище секретов, но и в локальном файле wal_keys.json.
О ротации данного ключа читайте в разделе «Ротация журнального ключа».
Ключ wal_keys.json:
- входит в резервные копии БД;
- находится в директории
$PGDATA/global, владельцем является пользователь postgres; - содержит ключи засекречивания для журналов WAL.
Пример файла wal_keys.json:
-rw------- 1 postgres postgres 108916 Sep 28 10:59 wal_keys.json
[
{
"controlBlock" : "{hash}",
"created" : 812628366806335,
"encryptionKey" : "{encryptionKey}",
"lsn" : "00000000/00000000",
"pgObjectType" : "W"
}
]
Содержит следующие данные:
controlBlock— контрольная сумма в форматеbase64;created—timestampмомента создания ключа;encryptionKey— засекреченный мастер-ключом сам ключ в форматеbase64;lsn— соответствующий LSN;pgObjectType— тип объектаW— WAL.
Мониторинг активации функциональности
Для возможности мониторинга включения прозрачного защитного преобразования данных (TDE) в СУБД Pangolin реализована функция проверки check_tde_is_on.
Проверьте включение засекречивания с помощью команды:
postgres=# SELECT * FROM check_tde_is_on();
check_tde_is_on
-----------------
t
(1 row)
Управление
Первоначальная настройка защитного преобразования для сервера СУБД Pangolin
Процесс первоначальной настройки засекречивания для сервера СУБД Pangolin включает следующие шаги:
- администратор БД останавливает СУБД Pangolin, и выводит сервер из эксплуатации;
- администратор БД настраивает параметр в конфигурационном файле СУБД Pangolin для включения засекречивания;
- сотрудник службы безопасности запускает утилиту
setup_kms_credentials, и создает файл с параметрами подключения к хранилищу секретов; - при необходимости сотрудник службы безопасности устанавливает мастер-ключ в хранилище секретов вручную;
- администратор БД перезапускает СУБД Pangolin и возвращает в эксплуатацию.
Смена мастер-ключа защитного преобразования
Процесс смены мастер-ключа засекречивания проходит следующим образом:
- сотрудник службы безопасности инициирует установку нового мастер-ключа в хранилище секретов. Если новый ключ не указан, он генерируется автоматически.
- новый мастер-ключ устанавливается в хранилище секретов, а предыдущий сохраняется для возможного восстановления данных.
- метка нового мастер-ключа фиксируется в хранилище секретов.
- ключи засекречивания пересчитываются с использованием нового мастер-ключа.
Если в хранилище секретов (KMS) устанавливается новый ключ без использования стандартных процедур управления ключами, возникает необходимость перекодирования существующих ключей.
Это делается путем их декодирования старым ключом и последующего кодирования новым. Данная операция может быть выполнена вручную администратором или автоматически системой.
Восстановление защитного преобразования БД при сбое процесса перекодирования БД
При сбое процесса перекодирования базы данных выполняются следующие шаги для восстановления кодирования:
-
Система или администратор инициируют процедуру восстановления.
-
Текущий и предыдущий мастер-ключи извлекаются из хранилища секретов в определенном порядке:
- по локальной метке текущего мастер-ключа;
- по локальной метке предыдущего мастер-ключа (если есть);
- по метке текущего мастер-ключа в хранилище секретов;
- по метке предыдущего мастер-ключа в хранилище (если имеется).
-
Ключи засекречивания декодируются теми же мастер-ключами в таком же порядке. Если декодирование не удалось, выдается ошибка «Не найден подходящий мастер-ключ».
-
Ключи, засекреченные предыдущим мастером-ключом, перекодируются текущим мастером-ключом. Те, что уже закодированы текущим ключом, остаются неизмененными. Если ключи засекречивания повреждены, системный каталог ключей восстанавливается из резервной копии.
Создание резервной копии БД, содержащей засекреченные данные
Создание резервной копии засекреченной базы данных выполняется следующим образом:
Администратор запускает процедуру резервного копирования:
- если нужна бинарная резервная копия с засекреченными данными, закодированным файлом ключей и меткой актуального мастер-ключа, выполняется выгрузка бинарной копии;
- если нужен SQL-скрипт для заполнения базы данных без засекреченных данных, используется утилита
pg_dumpилиpg_dumpallдля создания соответствующего скрипта.
Восстановление из бинарной резервной копии БД
Процедура восстановления из бинарной резервной копии базы данных включает следующие шаги:
- Администратор БД останавливает СУБД и выводит сервер из эксплуатации.
- Администратор БД очищает каталог с данными БД (
PGDATA). - Администратор БД запускает утилиту восстановления БД из резервной копии. При этом указывается файл резервной копии, содержащий зашифрованные данные, системный каталог с зашифрованными ключами шифрования и метка мастер-ключа, актуального на момент создания резервной копии.
- СУБД Pangolin получает информацию о метке мастер-ключа из резервной копии и запрашивает соответствующие ключи из хранилища секретов.
- Если мастер-ключи отличаются, СУБД Pangolin перекодирует ключи из резервной копии.
- Администратор БД запускает СУБД Pangolin в обычном режиме, и сервер возвращается в эксплуатацию.
Прозрачное защитное преобразование данных и объектов базы данных
Прозрачное защитное преобразование базы данных и ее объектов в СУБД Pangolin происходит следующим образом:
- Администратор БД создает засекреченное табличное пространство для новой базы данных, при этом автоматически создается ключ кодирования.
- Администратор БД затем создает саму засекреченную базу данных, размещенную в одном из созданных табличных пространств. При этом автоматически генерируются ключи кодирования для системного каталога базы данных.
- Администратор БД далее создает объекты базы данных (например, таблицы), указав табличные пространства для их размещения. Для новых объектов автоматически генерируются свои ключи кодирования. Чтобы объекты были закодированы, их следует размещать в специально созданном закодированном табличном пространстве.
- Для создания засекреченных табличных пространств используется команда с опцией
WITH(is_encrypted = on), которая задается только при их создании. Изменять значение этой опции запрещено, поскольку это потребует повторного защитного преобразования или рассекречивания всех данных в данном пространстве.
Ротация журнального ключа
Функциональность доступна только для редакций Enterprise и Enterprise для ERP-систем.
WAL-журнал засекречивается актуальным wal_key. Во время ротации в упреждающий журнал записывается операция о смене wal_key. Начиная со следующей записи, журнал засекречивается новым ключом. При репликации ключ передается через хранилище секретов (KMS), реплика обновляет его и читает засекреченные новым ключом записи журнала. Участники репликации будут использовать один и тот же ключ засекречивания WAL. Ключи wal_key также сохраняются в локальном файле wal_keys.json, чтобы иметь возможность оперировать ключами без доступа к хранилищу секретов.
Во время старта сервер, используя файл wal_keys.json, получит актуальный на момент CHECKPOINT ключ и сможет приступить к чтению упреждающего журнала. Если ключ из файла получить не удалось, будет совершена попытка инициализировать его из хранилища секретов.
Файл wal_keys.json играет ключевую роль для рассекречивания журнала упреждающей записи. В случае порчи или утери данного файла старт базы может завершиться неуспешно. Файл попадает в резервную копию и должен быть включен в число архивируемых файлов СРК.
Описание
Замена локального wal_key производится через журнал с помощью записи о смене ключа. Запись о смене ключа, кроме заголовка, содержит тип postgresql timestamp момента создания ключа. По координатам метки (LSN) и timestamp идентифицируется ключ. Ключ по соответствующему идентификатору хранится в хранилище секретов. Дополнительно ключи хранятся в засекреченном виде в локальном файле wal_keys.json. Это позволяет выполнить старт реплики в условиях недоступности хранилища.
Запрос на смену ключа разрешается выполнить только на мастере. Мастер помещает ключ в хранилище. Реплика, в процессе физической репликации прочитавшая запись о смене ключа, обращается в хранилище секретов за актуальным ключом и продолжает работу.
Схема процесса:

При старте сервер обратится в хранилище секретов, получит все wal_key_* и найдет ближайшую к точке старта смену ключа.
Структура журнала
Структура журнала может представлять собой разветвленное дерево. В моменты восстановления – Point In Time Recovery (PITR) – происходит создание нового timeline, и журнал ответвляется от старой версии. На приведенной ниже схеме PITR указаны вместе с их датой.

Поскольку WAL вычитывается последовательно, достаточно двигаться по нужной ветви журнала, применяя встречающиеся на пути записи о смене ключа.
Хранение ключей
Ключи засекречивания WAL хранятся локально и в хранилище секретов в виде:
wal_key_<%08X_%08X-formatted lsn>_<timestamp> : <ключ в формате base64>
Например:
"wal_key_00000000_03002288_00000807096703934798" : "d2h5IGFyZSB5b3UgaGVyZQ=="
Выбрано %08X_%08X-formatted lsn, вместо классического %08X/%08X, потому что Vault распознает / как директорию и отображает ключи в контринтуитивных папках.
Формат хранения ключей в wal_keys.json
{
"controlBlock" : "...", // Контрольная сумма в формате base64
"created" : 1234, // PostgreSQL timestamp момента создания
"encryptionKey" : "...", // Засекреченный мастер-ключом сам ключ в формате base64
"lsn" : "...", // Соответствующий LSN
"pgObjectType" : "W"
}
Контрольная сумма нужна в целях проверки корректности засекречивания ключа, в частности, правильного выбора мастер-ключа.
Ключи в памяти
Для засекречивания журнала реплики может быть необходимо иметь в памяти одновременно несколько ключей, актуальных на некоторой странице журнала. Для хранения ключей в памяти используется циклический буфер фиксированного размера, достаточного для содержания максимально возможного количества актуальных ключей. Размер можно высчитать по формуле:
BufferSize = UsableBytesInPage / SizeOfKeySwitchRecord + 2
Где:
BufferSize- количество ключей, которое необходимо хранить в разделяемой памяти;UsableBytesInPage- количество байт в странице WAL за вычетом заголовка страницы;SizeOfKeySwitchRecord- размер записи о смене ключа.
Если запись о смене ключа состояла бы лишь из заголовка, потребовалось бы 8160 / 32 + 2 = 257 мест в буфере. Каждая запись в буфере состоит из ключа и LSN, что составляет до 36 Байт. Соответственно, потребуется зарезервировать не более 9 Кбайт в разделяемой области памяти.
Работа утилит при недоступности хранилища секретов
Чтобы прочитать засекреченные WAL-файлы, утилитам необходим доступ к файлу $PGDATA/global/wal_keys.json. В файле хранятся засекреченные на мастер-ключ ключи засекречивания WAL. В случае недоступности хранилища секретов мастер-ключ можно получить из кеша. Для утилит кеш будет включен всегда с целью иметь возможность работать без доступа к хранилищу.
Ограничения
- Участники репликации используют общий
wal_key. - Хранилище секретов должно быть доступно во время первичной инициализации ключа
wal_key. - Реплики используют общий сервис хранилища секретов (KMS). Если KMS не доступен, функциональность замены ключа не работает.
- При использовании KMS-заменителя функциональность ротации
wal_keyне доступна, в связи с тем, что для KMS-заменителя не реализована возможность изменять и добавлять секреты. - Запрос о смене ключа можно выполнить только на мастере.
- После замены ключа выполнить откат на более старую версию будет невозможно.
Настройка
Выбор ключа засекречивания WAL
При старте для работы с журналом подбирается ключ, актуальный на момент контрольной точки, с которого начинает свою работу база. Ближайшая оставленная до контрольной точки (с наибольшим LSN, меньшим контрольной точки) метка о смене ключа соответствует актуальному ключу.
Сначала описанный принцип применяется к файлу wal_keys.json, в неуспешном случае к ключам, хранимым в KMS. В случае успешного получения ключей из KMS, они будут сохранены в wal_keys.json.
Если из обоих источников ключ получить не удалось, будет сгенерирован новый ключ с названием wal_key, на который будут засекречены все имеющиеся WAL-файлы. Только одна из реплик преуспеет в том, чтобы положить данный ключ в KMS. Остальные реплики получат его из KMS. Каждая из реплик укажет свое системное время в качестве момента создания данного ключа, сохраняемого вместе с ключом в файл wal_keys.json. Для остальных ключей момент создания будет общим, потому что он передается через журнал WAL.
Время последней ротации ключа
Время последней смены ключа будет получено из файла wal_keys.json, для каждого ключа в нем в виде 64-битного целого числа формата timestamp – хранится время создания. Момент последней замены ключа можно получить функцией get_last_wal_key_rotation_time. Если файл с ключами поврежден, выведутся соответствующие WARNING в лог, и вызов функции завершится с ошибкой.
Время создания (timestamp) в файле wal_keys.json и в хранилище секретов указаны в числовом формате. Для анализа и разбора ситуаций может быть полезным определить момент времени, закодированный данным числом. Один из возможных способов – перевести число в UNIX timestamp и воспользоваться любым презентатором. Например, встроенным в Pangolin:
SELECT to_timestamp(807096702690391 / 1000000 + 946684800);
to_timestamp
------------------------
2025-07-29 12:31:42+03
(1 row)
Перевод осуществляется по формуле:
UNIX_TIMESTAMP = POSTGRESQL_TIMESTAMP / MICROSECONDS_IN_SECOND + SECONDS_BETWEEN_1970_01_01_AND_2000_01_01 = POSTGRESQL_TIMESTAMP / 1000000 + 946684800
Ограничение частоты замен ключа
Между последовательными заменами ключа засекречивания WAL должно пройти не менее wal_key_reset_timeout секунд. Параметр внесен под защиту конфигурирования. Ограничение можно снять, присвоив параметру значение 0.
Время жизни ключа
Время жизни ключа задается целочисленным параметром wal_key_lifetime, значение которого указывается в секундах. По умолчанию установлено значение 360d, что соответствует 360 дням. По окончании указанного срока действия ключа в системный лог будут записываться сообщения уровня WARNING о его истечении.
Во избежание чрезмерно частого информирования о просроченном ключе добавлен параметр wal_key_check_delay. Это промежуток времени между последовательными проверками актуальности ключа. Единица измерения – секунды. Проверку актуальности можно запустить дополнительно послав сигнал SIGHUP процессу MKeyChecker (это можно сделать с помощью, например, pg_ctl reload. В этом случае также выполнится проверка на соответствие локального и удаленного (на KMS) мастер ключей и, при необходимости, перезасекречивание всех локальных ключей, в том числе в файле wal_keys.json). Если параметру wal_key_check_delay присвоено значение -1, то проверки актуальности ключа осуществляться не будут даже при получении сигнала.
Откат на более старую версию
Версии, не содержащие данную функциональность, хранят ключ засекречивания WAL вместе с остальными ключами засекречивания объектов в файле $PGDATA/global/enc_keys.json. После первого старта базы ключ будет перемещен в файл wal_keys.json. В случае отката ключ засекречивания WAL необходимо восстановить в прежнем файле enc_keys.json. Для этого необходимо сохранить перед обновлением enc_keys.json. После отката переместить из него wal_key.
Старые версии продукта не смогут работать с журналом WAL, если на нем были совершены замены ключа засекречивания. Журнал станет нечитаемым старой версией продукта сразу после первой ротации ключа.
Ротация ключа засекречивания WAL должна осуществляться только в случае уверенности в том, что обновление прошло успешно.
Функции
-
rotate_wal_key() → boolean- отротировать ключ; -
set_wal_key(new_wal_key TEXT) → boolean- заменить ключ на предложенный, закодированный в формате base64;примечаниеКлюч будет обрезан или дополнен нулями, чтобы иметь длину ровно 32 байта.
-
get_last_wal_key_rotation_time() → postgres timestamp- получить момент последней смены WAL-ключа.
Первые две функции возвращают true в случае успешной замены ключа и помещаются под защиту.
Логическая репликация при прозрачном защитном преобразовании данных (TDE)
Логическая репликация между серверами Pangolin осуществляется посредством прозрачного защитного преобразования данных. Участники репликации применяют ключи wal_key не только для преобразования записей журнала WAL, но и в качестве транспортного ключа.
Если серверы используют различные хранилища секретов, потребуется дополнительная настройка, чтобы участники репликации использовали общий ключ. Применение одного и того же wal_key создает уязвимую область системы.
Для возможности логической репликации между узлами Pangolin с разными ключами засекречивания журналов wal_key добавляется параметр конфигурации logical_replication_policy, регулирующий метод защиты сообщений, отправляемых по каналу связи. Этот параметр будет использоваться только при включенном TDE и управляться через KMS. Параметр принимает следующие значения:
DISABLED— запрещает логическую репликацию. Это значение по умолчанию.USE_TLS— предписывает удостовериться, что установлено TLS-соединение, после чего сообщения передаются без дополнительного преобразования. При этом значении проверка наличия TLS-соединения будет осуществляться один раз — при попытке установить соединение для логической репликации. Если соединение не соответствует требованиям TLSv1.3, репликация завершится с ошибкой.

- логическая репликация с TDE-сервера отключена по умолчанию;
- стороны должны установить TLS-соединение версии 1.3;
- при использовании настройки
USE_TLSзапрещена репликация через посредников, так как с их стороны отсутствует гарантия TDE; - запрещена репликация на сторонние сервисы, так как с их стороны отсутствует гарантия TDE.
Параметр logical_replication_policy управляет логической репликацией только при включенном TDE на публикующем сервере.
При возникновении ситуации, когда логическая репликация попадает в продолжительный цикл обработки большой транзакции, завершить его работу через стандартные команды (terminate) становится невозможным. Завершение процесса может занимать длительное время (до 8 часов), даже после изменения соответствующих параметров. Администраторы баз данных должны учитывать эти особенности и принимать меры по временному прекращению логической репликации в случае возникновения значительных задержек или постоянных перезапусков подписки.
При выполнении обновления убедитесь, что предварительно настроен параметр logical_replication_policy, иначе существующие логические репликации могут быть прерваны.
Сценарии репликации, доступные после добавления параметра конфигурации logical_replication_policy:
- Репликация через TLS.
- Репликация запрещена.
Настройка логической репликации
Для реализации двух вариантов конфигурации сервера-подписчика и публикующего сервера (Publisher с поддержкой TDE, Subscriber с поддержкой TDE / Publisher с поддержкой TDE, Subscriber без поддержки TDE), предложена следующая схема:

Шаги по настройке логической репликации:
-
Настройте TLS-соединение между публикующим сервером и сервером-подписчиком (администратор СУБД):
-
В конфигурационном файле публикующего сервера
pg_hba.confдобавьте подписчиков, указав тип соединенияhostssl. -
Включите ssl на серверах:
ALTER SYSTEM SET ssl TO on;
SELECT pg_reload_conf();
SHOW ssl; -
Если репликация уже настроена, удостоверьтесь, что используются ssl-соединения:
SELECT pg_stat_ssl.pid, datname, usename, ssl, client_addr
FROM pg_stat_ssl
JOIN pg_stat_activity
ON pg_stat_ssl.pid = pg_stat_activity.pid; -
При необходимости выключите процесс с небезопасным соединением, чтобы произошло переподключение:
SELECT pg_stpg_terminate_backend(<pid>);
-
-
Через веб-интерфейс хранилища секретов установите в KMS значение
logical_replication_policyравнымUSE_TLS(администратор безопасности). -
Удостоверитесь, что параметр
logical_replication_policyзадан верно. Для этого необходимо перезагрузить базу данных (администратор СУБД):pg_ctl reloadSHOW logical_replication_policy; -
Настройте логическую репликацию как требуется в PostgreSQL (администратор СУБД):
-
На публикующем сервере создайте роль для подписчика с атрибутами
LOGINиREPLICATIONи с правами на чтение необходимых таблиц:CREATE ROLE subscriber REPLICATION LOGIN;
GRANT SELECT ON TABLE <replication_table> TO subscriber;
GRANT USAGE ON SCHEMA <table_schema> TO subscriber; -
На публикующем сервере создайте публикацию реплицируемых таблиц:
CREATE PUBLICATION <publication_name>
FOR TABLE <replication_table>; -
На публикующем сервере удостоверьтесь, что
wal_levelимеет значениеlogical. При необходимости измените значение параметра и перезагрузите СУБД:SHOW wal_level; -
На сервере-подписчике создайте соответствующие таблицы с такими же схемами.
-
На сервере-подписчике создайте подписку на ожидаемые таблицы, в строке подключения укажите созданного в пункте 4.a пользователя:
CREATE SUBSCRIPTION <subscription_name>
CONNECTION 'user=subscriber host=<host> port=<port> dbname=<dbname>'
PUBLICATION <publication_name>;
-
Отмена логической репликации
Для отмены логической репликации, необходимо удалить подписку и публикацию с помощью стандартного протокола PostgreSQL. При необходимости, запретить логическую репликацию, установив параметр logical_replication_policy равным DISABLED.
Если сначала изменить logical_replication_policy на DISABLED, то удаление существующих подписок может сопровождаться сложностями. Процессы, ответственные за поддержание установленных связей для репликации, завершат свою работу с ошибкой. Попытки восстановить соединения завершатся неудачно. В полученной конфигурации администраторы СУБД могут удалить подписки и публикации самостоятельно. Ситуация аналогична разрыву сети между подписчиком и публикующем сервером, соответственно, действия будут такими же: на публикующем сервере достаточно удалить публикацию, на подписчике — выключить подписку, удалить из нее слот репликации, после чего сбросить саму подписку.

Шаги по отмене логической репликации:
-
Через веб-интерфейс хранилища секретов установите в хранилище секретов значение
logical_replication_policyравнымDISABLED(администратор безопасности). -
Перечитайте конфигурацию сервера, например (администратор СУБД публикующего сервера):
pg_ctl reload -
Удалите публикацию (администратор СУБД публикующего сервера):
DROP PUBLICATION <publication_name>; -
Удалите подписку (администратор СУБД сервера-подписчика):
-
Когда на публикующем сервере установлен параметр
logical_replication_policyравнымDISABLED, все соединения, созданные для логической репликации, будут отклоняться. Подписчик при попытке удалить подписку столкнется с ошибкой:DROP SUBSCRIPTION <subscription_name>;
FATAL: Logical replication from the server with enabled TDE is prohibited by the logical_replication_policy option: DISABLED.
HINT: Use ALTER SUBSCRIPTION ... DISABLE to disable the subscription, and then use ALTER SUBSCRIPTION ... SET (slot_name = NONE) to disassociate it from the slot. -
Воспользуйтесь подсказкой:
ALTER SUBSCRIPTION <subscription_name> DISABLE;
ALTER SUBSCRIPTION <subscription_name> SET ( slot_name = NONE );
DROP SUBSCRIPTION <subscription_name>;
-
Сценарии использования
Пример защитного преобразования объектов БД
-
Создайте директорию для засекреченного табличного пространства
/pgdata/0{major_version}/tablespaces/tde_onи директорию для незасекреченного пространства/pgdata/0{major_version}/tablespaces/tde_off(на всех узлах):$ mkdir /pgdata/0{major_version}/tablespaces/tde_on
$ mkdir /pgdata/0{major_version}/tablespaces/tde_off -
Создайте засекреченное и незасекреченное табличные пространства:
CREATE TABLESPACE tde_on LOCATION '/pgdata/0{major_version}/tablespaces/tde_on' WITH (is_encrypted = on);
CREATE TABLESPACE tde_off LOCATION '/pgdata/0{major_version}/tablespaces/tde_off'; -
Проверьте созданные табличные пространства:
SELECT * FROM pg_tablespace;oid | spcname | spcowner | spcacl | spcoptions
------+------------+----------+-------------------------------------------+-------------------
1663 | pg_default | 10 | |
1664 | pg_global | 10 | |
16400 | Tbl_t | 16387 | {db_admin=C/db_admin,as_admin=C/db_admin} |
17823 | tde_on | 10 | | {is_encrypted=on}
17824 | tde_off | 10 | |
(5 rows)В директории
/pgdata/0{major_version}/tablespacesdrwx------ 3 postgres postgres 4096 Oct 6 04:53 Tbl_t
drwx------ 3 postgres postgres 4096 Oct 6 08:51 tde_off
drwx------ 3 postgres postgres 4096 Oct 6 08:50 tde_on -
Создайте таблицы в засекреченном и незасекреченном табличных пространствах, добавьте в них данные:
CREATE TABLE table_tde_on (id int, a text) TABLESPACE tde_on;
INSERT INTO table_tde_on VALUES (1, 'Matrena');
CREATE TABLE table_tde_off (id int, a text) TABLESPACE tde_off;
INSERT INTO table_tde_off VALUES (1, 'Fedora'); -
Выполните контрольную точку:
CHECKPOINT; -
Выполните поиск ранее добавленных записей в таблицы по файлам данных в директориях БД
/pgdata/0{major_version}/data/base,/pgdata/0{major_version}/data/pg_wal,/pgdata/0{major_version}/tablespaces:cd /pgdata/0{major_version}
$ grep -R 'Matrena' /pgdata/0{major_version}/data/base
$ grep -R 'Matrena' /pgdata/0{major_version}/data/pg_wal
$ grep -R 'Matrena' /pgdata/0{major_version}/tablespaces
$ grep -R 'Fedora' /pgdata/0{major_version}/data/base
$ grep -R 'Fedora' /pgdata/0{major_version}/data/pg_wal
$ grep -R 'Fedora' /pgdata/0{major_version}/tablespaces
Binary file /pgdata/0{major_version}/tablespaces/tde_off/PG_13_20220{major_version}301/13604/17892 matchesФайлы данных засекречены: засекреченные данные в открытом виде не обнаружены ни на Active, ни на Standby узлах. Обнаружены только данные, созданные в незасекреченной таблице.
-
Выполните просмотр файла с ключами
$PGDATA/global/enc_keys.json:$ cat $PGDATA/global/enc_keys.json[
{
"controlBlock" : "{hash}",
"dataBaseId" : 13604,
"encryptionKey" : "{encryptionKey}",
"objectId" : 17889,
"pgObjectType" : "R"
},
{
"controlBlock" : "{hash}",
"dataBaseId" : 13604,
"encryptionKey" : "{encryptionKey}",
"objectId" : 17886,
"pgObjectType" : "R"
},
{
"controlBlock" : "{hash}",
"dataBaseId" : 13604,
"encryptionKey" : "{encryptionKey}",
"objectId" : 17891,
"pgObjectType" : "R"
},
{
"controlBlock" : "{hash}",
"dataBaseId" : 0,
"encryptionKey" : "{encryptionKey}",
"objectId" : 17884,
"pgObjectType" : "T"
},
// ...
]В файле отражены засекреченные объекты:
- с типом объекта
R(отношение): таблицаtable_tde_on (objectId=17886), toast-таблицаpg_toast_17886 (objectId=17889), индекс к нейpg_toast_17886_index (objectId=17891):
SELECT oid,relname FROM pg_class WHERE oid in ('17889','17886','17891');oid | relname
-------+----------------------
17889 | pg_toast_17886
17891 | pg_toast_17886_index
17886 | table_tde_on
(3 rows)- с типом объекта
T(табличное пространство): созданное табличное пространствоtde_on:
SELECT * FROM pg_tablespace WHERE oid='17884';oid | spcname | spcowner | spcacl | spcoptions
-------+---------+----------+-------------------------------------------+-------------------
17884 | tde_on | 10 | {postgres=C/postgres,as_admin=C/postgres} | {is_encrypted=on}
(1 row) - с типом объекта