Журналирование и аудит#

Для журналирования и аудита событий безопасности используется модифицированное расширение pgAudit. Оно обеспечивает детальное журналирование сессий и объектов для целей аудита. События подключения и события настройки механизма защиты данных включаются в отдельные классы регистрируемых событий для предоставления возможности гибкой настройки аудита. Расширение pgAudit заменяет стандартное средство журналирования PostgreSQL.

Формат#

Примечание:

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

Записи аудита записываются в стандартное средство ведения журнала и содержат столбцы в формате CSV:

LOG:  AUDIT: <AUDIT_TYPE>,<STATEMENT ID>,<SUBSTATEMENT ID>,<CLASS>,<STATEMENT_TYPE>,<OBJECT_TYPE>,<OBJECT_NAME>,<COMMAND_TEXT>,<PARAMETER_LIST>,ERROR: <ERROR_MESSAGE>

  • AUDIT_TYPE - тип, может быть SESSION (аудит действий пользователя для всех запросов) или OBJECT (аудит действий над каким либо отношением (таблицей));

  • STATEMENT ID - номер запроса;

  • SUBSTATEMENT ID - номер подзапроса;

  • CLASS - класс: DDL, READ, WRITE и т.д. (см. ниже подраздел pgaudit.log);

  • STATEMENT_TYPE - тип запроса CREATE TABLE, ALTER TABLE, SELECT, INSERT, UPDATE, DELETE и т.д.;

  • OBJECT_TYPE - тип объекта, если есть (TABLE, INDEX, VIEW и т.д.);

  • OBJECT_NAME - имя объекта, если есть (например, public.account);

  • COMMAND_TEXT - текст команды;

  • PARAMETER_LIST - список параметров, если есть;

  • ERROR_MESSAGE - сообщение об ошибке, если есть.

Пример:

LOG:  AUDIT: SESSION,1,1,READ,SELECT,,, SELECT * FROM ext.test_table;,<not logged>,ERROR: permission denied for table test_table

У записей класса CONNECTION свой формат:

AUDIT: <AUDIT_TYPE>,<CLASS>,<EVENT>,<SESSION_TIME>,<DATA_BASE>,<USER>, <ID>
  • AUDIT_TYPE — всегда SESSION.

  • CLASS — всегда CONNECTION.

  • EVENTOPEN, CLOSED, FAILED, CHANGE USER.

  • SESSION_TIME — только для события CLOSED. Формат записи: «session time: %d:%02d:%02d.%03d» — часы, минуты, секунды, миллисекунды соответственно.

  • DATA_BASE — имя базы данных, к которой осуществляется подключение. Формат записи: - «database = %s» (имя базы данных).

  • USER — имя пользователя, подключающегося к базе данных. Формат записи: — «user = %s» (имя пользователя).

Пример:

LOG:  AUDIT: SESSION, CONNECTION, OPEN,database = First_db,user = user_test2
LOG:  AUDIT: SESSION, CONNECTION, CLOSED, session time: 0:14:43.261,database = First_db,user = user_test2

Для событий включения и выключения трассировки сессии, записи в журнале имеют формат:

  • AUDIT_TYPE - всегда SESSION;

  • CLASS - всегда MISC;

  • STATEMENT_TYPE - всегда SET;

  • OBJECT_TYPE - всегда TRACING;

  • OBJECT_NAME - пусто;

  • COMMAND_TEXT — зависит от события:

    • для события включения трассировки сессии сообщение вида: \"<start,числовое_значение_уровня_логирования,имя_лог-файла>\". Слово start является константой;

    • для события выключения трассировки сессии содержит константу stop: \"<stop>\".

Пример:

LOG:  AUDIT: SESSION,1,1,MISC,SET,TRACING,,\"<start,15,/pgdata/06/data/tracing/trace1.log>\",<not logged>
LOG:  AUDIT: SESSION,2,1,MISC,SET,TRACING,,\"<stop>\",<not logged>

Для добавления любых других полей, необходимых для удовлетворения ваших требований к журналу аудита, может использоваться префикс строки журнала (log_line_prefix):

Спецсимвол

Назначение

Только для пользовательского процесса

%a

Имя приложения (application_ name)

да

%u

Имя пользователя

да

%d

Имя базы данных

да

%r

Имя удаленного узла или IP-адрес, а также номер порта

да

%h

Имя удаленного узла или IP-адрес

да

%p

Идентификатор процесса

нет

%t

Штамп времени, без миллисекунд

нет

%m

Штамп времени, с миллисекундами

нет

%n

Штамп времени, с миллисекундами (в виде времени Unix)

нет

%i

Тег команды: тип текущей команды в сессии

да

%e

