Задание 1: Защита системного каталога pg_proc
В этом задании мы изучим устройство защиты целостности, поставим системный каталог pg_proc под защиту и проверим целостность данных.
Для удобства рекомендуем открыть на сервере три отдельных терминала, распределив задачи следующим образом:
- Терминал 1: для мониторинга логов.
- Терминал 2: для работы от имени системного пользователя
postgres. - Терминал 3: для действий от имени пользователя
student.
Инфраструктура подсистемы
В сеансе postgres проверим наличие и содержимое каталога pg_integrity:
[student@srv1 ~]$ sudo -iu postgres
===============================================================
You are connected to Pangolin Cluster (Pobeda)
- Hostname : srv1
- IP Address : <IP-Address1>
---------------------------------------------------------------
- node ( master ) : <IP-Address1>
- node ( replica ) : <IP-Address2>
- arbiter : <IP-Address3>
- Manager version : 2.1.13
- Pangolin version : 6.7.0
===============================================================
[postgres@srv1 ~]$ cd /pgdata/06/data/
[postgres@srv1 data]$ ls -l pg_integrity/
total 8
-rw------- 1 postgres postgres 26 Feb 1 17:35 integrity_files.json
-rw------- 1 postgres postgres 26 Feb 1 17:35 integrity_relations.json
Сохраним каталог pg_integrity вместе с его содержимым в домашнем каталоге пользователя postgres:
[postgres@srv1 data]$ cp -av pg_integrity/ ~postgres/
'pg_integrity/' -> '/var/lib/postgres/pg_integrity'
'pg_integrity/integrity_files.json' -> '/var/lib/postgres/pg_integrity/integrity_files.json'
'pg_integrity/integrity_relations.json' -> '/var/lib/postgres/pg_integrity/integrity_relations.json'
Посмотрим, что находится в этих файлах:
[postgres@srv1 data]$ cat pg_integrity/integrity_files.json
{
"integrity" : null
}
[postgres@srv1 data]$ cat pg_integrity/integrity_relations.json
{
"integrity" : null
}
Постановка pg_proc под защиту
Системный каталог pg_proc содержит метаданные о функциях и процедурах.
Если pg_proc поставлен под защиту, то любое изменение, связанное с любой функцией и процедурой приведет:
- к разрыву всех текущих сессий;
- к блокировке доступа всех пользователей, кроме администратора СУБД.
Информация о нарушении целостности системного каталога pg_proc также будет записана в журнал сообщений.
Для проверки создадим в сеансе student функцию:
[postgres@srv1 ~]$ exit
[student@srv1 ~]$ psql -p 5433 -h srv1
psql (15.5)
Type "help" for help.
student=> CREATE FUNCTION vcheras() RETURNS timestamp AS
$$
SELECT now() - '1 day'::interval;
$$ LANGUAGE SQL;
Выдает ошибку. Что делать?
Если вышла ошибка вида:
ERROR: no schema has been selected to create in
В файле конфигурации /etc/pangolin-manager/postgres.yml необходимо исправить параметр:
[student@srv1 ~]$ sudo vi /etc/pangolin-manager/postgres.yml
search_path: public,ext
[student@srv1 ~]$ sudo systemctl restart pangolin-manager
Затем повторите создание функции.
CREATE FUNCTION
student=> \df vcheras
List of functions
Schema | Name | Result data type | Argument data types | Type
--------+---------+-----------------------------+---------------------+------
public | vcheras | timestamp without time zone | | func
(1 row)
student=> SELECT now(); SELECT vcheras();
now
-------------------------------
2026-09-14 13:44:23.730486+03
(1 row)
vcheras
----------------------------
2026-09-13 13:44:23.730816
(1 row)
student=> SELECT now(), vcheras();
now | vcheras
-------------------------------+----------------------------
2026-09-14 13:44:41.744621+03 | 2026-09-13 13:44:41.744621
(1 row)
Посмотрим, как выглядит информация о функции vcheras() в системном каталоге pg_proc:
student=> SELECT * FROM pg_proc WHERE proname = 'vcheras' \gx
-[ RECORD 1 ]---+----------------------------------
oid | 16390
proname | vcheras
pronamespace | 2200
proowner | 16388
prolang | 14
procost | 100
prorows | 0
provariadic | 0
prosupport | -
prokind | f
prosecdef | f
proleakproof | f
proisstrict | f
proretset | f
provolatile | v
proparallel | u
pronargs | 0
pronargdefaults | 0
prorettype | 1114
proargtypes |
proallargtypes |
proargmodes |
proargnames |
proargdefaults |
protrftypes |
prosrc | +
| SELECT now() - '1 day'::interval;+
|
probin |
prosqlbody |
proconfig |
proacl |
Столбец prosecdef содержит false.
Включение контроля целостности pg_proc
Откроем в эмуляторе терминала еще одну сессию пользователя ОС postgres, в которой запустим мониторинг записей в журнале сообщений:
[postgres@srv1 data]$ tail -f `cut -d' ' -f2 $PGDATA/current_logfiles` -n 20
...
2026-09-23 12:25:35 MSK [177743]: [4-1] app=psql,user=postgres,db=postgres,client=<IP-Address1>,type=client backend LOG: AUDIT: SESSION, CONNECTION, OPEN,database = postgres,user = postgres
2026-09-23 12:26:47 MSK [177743]: [5-1] app=psql,user=postgres,db=postgres,client=<IP-Address1>,type=client backend ERROR: function vcheras() does not exist
2026-09-23 12:26:47 MSK [177743]: [6-1] app=psql,user=postgres,db=postgres,client=<IP-Address1>,type=client backend STATEMENT: ALTER FUNCTION vcheras() SECURITY DEFINER;
2026-09-23 12:27:38 MSK [177759]: [1-1] app=[unknown],user=[unknown],db=[unknown],client=<IP-Address1>,type=not initialized LOG: connection received: host=<IP-Address1> port=32904
...
В сеансе суперпользователя установим контроль целостности pg_proc:
postgres=# SELECT pg_integrity_add_catalog('student','pg_catalog.pg_proc');
pg_integrity_add_catalog
--------------------------
t
(1 row)
В результате появится запись в журнале сообщений:
2026-09-23 12:29:59 MSK [177778]: [1-1] app=object of calculation sha256,user=postgres,db=student,client=[bgworker],type=object of calculation sha256 LOG: Relation hash successfully added "student" "pg_catalog.pg_proc"
Проверим, что записалось в файл pg_integrity/integrity_relations.json:
postgres=# \! cat $PGDATA/pg_integrity/integrity_relations.json
{
"integrity" : [
{
"db" : "student",
"hash" : "2b25e48f14ea486954f8adc360d9ece913641ee22297d7147053c368535a30bd",
"name" : "pg_catalog.pg_proc",
"type" : "relation"
}
]
}
В сеансе student изменим параметр SECURITY функции vcheras():
student=> ALTER FUNCTION vcheras() SECURITY DEFINER;
ALTER FUNCTION
student=> SELECT proname, prosecdef FROM pg_proc WHERE proname = 'vcheras';
proname | prosecdef
---------+-----------
vcheras | t
(1 row)
Сеанс пользователя пока не прерван. Убедимся в этом:
student=> SELECT pg_backend_pid();
pg_backend_pid
----------------
177759
(1 row)
Проверка целостности
Если выполнить проверку целостности, то все сеансы будут заблокированы.
В сеансе суперпользователя:
postgres=# SELECT pg_integrity_check();
pg_integrity_check
--------------------
f
(1 row)
Проверим, существует ли сеанс student:
student=> SELECT pg_backend_pid();
FATAL: terminating connection due to administrator command
SSL connection has been closed unexpectedly
The connection to the server was lost. Attempting reset: Failed.
The connection to the server was lost. Attempting reset: Failed.
!?>
Вот, что записалось в журнал сообщений:
2026-09-23 12:29:59 MSK [177778]: [1-1] app=integrity check worker,user=,db=,client=[bgworker],type=integrity check worker WARNING: The hash is different for the catalog object: pg_catalog.pg_proc
2026-09-23 12:29:59 MSK [177778]: [2-1] app=integrity check worker,user=,db=,client=[bgworker],type=integrity check worker WARNING: Disconnect proc pid 177759 roleId 16390 rolename student
2026-09-23 12:29:59 MSK [177759]: [7-1] app=psql,user=student,db=student,client=<IP-Address1>,type=client backend FATAL: terminating connection due to administrator command
Снова выполним команду включения контроля целостности:
postgres=# SELECT pg_integrity_add_catalog('student','pg_catalog.pg_proc');
pg_integrity_add_catalog
--------------------------
t
(1 row)
postgres=# SELECT pg_integrity_check();
pg_integrity_check
--------------------
t
(1 row)
Отслеживаемая контрольная сумма изменилась:
postgres=# \! cat $PGDATA/pg_integrity/integrity_relations.json
{
"integrity" : [
{
"db" : "student",
"hash" : "fb4c67a66029f1e51de6aebc46ce59b83a338025e65bf72e69f9c89d393fe25b",
"name" : "pg_catalog.pg_proc",
"type" : "relation"
}
]
}
Теперь снова можно открыть сеанс роли student:
[student@srv1 ~]$ psql -p 5433 -h srv1
psql (15.5)
Type "help" for help.
student=> SELECT pg_backend_pid();
pg_backend_pid
----------------
177981
(1 row)