Назад к обновлениям
New releaseJul 30, 2026

pgaudit v19beta3

Расширение аудита PostgreSQL

Поделиться

pgAudit
Журналирование аудита для Open Source PostgreSQL

Введение

Расширение PostgreSQL Audit Extension (pgAudit) обеспечивает детальное журналирование аудита сессий и/или объектов через стандартный механизм журналирования PostgreSQL.

Цель pgAudit — предоставить пользователям PostgreSQL возможность создавать журналы аудита, которые часто требуются для соответствия государственным, финансовым или ISO-сертификациям.

Аудит — это официальная проверка счетов физического лица или организации, обычно проводимая независимым органом. Информация, собираемая pgAudit, правильно называется контрольным следом или журналом аудита. В этой документации используется термин «журнал аудита».

Зачем нужен pgAudit?

Базовое журналирование операторов может быть обеспечено стандартным механизмом журналирования с помощью log_statement = all. Это приемлемо для мониторинга и других целей, но не обеспечивает уровень детализации, обычно требуемый для аудита. Недостаточно иметь список всех операций, выполненных над базой данных. Также должна быть возможность находить конкретные операторы, представляющие интерес для аудитора. Стандартный механизм журналирования показывает, что запросил пользователь, тогда как pgAudit фокусируется на деталях того, что произошло, пока база данных выполняла запрос.

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

DO $$
BEGIN
    EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;

Стандартное журналирование выдаст вам это:

LOG:  statement: DO $$
BEGIN
    EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;

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

AUDIT: SESSION,33,1,FUNCTION,DO,,,"DO $$
BEGIN
    EXECUTE 'CREATE TABLE import' || 'ant_table (id INT)';
END $$;"
AUDIT: SESSION,33,2,DDL,CREATE TABLE,TABLE,public.important_table,CREATE TABLE important_table (id INT)

Журналируется не только блок DO, но и подоператор 2 содержит полный текст CREATE TABLE с типом оператора, типом объекта и полным именем, чтобы упростить поиск.

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

Особенности использования

В зависимости от настроек pgAudit может создавать огромный объём журналирования. Будьте осторожны, чтобы точно определить, что именно должно журналироваться в вашей среде, чтобы избежать избыточного журналирования.

Например, при работе в среде OLAP, вероятно, неразумно журналировать вставки в большую таблицу фактов. Размер файла журнала, скорее всего, будет во много раз превышать фактический объём данных вставок, поскольку файл журнала представлен в виде текста. Поскольку журналы обычно хранятся вместе с операционной системой, это может привести к очень быстрому исчерпанию дискового пространства. В случаях, когда невозможно ограничить журналирование аудита определёнными таблицами, обязательно оцените влияние на производительность во время тестирования и выделите достаточно места на томе журнала. Это также может относиться к средам OLTP. Даже если объём вставок не так высок, влияние журналирования аудита на производительность может заметно сказаться на задержках.

Чтобы ограничить количество отношений, для которых ведётся журнал аудита для операторов SELECT и DML, рассмотрите возможность использования объектного журналирования аудита (см. Объектное журналирование аудита). Объектное журналирование аудита позволяет выбирать отношения для журналирования, что позволяет уменьшить общий объём журнала. Однако при добавлении новых отношений их необходимо явно добавлять в объектное журналирование аудита. Программное решение, при котором указанные таблицы исключаются из журналирования, а все остальные включаются, может быть хорошим вариантом в этом случае.

Совместимость с версиями PostgreSQL

pgAudit поддерживает PostgreSQL 14 или новее.

Чтобы поддерживать новые функции, появляющиеся в каждом выпуске PostgreSQL, pgAudit поддерживает отдельную ветку для каждой основной версии PostgreSQL (в настоящее время PostgreSQL 14–19), которая будет поддерживаться аналогично проекту PostgreSQL.

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

Версии pgAudit соотносятся с основными версиями PostgreSQL следующим образом:

  • pgAudit v19.X предназначен для поддержки PostgreSQL 19.

  • pgAudit v18.X предназначен для поддержки PostgreSQL 18.

  • pgAudit v17.X предназначен для поддержки PostgreSQL 17.

  • pgAudit v16.X предназначен для поддержки PostgreSQL 16.

  • pgAudit v1.7.X предназначен для поддержки PostgreSQL 15.

  • pgAudit v1.6.X предназначен для поддержки PostgreSQL 14.

Компиляция и установка

pgAudit может быть скомпилирован с установленной копией PostgreSQL с пакетами разработки с использованием PGXS. Следующие инструкции должны работать в большинстве Unix-подобных операционных систем.

Клонируйте расширение pgAudit:

git clone https://github.com/pgaudit/pgaudit.git

Перейдите в каталог pgAudit:

cd pgaudit

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

git checkout REL_19_STABLE

Соберите и установите pgAudit:

make install USE_PGXS=1 PG_CONFIG=/usr/pgsql-19/bin/pg_config

Инструкции по тестированию и разработке можно найти в test.

Настройки

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

Настройки могут быть заданы глобально (в postgresql.conf или с помощью ALTER SYSTEM ... SET), на уровне базы данных (с помощью ALTER DATABASE ... SET) или на уровне роли (с помощью ALTER ROLE ... SET). Обратите внимание, что настройки не наследуются через обычное наследование ролей, и SET ROLE не изменяет настройки pgAudit пользователя. Это ограничение системы ролей, а не особенность pgAudit.

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

Кроме того, перед установкой pgaudit.log необходимо вызвать CREATE EXTENSION pgaudit, чтобы обеспечить корректную работу pgaudit. Расширение устанавливает триггеры событий, которые добавляют дополнительное аудирование для DDL. pgAudit будет работать и без установленного расширения, но операторы DDL не будут содержать информацию о типе и имени объекта.

Если расширение pgaudit удалено и его необходимо пересоздать, сначала необходимо сбросить pgaudit.log, иначе будет вызвана ошибка.

pgaudit.log

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

  • READ: SELECT и COPY, когда источником является отношение или запрос.

  • WRITE: INSERT, UPDATE, DELETE, TRUNCATE и COPY, когда назначением является отношение.

  • FUNCTION: Вызовы функций и блоки DO.

  • ROLE: Операторы, связанные с ролями и привилегиями: GRANT, REVOKE, CREATE/ALTER/DROP ROLE.

  • DDL: Все DDL, не входящие в класс ROLE.

  • MISC: Прочие команды, например DISCARD, FETCH, CHECKPOINT, VACUUM, SET.

  • MISC_SET: Прочие команды SET, например SET ROLE.

  • ALL: Включает все перечисленное выше.

Несколько классов можно указать через запятую, а классы можно вычитать, ставя перед классом знак - (см. Сессионное журналирование аудита).

По умолчанию — none.

pgaudit.log_catalog

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

По умолчанию — on.

pgaudit.log_client

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

Обратите внимание, что pgaudit.log_level включается только тогда, когда pgaudit.log_client равен on.

По умолчанию — off.

pgaudit.log_level

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

Обратите внимание, что pgaudit.log_level включается только тогда, когда pgaudit.log_client равен on; в противном случае будет использоваться значение по умолчанию.

По умолчанию — log.

pgaudit.log_parameter

Указывает, что журналирование аудита должно включать параметры, переданные вместе с оператором. При наличии параметров они будут включены в формате CSV после текста оператора.

По умолчанию — off.

pgaudit.log_parameter_max_size

Указывает, что значения параметров, длина которых превышает эту настройку (в байтах), не должны журналироваться, а заменяться на <long param suppressed>. Настройка задаётся в байтах, а не в символах, поэтому не учитывает многобайтовые символы в кодировке текстового параметра. Эта настройка не действует, если log_parameter равен off. Если эта настройка равна 0 (по умолчанию), все параметры журналируются независимо от длины.

По умолчанию — 0.

pgaudit.log_relation

Указывает, должно ли сессионное журналирование аудита создавать отдельную запись журнала для каждого отношения (TABLE, VIEW и т. д.), указанного в операторе SELECT или DML. Это удобное сокращение для исчерпывающего журналирования без использования объектного журналирования аудита.

По умолчанию — off.

pgaudit.log_rows

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

По умолчанию — off.

pgaudit.log_statement

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

По умолчанию — on.

pgaudit.log_statement_once

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

По умолчанию — off.

pgaudit.role

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

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

Сессионное журналирование аудита

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

Конфигурация

Сессионное журналирование включается настройкой pgaudit.log.

Включите сессионное журналирование для всех DML и DDL и журналируйте все отношения в операторах DML:

set pgaudit.log = 'write, ddl';
set pgaudit.log_relation = on;

Включите сессионное журналирование для всех команд, кроме MISC, и поднимите сообщения журнала аудита до уровня NOTICE:

set pgaudit.log = 'all, -misc';
set pgaudit.log_level = notice;

Пример

В этом примере сессионное журналирование аудита используется для журналирования операторов DDL и SELECT. Обратите внимание, что оператор вставки не журналируется, поскольку класс WRITE не включён.

SQL:

set pgaudit.log = 'read, ddl';

create table account
(
    id int,
    name text,
    password text,
    description text
);

insert into account (id, name, password, description)
             values (1, 'user1', 'HASH1', 'blah, blah');

select *
    from account;

Вывод журнала:

AUDIT: SESSION,1,1,DDL,CREATE TABLE,TABLE,public.account,create table account
(
    id int,
    name text,
    password text,
    description text
);,<not logged>
AUDIT: SESSION,2,1,READ,SELECT,,,select *
    from account,,<not logged>

Объектное журналирование аудита

Объектное журналирование аудита записывает операторы, затрагивающие конкретное отношение. Поддерживаются только команды SELECT, INSERT, UPDATE и DELETE. TRUNCATE не входит в объектное журналирование аудита.

Объектное журналирование аудита предназначено для более детальной замены pgaudit.log = 'read, write'. Поэтому их совместное использование может не иметь смысла, но одним из возможных сценариев является использование сессионного журналирования для записи каждого оператора с последующим дополнением объектным журналированием для получения более подробной информации о конкретных отношениях.

Конфигурация

Объектное журналирование аудита реализовано через систему ролей. Настройка pgaudit.role определяет роль, которая будет использоваться для журналирования аудита. Отношение (TABLE, VIEW и т. д.) будет журналироваться, если роль аудита имеет разрешения на выполненную команду или наследует разрешения от другой роли. Это позволяет эффективно иметь несколько ролей аудита, даже если в любом контексте существует только одна основная роль.

Установите pgaudit.role в auditor и предоставьте права SELECT и DELETE на таблицу account. Любые операторы SELECT или DELETE по таблице account теперь будут журналироваться:

set pgaudit.role = 'auditor';

grant select, delete
   on public.account
   to auditor;

Пример

В этом примере объектное журналирование аудита используется для иллюстрации детального подхода к журналированию операторов SELECT и DML. Обратите внимание, что журналирование таблицы account контролируется разрешениями на уровне столбцов, тогда как журналирование таблицы account_role_map осуществляется на уровне таблицы.

SQL:

set pgaudit.role = 'auditor';

create table account
(
    id int,
    name text,
    password text,
    description text
);

grant select (password)
   on public.account
   to auditor;

select id, name
  from account;

select password
  from account;

grant update (name, password)
   on public.account
   to auditor;

update account
   set description = 'yada, yada';

update account
   set password = 'HASH2';

create table account_role_map
(
    account_id int,
    role_id int
);

grant select
   on public.account_role_map
   to auditor;

select account.password,
       account_role_map.role_id
  from account
       inner join account_role_map
            on account.id = account_role_map.account_id

Вывод журнала:

AUDIT: OBJECT,1,1,READ,SELECT,TABLE,public.account,select password
  from account,<not logged>
AUDIT: OBJECT,2,1,WRITE,UPDATE,TABLE,public.account,update account
   set password = 'HASH2',<not logged>