Код ошибки SQLSTATE

нет

%c

Идентификатор сессии. Подробности ниже

нет

%l

Номер строки журнала для каждой сессии или процесса. Начинается с 1

нет

%s

Штамп времени начала процесса

нет

%v

Идентификатор виртуальной транзакции (backendID/ localXID)

нет

%x

Идентификатор транзакции (0 если не присвоен)

нет

%q

Ничего не выводит. Непользовательские процессы останавливаются в этой точке. Игнорируется пользовательскими процессами

нет

%%

Выводит %

нет

Пример префикса строки журнала: «%m %u %d \[%p\]:» - включить дату/время, имя пользователя, имя базы данных и идентификатор процесса для каждой записи журнала аудита.

В качестве идентификатора используется uuidv4 (формируется случайным образом). Для получения идентификатора используется функция gen_random_uuid. Формат идентификатора:

xxxxxxxxxxxxMxxxNxxxxxxxxxxxxxxx
Значения на позициях M и N определяют соответственно версию и вариант UUID

Примечание:

В случае, если опция pgaudit.legal отключена, то записи формируются по старым правилам и их формат приводится к начальному виду.

Событие восстановления базы данных#

Добавлен новый класс событий RECOVERY, который имеет формат:

AUDIT: <AUDIT_TYPE>,<CLASS>,<ACTION>,<TYPE>,<PHASE>,<DBNAME>,<FILE>,<TIME>,<RESULT>,<ID>,<IMPORTANCE>

Поля:

  • AUDIT_TYPE - тип аудита, всегда SESSION;

  • CLASS - класс события, всегда RECOVERY;

  • ACTION - одно из следующих значений: pg_dump / pg_restore / pg_dumpall / pg_basebackup / pg_probackup / pg_backup_start / pg_backup_stop;

  • TYPE - тип события:

    • BACKUP - создание копии;

    • RESTORE - восстановление из копии;

  • PHASE - фаза:

    • START - начало операции;

    • STOP - завершение операции;

  • DBNAME - имя базы данных;

  • FILE - имя файла / каталога резервной копии;

  • TIME - продолжительность операции в минутах (для фазы START всегда ноль);

  • RESULT - результат операции:

    • SUCCESS - операция успешно завершена;

    • FAIL - операция завершена с ошибкой (для фазы START всегда SUCCESS);

  • ID - идентификатор события;

  • IMPORTANCE - важность события, всегда HIGH.

События RECOVERY возникают при использовании утилит:

  • pg_dump - событие создания резервной копии;

  • pg_restore - событие восстановления из резервной копии;

  • pg_dumpall - событие создания резервной копии;

  • pg_basebackup - событие создания резервной копии;

  • pg_probackup - событие создания резервной копии (событие аудита формируется только в режиме backup);

  • manage_backup - событие создания резервной копии.

Примечание:

События RECOVERY возникают при использовании сторонних утилит, если они используют pg_backup_start / pg_backup_stop (поле ACTION принимает значение pg_backup_start / pg_backup_stop).

Каждая из утилит в процессе своей работы передает на сервер информацию о событии RECOVERY при помощи одной из функций:

  • start_recovery_event;

  • stop_recovery_event;

  • pg_backup_start;

  • pg_backup_stop.

Если в работе утилит не возникает ошибок, то формируется два события RECOVERY, отвечающих за начало процесса (PHASE=START) и за его завершение (PHASE=STOP). Если в процессе работы утилит возникают ошибки, то второе событие может отсуствовать в журнале аудита, либо содержать информацию об ошибке.

Событие нарушение целостности объектов контроля#

Добавлен новый класс событий INTEGRITY, который имеет формат:

AUDIT: <AUDIT_TYPE>,<CLASS>,<INTEGRITY_SUBJECT>,<INTEGRITY_OBJECT>,<INTEGRITY_ERROR>,<INTEGRITY_MODE>,<INTEGRITY_ACTION>,<ID>,<IMPORTANCE>

Поля:

  • AUDIT_TYPE - тип аудита, всегда SESSION;

  • CLASS - класс события, всегда INTEGRITY;

  • INTEGRITY_SUBJECT - субъект контроля:

    • MODULE - контроль загрузки модулей;

    • CORE - контроль целостности объектов базы данных;

    • CONFIG - контроль целостности конфигурации базы данных.

  • INTEGRITY_OBJECT - объекта контроля: путь к файлу или имя базы / каталога;

  • INTEGRITY_ERROR - тип изменения:

    • NOT_ALLOWED - объект запрещен;

    • DELETED - объект удален;

    • CHECK_SUM - контрольная сумма объекта не совпала с ожидаемой;

    • INTERNAL - внутренняя ошибка механизмов контроля целостности (в поле INTEGRITY_OBJECT будет записана расшифровка ошибки).

  • INTEGRITY_MODE - метод контроля, всегда SHA256;

  • INTEGRITY_ACTION - реакция на изменение:

    • SKIP - плагин не загружается/расширение не используется;

    • BLOCK_CONNECTION - блокировка подключения пользователей (кроме суперпользователей);

  • ID - идентификатор события;

  • IMPORTANCE - важность события, всегда EMERGENCY.

