Перейти к основному содержимому

Задание 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: Включение механизма​

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

    [UserName@ServerName ~]$ sudo systemctl stop postgresql
    [UserName@ServerName ~]$ sudo systemctl status postgresql
    ○ postgresql.service - Runners PostgreSQL service
    Loaded: loaded (/etc/systemd/system/postgresql.service; enabled; preset: disabled)
    Active: inactive (dead) since Tue 2025-04-01 23:04:12 MSK; 4min 53s ago
    Duration: 44min 9.014s
    Process: 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.189s

    Apr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.319 MSK [971] LOG: License CPUs number allowed: unrestricted
    Apr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.319 MSK [971] LOG: License allowed memory in bytes: unrestricted
    Apr 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 entries
    Apr 01 22:20:03 ServerName bash[971]: 2025-04-01 22:20:03.454 MSK [971] LOG: redirecting log output to logging collector process
    Apr 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.
  2. Так как по итогу предыдущего задания мы настроили KMS, то конфигурационные параметры нужно менять именно там. Установите динамический параметр is_tde_on = on:

    [kmadmin_pg@ServerName ~]$ vi /etc/pangolin-security-utilities/kms_dynamic_params.cfg
    secure_config = on
    is_tde_on = on
    ssl = on
    ssl_cert_file = /pg_ssl/server.crt
    ssl_key_file = /pg_ssl/server.key
    ssl_ca_file = /pg_ssl/root.crt
    password_policies_enable = on
    psql_encrypt_password = on
    password_encryption = scram-sha-256
    enabled_sec_admin_extra_auth_methods = cert
    enabled_extra_auth_methods = cert,trust
  3. Запустите сервер Pangolin:

    [UserName@ServerName ~]$ sudo systemctl start postgresql
    [UserName@ServerName ~]$ sudo systemctl status postgresql
    ● postgresql.service - Runners PostgreSQL service
    Loaded: loaded (/etc/systemd/system/postgresql.service; enabled; preset: disabled)
    Active: active (running) since Tue 2025-04-01 23:16:08 MSK; 7min ago
    Process: 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.3M
    CPU: 1.275s
    CGroup: /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: Создание защищенного табличного пространства​

  1. Создайте две директории для табличных пространств:

    • /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 16
    drwxr-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 data
    drwxr-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 16
    drwxr-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_off
    drwxr-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
  2. Создайте защищенное и незащищенное табличные пространства в созданных директориях:

    [postgres@ServerName ~]$ 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=# CREATE TABLESPACE tde_on LOCATION '/pgdata/06/tablespaces/tde_on' WITH (is_encrypted = on);
    CREATE TABLESPACE
    postgres@postgres=# CREATE TABLESPACE tde_off LOCATION '/pgdata/06/tablespaces/tde_off';
    CREATE TABLESPACE
    postgres@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)
  3. Выдайте пользователю dbadmin привилегии для работы с этими табличными пространствами:

    postgres@postgres=# GRANT ALL PRIVILEGES ON TABLESPACE tde_on TO dbadmin;
    GRANT
    postgres@postgres=# GRANT ALL PRIVILEGES ON TABLESPACE tde_off TO dbadmin;
    GRANT
    postgres@postgres=# GRANT ALL ON SCHEMA public TO dbadmin;
    GRANT
  4. Внесите изменения в конфигурационный файл $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 cert
    host all all 127.0.0.1/32 scram-sha-256 <----- для подключения пользователя dbadmin
    hostssl all postgres <IP-Address>/32 cert
    host 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-256
    host replication all 127.0.0.1/32 scram-sha-256
    host replication all ::1/128 scram-sha-256
    Примечание

    Поменяйте <IP-Address> на значение IP-адреса вашей виртуальной машины.

    [UserName@ServerName ~]$ sudo systemctl restart postgresql
  5. Подключитесь к базе postgres пользователем dbadmin:

    [postgres@ServerName ~]$ psql -U dbadmin -d postgres -h 127.0.0.1
    Password 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.
  6. Создайте таблицы в защищенном и незащищенном табличных пространствах, добавьте в них данные:

    dbadmin@postgres=# CREATE TABLE table_tde_on (id int, a text) TABLESPACE tde_on;
    CREATE TABLE
    dbadmin@postgres=# INSERT INTO table_tde_on VALUES (1, 'студент');
    INSERT 0 1
    dbadmin@postgres=# CREATE TABLE table_tde_off (id int, a text) TABLESPACE tde_off;
    CREATE TABLE
    dbadmin@postgres=# INSERT INTO table_tde_off VALUES (1, 'Света');
    INSERT 0 1
    dbadmin@postgres=# TABLE table_tde_on;
    ┌────┬─────────┐
    │ id │ a │
    ├────┼─────────┤
    │ 1 │ студент │
    └────┴─────────┘
    (1 row)
    dbadmin@postgres=# TABLE table_tde_off;
    ┌────┬───────┐
    │ id │ a │
    ├────┼───────┤
    │ 1 │ Света │
    └────┴───────┘
    (1 row)
  7. Выполните контрольную точку:

    dbadmin@postgres=# \c postgres postgres
    SSL 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
  8. Выполните поиск ранее добавленных записей в таблицы по файлам данных в директориях БД /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/tablespaces
    grep: /pgdata/06/tablespaces/tde_off/PG_15_202409231/5/16429: binary file matches # <----- Обнаружены только данные, созданные в незакодированной таблице.
  9. Откройте файл с ключами $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)

Подведем итоги​

Вопрос 1

Выберете все корректные утверждения: