Задание 1: Прозрачное защитное преобразование данных (TDE)
Прозрачное защитное преобразование данных (Transparent Data Encryption, TDE) — это технология, предназначенная для защиты данных на уровне файловой системы. Данные преобразуются перед записью на диск и декодируются при чтении в память. TDE позволяет защитить данные от несанкционированного доступа со стороны системных администраторов и других лиц, имеющих доступ к файловой системе. Более подробно с TDE можно ознакомиться в документации.
TDE интегрируется с системой управления ключами (Key Management System, KMS) HashiCorp Vault, которая отвечает за хранение секретов, таких как ключи API и пароли.
Для включения механизма в конфигурационном файле /etc/pangolin-security-utilities/kms_dynamic_params.cfg параметр is_tde_on устанавливается в значение on.
Для возможности мониторинга включения прозрачного защитного преобразования данных (TDE) в СУБД Pangolin реализована функция проверки check_tde_is_on:
postgres@postgres=# SELECT * FROM check_tde_is_on();
┌─────────────────┐
│ check_tde_is_on │
├─────────────────┤
│ t │
└─────────────────┘
(1 row)
При работе с СУБД Pangolin секретность данных обеспечивается защитой:
- настроечных параметров и конфигураций;
- доступа к пользовательским данных в объектах БД.
В этом задании рассмотрим защитное преобразование данных.
Упражнение 1: Включение механизма
-
Остановите сервер Pangolin:
[UserName@ServerName ~]$ sudo systemctl stop postgresql[UserName@ServerName ~]$ sudo systemctl status postgresql○ postgresql.service - Runners PostgreSQL serviceLoaded: loaded (/etc/systemd/system/postgresql.service; enabled; preset: disabled)Active: inactive (dead) since Tue 2025-04-01 23:04:12 MSK; 4min 53s agoDuration: 44min 9.014sProcess: 969 ExecStartPre=/bin/mkdir -p /var/run/postgresql (code=exited, status=0/SUCCESS)Process: 970 ExecStartPre=/bin/chown -R postgres:postgres /var/run/postgresql (code=exited, status=0/SUCCESS)Process: 971 ExecStart=/bin/bash -i -c /usr/pangolin-6/bin/postgres -D /pgdata/06/data (code=exited, status=0/SUCCESS)Main PID: 971 (code=exited, status=0/SUCCESS)CPU: 4.189sApr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.319 MSK [971] LOG: License CPUs number allowed: unrestrictedApr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.319 MSK [971] LOG: License allowed memory in bytes: unrestrictedApr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.366 MSK [971] LOG: configuration file "/pgdata/06/data/pg_quota.conf" contains no entriesApr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.454 MSK [971] LOG: redirecting log output to logging collector processApr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.454 MSK [971] HINT: Future log output will appear in directory "/pgerrorlogs/06".Apr 01 22:20:03 ServerName systemd[1]: Started postgresql.service - Runners PostgreSQL service.Apr 01 23:04:12 ServerName systemd[1]: Stopping postgresql.service - Runners PostgreSQL service...Apr 01 23:04:12 ServerName systemd[1]: postgresql.service: Deactivated successfully.Apr 01 23:04:12 ServerName systemd[1]: Stopped postgresql.service - Runners PostgreSQL service.Apr 01 23:04:12 ServerName systemd[1]: postgresql.service: Consumed 4.189s CPU time. -
Так как по итогу предыдущего задания мы настроили KMS, то конфигурационные параметры нужно менять именно там. Установите динамический параметр
is_tde_on = on:[kmadmin_pg@ServerName ~]$ vi /etc/pangolin-security-utilities/kms_dynamic_params.cfgsecure_config = onis_tde_on = onssl = onssl_cert_file = /pg_ssl/server.crtssl_key_file = /pg_ssl/server.keyssl_ca_file = /pg_ssl/root.crtpassword_policies_enable = onpsql_encrypt_password = onpassword_encryption = scram-sha-256enabled_sec_admin_extra_auth_methods = certenabled_extra_auth_methods = cert,trust -
Запустите сервер Pangolin:
[UserName@ServerName ~]$ sudo systemctl start postgresql[UserName@ServerName ~]$ sudo systemctl status postgresql● postgresql.service - Runners PostgreSQL serviceLoaded: loaded (/etc/systemd/system/postgresql.service; enabled; preset: disabled)Active: active (running) since Tue 2025-04-01 23:16:08 MSK; 7min agoProcess: 1751 ExecStartPre=/bin/mkdir -p /var/run/postgresql (code=exited, status=0/SUCCESS)Process: 1752 ExecStartPre=/bin/chown -R postgres:postgres /var/run/postgresql (code=exited, status=0/SUCCESS)Main PID: 1753 (postgres)Tasks: 13 (limit: 9499)Memory: 55.3MCPU: 1.275sCGroup: /system.slice/postgresql.service├─1753 /usr/pangolin-6/bin/postgres -D /pgdata/06/data├─1770 "postgres: logger "├─1771 "postgres: checkpointer "├─1772 "postgres: background writer "├─1774 "postgres: idle sessions terminator "├─1775 "postgres: walwriter "├─1776 "postgres: autovacuum launcher "├─1777 "postgres: autounite launcher "├─1778 "postgres: integrity check launcher "├─1779 "postgres: license checker "├─1780 "postgres: password policy cache "├─1781 "postgres: mkeychecker "└─1782 "postgres: logical replication launcher "...
Упражнение 2: Проверка защитного преобразования данных
Ключи защитного преобразования организованы в двухуровневую иерархию:
- мастер-ключ регулярно изменяется и используется для защиты ключей второго уровня;
- ключи второго уровня защищают объекты базы данных и не подлежат ротации, что позволяет избежать перекодирования данных при обновлении мастер-ключа.
При первом старте сервера БД после включения прозрачного преобразования данных ключи будут созданы в директории $PGDATA/global:
- файл
$PGDATA/global/enc_settings.cfgс меткой актуального мастер-ключа; - файл
$PGDATA/global/enc_keys.jsonс ключами защитного преобразования табличных пространств, отношений и журналов WAL.
[postgres@ServerName ~]$ cd $PGDATA/global/
[postgres@ServerName global]$ ls -la $PGDATA/global/ | grep .cfg
-rw-------. 1 postgres postgres 60 Apr 1 23:16 enc_settings.cfg
[postgres@ServerName global]$ ls -la $PGDATA/global/ | grep .json
-rw-------. 1 postgres postgres 244 Apr 1 23:16 enc_keys.json
-rw------- 1 postgres postgres 3 Apr 1 23:16 enc_keys.json.bak
-rw------- 1 postgres postgres 382 Apr 1 23:16 wal_keys.json
Теперь можно проверить включение механизма защитного преобразования данных:
[postgres@ServerName global]$ psql
Pager is used for long output.
Border style is 2.
Line style is unicode.
psql (15.5)
SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)
Type "help" for help.
postgres@postgres=# SELECT * FROM check_tde_is_on();
┌─────────────────┐
│ check_tde_is_on │
├─────────────────┤
│ t │
└─────────────────┘
(1 row)
Упражнение 3: Создание защищенного табличного пространства
-
Создайте две директории для табличных пространств:
/pgdata/06/tablespaces/tde_on/pgdata/06/tablespaces/tde_off
[UserName@ServerName ~]$ sudo mkdir -p /pgdata/06/tablespaces/tde_on[UserName@ServerName ~]$ sudo mkdir -p /pgdata/06/tablespaces/tde_off[UserName@ServerName ~]$ sudo ls -la /pgdata/06/total 16drwxr-xr-x. 4 postgres postgres 4096 Apr 2 13:03 .drwxr-xr-x. 3 root root 4096 Mar 27 13:32 ..drwx------. 24 postgres postgres 4096 Apr 2 13:00 datadrwxr-xr-x. 4 root root 4096 Apr 2 13:04 tablespaces[UserName@ServerName ~]$ sudo chown postgres:postgres /pgdata/06/tablespaces/[UserName@ServerName ~]$ sudo ls -la /pgdata/06/tablespaces/total 16drwxr-xr-x. 4 postgres postgres 4096 Apr 2 13:04 .drwxr-xr-x. 4 postgres postgres 4096 Apr 2 13:03 ..drwxr-xr-x. 2 root root 4096 Apr 2 13:04 tde_offdrwxr-xr-x. 2 root root 4096 Apr 2 13:03 tde_on[UserName@ServerName ~]$ sudo chown postgres:postgres /pgdata/06/tablespaces/tde_off[UserName@ServerName ~]$ sudo chown postgres:postgres /pgdata/06/tablespaces/tde_on -
Создайте защищенное и незащищенное табличные пространства в созданных директориях:
[postgres@ServerName ~]$ psqlPager is used for long output.Border style is 2.Line style is unicode.psql (15.5)SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)Type "help" for help.postgres@postgres=# CREATE TABLESPACE tde_on LOCATION '/pgdata/06/tablespaces/tde_on' WITH (is_encrypted = on);CREATE TABLESPACEpostgres@postgres=# CREATE TABLESPACE tde_off LOCATION '/pgdata/06/tablespaces/tde_off';CREATE TABLESPACEpostgres@postgres=# SELECT * FROM pg_tablespace;┌───────┬────────────┬──────────┬────────┬───────────────────┐│ oid │ spcname │ spcowner │ spcacl │ spcoptions │├───────┼────────────┼──────────┼────────┼───────────────────┤│ 1663 │ pg_default │ 10 │ │ ││ 1664 │ pg_global │ 10 │ │ ││ 16411 │ tde_on │ 10 │ │ {is_encrypted=on} ││ 16412 │ tde_off │ 10 │ │ │└───────┴────────────┴──────────┴────────┴───────────────────┘(4 rows) -
Выдайте пользователю
dbadminпривилегии для работы с этими табличными пространствами:postgres@postgres=# GRANT ALL PRIVILEGES ON TABLESPACE tde_on TO dbadmin;GRANTpostgres@postgres=# GRANT ALL PRIVILEGES ON TABLESPACE tde_off TO dbadmin;GRANTpostgres@postgres=# GRANT ALL ON SCHEMA public TO dbadmin;GRANT -
Внесите изменения в конфигурационный файл
$PGDATA/pg_hba.conf. Для применения значений в этом файле необходимо перезагрузить сервер:[postgres@ServerName ~]$ vi $PGDATA/pg_hba.conf# TYPE DATABASE USER ADDRESS METHOD# "local" is for Unix domain socket connections only#local all all scram-sha-256# IPv4 local connections:hostssl all postgres 127.0.0.1/32 certhost all all 127.0.0.1/32 scram-sha-256 <----- для подключения пользователя dbadminhostssl all postgres <IP-Address>/32 certhost all all <IP-Address>/32 scram-sha-256 <----- для подключения пользователя dbadmin# IPv6 local connections:#host all all ::1/128 scram-sha-256# Allow replication connections from localhost, by a user with the# replication privilege.#local replication all scram-sha-256host replication all 127.0.0.1/32 scram-sha-256host replication all ::1/128 scram-sha-256ПримечаниеПоменяйте
<IP-Address>на значение IP-адреса вашей виртуальной машины.[UserName@ServerName ~]$ sudo systemctl restart postgresql -
Подключитесь к базе
postgresпользователемdbadmin:[postgres@ServerName ~]$ psql -U dbadmin -d postgres -h 127.0.0.1Password for user dbadmin:Pager is used for long output.Border style is 2.Line style is unicode.psql (15.5)SSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)Type "help" for help. -
Создайте таблицы в защищенном и незащищенном табличных пространствах, добавьте в них данные:
dbadmin@postgres=# CREATE TABLE table_tde_on (id int, a text) TABLESPACE tde_on;CREATE TABLEdbadmin@postgres=# INSERT INTO table_tde_on VALUES (1, 'студент');INSERT 0 1dbadmin@postgres=# CREATE TABLE table_tde_off (id int, a text) TABLESPACE tde_off;CREATE TABLEdbadmin@postgres=# INSERT INTO table_tde_off VALUES (1, 'Света');INSERT 0 1dbadmin@postgres=# TABLE table_tde_on;┌────┬─────────┐│ id │ a │├────┼─────────┤│ 1 │ студент │└────┴─────────┘(1 row)dbadmin@postgres=# TABLE table_tde_off;┌────┬───────┐│ id │ a │├────┼───────┤│ 1 │ Света │└────┴───────┘(1 row) -
Выполните контрольную точку:
dbadmin@postgres=# \c postgres postgresSSL connection (protocol: TLSv1.3, cipher: TLS_AES_256_GCM_SHA384, compression: off)You are now connected to database "postgres" as user "postgres".postgres@postgres=# CHECKPOINT;CHECKPOINT -
Выполните поиск ранее добавленных записей в таблицы по файлам данных в директориях БД
/pgdata/06/data/base,/pgdata/06/data/pg_wal,/pgdata/06/tablespaces:[postgres@ServerName ~]$ grep -R 'студент' /pgdata/06/data/base /pgdata/06/data/pg_wal /pgdata/06/tablespaces[postgres@ServerName ~]$ grep -R 'Света' /pgdata/06/data/base /pgdata/06/data/pg_wal /pgdata/06/tablespacesgrep: /pgdata/06/tablespaces/tde_off/PG_15_202409231/5/16429: binary file matches # <----- Обнаружены только данные, созданные в незакодированной таблице. -
Откройте файл с ключами
$PGDATA/global/enc_keys.json. В файле отражены закодированные объекты:[postgres@ServerName ~]$ cat $PGDATA/global/enc_keys.json[{"controlBlock" : "{хеш-1}","dataBaseId" : 0,"encryptionKey" : "{ключ-1}","objectId" : {oid1},"pgObjectType" : "T"},{"controlBlock" : "{хеш-2}","dataBaseId" : 5,"encryptionKey" : "{ключ-2}","objectId" : {oid2},"pgObjectType" : "R"},{"controlBlock" : "{хеш-3}","dataBaseId" : 5,"encryptionKey" : "{ключ-3}","objectId" : {oid3},"pgObjectType" : "R"},{"controlBlock" : "{хеш-4}","dataBaseId" : 5,"encryptionKey" : "{ключ-4}","objectId" : {oid4},"pgObjectType" : "R"}]Где:
controlBlock— контрольный блок, состоящий из метки мастер-ключа,oidбазы данных объекта, типа объекта иoidсамого объекта, засекреченный ключом;dataBaseId—oidбазы данных объекта;encryptionKey— ключ кодирования объекта в засекреченном виде;objectId—oidобъекта, которому назначен соответствующий ключ засекречивания;pgObjectType— тип объекта, которому назначен соответствующий ключ засекречивания, гдеT— табличное пространство,R— отношение.
Посмотрите что это за объекты:
[postgres@ServerName ~]$ psql -c "SELECT oid,relname FROM pg_class WHERE oid in ('{oid1}','{oid2}','{oid3}','{oid4}');"СведенияЗначения
{oid1},{oid2},{oid3},{oid4}необходимо внести вручную из файлаenc_keys.json.Pager is used for long output.Border style is 2.Line style is unicode.┌───────┬──────────────────────┐│ oid │ relname │├───────┼──────────────────────┤│ <oid> │ table_tde_on ││ <oid> │ pg_toast_<oid> ││ <oid> │ pg_toast_<oid>_index │└───────┴──────────────────────┘(3 rows)[postgres@ServerName ~]$ psql -c "SELECT oid, spcname FROM pg_tablespace where oid=<oid, которого не было в прошлой таблице>;"Pager is used for long output.Border style is 2.Line style is unicode.┌───────┬─────────┐│ oid │ spcname │├───────┼─────────┤│ <oid> │ tde_on │└───────┴─────────┘(1 row)