События INTEGRITY возникают, когда для объекта контроля обнаруживается одна из ошибок:

  • Объект контроля запрещен к использованию, если настройка не позволяется использовать объект контроля. Например, если расширение не содержится в списке для контроля загрузки модулей. Если список модулей пуст или отсутствует на диске, то при попытке загрузить любой модуль будет возникать данная ошибка.

  • Объект контроля удален (нет доступа).

  • Контрольная сумма объекта контроля не совпадает с ожидаемой.

Для формирования таких событий в модуль pgaudit добавлена функция pgaudit_integrity_violation_event:

/* Integrity subject type */
typedef enum
{
    INTEGRITY_SUBJECT_MODULE,
    INTEGRITY_SUBJECT_CORE
}
IntegritySubjectType;

/* Integrity error type */
typedef enum
{
    INTEGRITY_ERROR_NOT_ALLOWED,
    INTEGRITY_ERROR_DELETED,
    INTEGRITY_ERROR_CHECK_SUM
}
IntegrityErrorType;

/* Integrity mode type */
typedef enum
{
    INTEGRITY_MODE_SHA256
}
IntegrityModeType;

/* Integrity action type */
typedef enum
{
    INTEGRITY_ACTION_SKIP,
    INTEGRITY_ACTION_BLOCK_CONNECTION
}
IntegrityActionType;

/* Integrity violation occurred */
extern void
pgaudit_integrity_violation_event(
    IntegritySubjectType  subject,
    const char           *object,
    IntegrityErrorType    error,
    IntegrityModeType     mode,
    IntegrityActionType   action);

События запуска/остановки базы данных с причиной остановки#

Добавлен новый класс событий ACTION, который имеет формат:

AUDIT: <AUDIT_TYPE>,<CLASS>,<ACTION>,<WHAT>,<ID>,<IMPORTANCE>

Поля:

  • AUDIT_TYPE - тип аудита, всегда SESSION;

  • CLASS - класс события, всегда ACTION;

  • ACTION - действие:

    • START - запуск базы данных;

    • STOP - остановка базы данных;

  • WHAT - причина остановки базы данных (для действия START не заполняется);

  • ID - идентификатор события;

  • IMPORTANCE - важность события, всегда HIGH.

События ACTION возникают при запуске и остановке базы данных.

События изменения конфигурации системы управления базами данных#

Добавлен новый класс событий PARAMETER, который имеет формат:

AUDIT: <AUDIT_TYPE>,<CLASS>,<WHAT>,<ID>,<IMPORTANCE>
  • AUDIT_TYPE - тип аудита, всегда SESSION;

  • CLASS - класс события, всегда PARAMETER;

  • WHAT - сообщение об изменении параметра: "parameter "%name" changed from "%old_value" to "%new_value"":

    • %name - название параметра;

    • %old_value - предыдущее значение параметра;

    • %new_value - новое значение параметра;

  • ID - идентификатор события;

  • IMPORTANCE - важность события, всегда HIGH.

События PARAMETER возникают после перечитывании конфигурации, если:

  1. Параметр был изменен в файле конфигурации СУБД;

  2. Параметр был изменен при помощи ALTER SYSTEM SET name = value; или ALTER SYSTEM RESET name.

Действия по изменению параметров для пользователя или сессии (ALTER USER user SET name = value; или SET name = value;) попадают в аудит в рамках класса ROLE или MISC соответственно.

В СУБД Pangolin предусмотрена Настройка механизма оповещения администратора системы управления базами данных, администратора базы данных (администратора информационной системы) о событиях безопасности. Далее приведен скрипт оповещения администраторов:

#!/bin/sh
 
# Адрес/адреса администраторов
admins="admin@localhost admin1@localhost admin2@localhost"
 
# В зависимости от конфигурации аудита указывается множество файлов журнала
# Например, если
#     pgaudit.log_filename = 'audit-%u.log'
#     pgaudit.log_directory = '/pgdata/06/data/audit'
# то audit_files=/pgdata/06/data/audit/audit-*.log
audit_files={множество_файлов_журнала}
 
# Каталог для хранения временных файлов, которые создаются в процессе работы скрипта
# Необходимы права для модификации данного каталога
audit_tmp_directory={каталог_для_хранения_временных_файлов}
 