AUDIT: OBJECT,3,1,READ,SELECT,TABLE,public.account,select account.password,
       account_role_map.role_id
  from account
       inner join account_role_map
            on account.id = account_role_map.account_id,<not logged>
AUDIT: OBJECT,3,1,READ,SELECT,TABLE,public.account_role_map,select account.password,
       account_role_map.role_id
  from account
       inner join account_role_map
            on account.id = account_role_map.account_id,<not logged>

Формат

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

  • AUDIT_TYPESESSION или OBJECT.

  • STATEMENT_ID — Уникальный идентификатор оператора для данной сессии. Каждый идентификатор оператора представляет вызов серверного процесса. Идентификаторы операторов последовательны, даже если некоторые операторы не журналируются. Для одного идентификатора оператора может быть несколько записей, когда журналируется более одного отношения.

  • SUBSTATEMENT_ID — Последовательный идентификатор для каждого подоператора в рамках основного оператора. Например, вызов функции из запроса. Идентификаторы подоператоров непрерывны, даже если некоторые подоператоры не журналируются. Для одного идентификатора подоператора может быть несколько записей, когда журналируется более одного отношения.

  • CLASS — например, READ, ROLE (см. pgaudit.log).

  • COMMAND — например, ALTER TABLE, SELECT.

  • OBJECT_TYPETABLE, INDEX, VIEW и т. д. Доступен для операторов SELECT, DML и большинства операторов DDL.

  • OBJECT_NAME — Полное имя объекта (например, public.account). Доступно для операторов SELECT, DML и большинства операторов DDL.

  • STATEMENT — Оператор, выполненный в серверном процессе.

  • PARAMETER — Если установлен pgaudit.log_parameter, это поле будет содержать параметры оператора в виде заключённого в кавычки CSV или <none>, если параметров нет. В противном случае поле равно <not logged>.

Используйте log_line_prefix, чтобы добавить любые другие поля, необходимые для удовлетворения требований к журналу аудита. Типичный префикс строки журнала может быть '%m %u %d [%p]: ', который предоставит дату/время, имя пользователя, имя базы данных и идентификатор процесса для каждой записи аудита.

Предостережения

Журналирование аудита выполняется по мере возможности и не является транзакционным. pgAudit записывает записи аудита через стандартный механизм журналирования PostgreSQL, который не синхронизирует каждую запись с диском одновременно с транзакцией, создавшей её, и не передаёт ошибки записи обратно в сессию. Нет гарантии, что зафиксированная транзакция будет иметь соответствующую запись в журнале аудита. Если сервер выйдет из строя или произойдёт сбой питания, или назначение журнала станет недоступным (например, том журнала заполнится) после фиксации транзакции, но до того, как её записи аудита будут надёжно записаны, эти записи могут быть потеряны. И наоборот, оператор журналируется при его выполнении, поэтому запись может быть создана, даже если её транзакция впоследствии будет откачена.

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

ALTER TABLE test RENAME TO test2;

AUDIT: SESSION,36,1,DDL,ALTER TABLE,TABLE,public.test2,ALTER TABLE test RENAME TO test2,<not logged>

Возможно, что команда будет зарегистрирована в журнале более одного раза. Например, когда таблица создаётся с первичным ключом, указанным при создании, индекс для первичного ключа будет журналироваться независимо, и для индекса будет создана ещё одна запись аудита в рамках записи о создании. Однако все эти записи будут содержаться в одном идентификаторе оператора.

Автовакуум и автоанализ не журналируются.

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

Надёжно аудировать суперпользователей с помощью pgAudit невозможно. Одно из решений — ограничить доступ к учётным записям суперпользователей и использовать расширение set_user для повышения привилегий при необходимости.

Авторы

Расширение PostgreSQL Audit Extension основано на проекте 2ndQuadrant pgaudit, авторами которого являются Саймон Риггз (Simon Riggs), Абхиджит Менон-Сен (Abhijit Menon-Sen) и Иэн Барвик (Ian Barwick), и представлено как расширение для ядра PostgreSQL. Дополнительная разработка выполнена Дэвидом Стилом (David Steele) из Crunchy Data.

Категории