Журналирование и аудит#
Для журналирования и аудита событий безопасности используется модифицированное расширение 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.EVENT—OPEN,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):
Спецсимвол |
Назначение |
Только для пользовательского процесса |
|---|---|---|
|
Имя приложения (application_ name) |
да |
|
Имя пользователя |
да |
|
Имя базы данных |
да |
|
Имя удаленного узла или IP-адрес, а также номер порта |
да |
|
Имя удаленного узла или IP-адрес |
да |
|
Идентификатор процесса |
нет |
|
Штамп времени, без миллисекунд |
нет |
|
Штамп времени, с миллисекундами |
нет |
|
Штамп времени, с миллисекундами (в виде времени Unix) |
нет |
|
Тег команды: тип текущей команды в сессии |
да |
|
Код ошибки SQLSTATE |
нет |
|
Идентификатор сессии. Подробности ниже |
нет |
|
Номер строки журнала для каждой сессии или процесса. Начинается с 1 |
нет |
|
Штамп времени начала процесса |
нет |
|
Идентификатор виртуальной транзакции (backendID/ localXID) |
нет |
|
Идентификатор транзакции (0 если не присвоен) |
нет |
|
Ничего не выводит. Непользовательские процессы останавливаются в этой точке. Игнорируется пользовательскими процессами |
нет |
|
Выводит % |
нет |
Пример префикса строки журнала: «%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 возникают после перечитывании конфигурации, если:
Параметр был изменен в файле конфигурации СУБД;
Параметр был изменен при помощи
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#
Указывает, какие классы операторов будут регистрироваться при ведении журнала аудита сессии. Возможные значения:
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;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>