# Пересоздание каталога для хранения временных файлов
rm -rf $audit_tmp_directory
mkdir $audit_tmp_directory
 
# Проверка наличия необходимых утилит для скрипта
t="inotifywait sendmail"
if [ "$(which $t &>/dev/null; echo $?)" != 0 ]
  then
    echo "ERROR: [$t] tools not available! Exiting..."
    exit 1
fi
 
# Сохранение референцных файлов аудита
cp $audit_files $audit_tmp_directory
 
 
while true; do
 
# Ожидание изменений в любом из файлов журнала, возвращает полный путь до измененного файла
file_path=$(inotifywait --format %w -e modify $audit_files)
# Имя файла без пути
file_name=${file_path##*/}
  
# Сохранение измененного файла во временный каталог
# Последующие изменения журнала попадут в новые сообщения
cp $file_path $audit_tmp_directory/audit.tmp
# Сообщение для администратора - это новые данные аудита, добавленные в файл (относительно референцных)
audit_message=$(diff --changed-group-format='%<' --unchanged-group-format='' $audit_tmp_directory/audit.tmp $audit_tmp_directory/$file_name)
 
# Подготовка и отправка письма
# Для конструкции EOF в качестве отступов использовать <tab>
echo "send mail: $audit_message"
 
cat <<EOF | sendmail -t
To: $admins
Subject: audit event occurred
 
$audit_message
EOF
 
# Сохранение файла (после старого event'а) для последующего сравнения
mv $audit_tmp_directory/audit.tmp $audit_tmp_directory/$file_name
 
done

Примечание:

Для обеспечения возможности отправлять email-сообщения с серверов PG требуется наличие утилит: inotifywaitи sendmail.

Параметры#

pgaudit.log#

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

  • READSELECT и COPY, если источник — отношение или запрос;

  • WRITEINSERT, 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;

  • MISC_SET_ROLE – только команды SET ROLE;

  • CONNECTION – события, связанные с подключением к серверу. Существуют 4 типа таких событий: OPEN, CLOSED, FAILED, CHANGE USER. Событие FAILED регистрируется в случае неудачной попытки аутентификации по паролю и независимо от значения gaudit.log;

  • PROTECTION – функции настройки механизма защиты от привилегированных пользователей;

  • ALL – включить все вышеперечисленное.

Можно включить несколько классов, перечислив их через запятую, или исключить определенные классы, поставив перед ними знак минус «-» (см. ниже подраздел «Ведение журнала аудита сессии»).

Значение по умолчанию — none.

pgaudit.log_catalog#

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

Значение по умолчанию — on.

pgaudit.log_client#

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

Значение по умолчанию - off.

pgaudit.log_level#

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

Примечание:

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

Значение по умолчанию — log.

pgaudit.log_parameter#

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

Значение по умолчанию — off.

pgaudit.log_relation#

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

Значение по умолчанию — off.

pgaudit.log_rows#

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

При включении (on) поле строк будет указан после поля параметра (при pgaudit.log_parameter = on).

Значение по умолчанию - off.

pgaudit.log_statement#

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

Значение по умолчанию - on.

pgaudit.log_statement_once#

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

Значение по умолчанию — off.

pgaudit.role#

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

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

Рекомендации#

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

Например, при работе в среде OLAP не лучшим решением станет проверять вставки журналов в большую таблицу фактов. Размер файла журнала, скорее всего, будет во много раз больше фактического размера данных вставок, поскольку файл журнала хранится в текстовом виде. И так как журналы обычно хранятся на диске вместе с ОС, это может привести к очень быстрому исчерпанию дискового пространства.

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

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

Внимание!

Настройки pgaudit могут быть изменены только суперпользователем.

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

Настройки не наследуются через обычное наследование ролей, и SET ROLE не изменит настройки pgaudit пользователя. Это ограничение системы ролей, а не особенность pgaudit.

Настройки могут быть заданы:

  • глобально – в файле postgresql.conf или с помощью ALTER SYSTEM ... SET;

  • на уровне базы данных – с помощью ALTER DATABASE ... SET;

  • на уровне роли – с помощью ALTER ROLE ... SET.

Чтобы логи аудита выводились в журнал, в файле postgresql.conf задайте параметры:

pgaudit.log = 'ddl, role, connection, misc_set, protection'
pgaudit.log_client = 'on'
pgaudit.log_level = 'log'

Ведение журнала аудита сессии#

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

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

Ведение журнала сессии включается с помощью параметра 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. Обратите внимание, что оператор INSERT не регистрируется, так как класс WRITE не включен.

Пример:

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 — на уровне таблиц.

Пример:

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>