SSD Nodes Learn 🎉 VPS от $5.50/мес
Руководства Matt ConnorАвтор: Matt Connor

Как настроить аудит команд пользователей в Linux

История оболочки не гарантирует безопасность. Узнайте, как использовать sudo, запись сессий, хуки bash и аудит ядра execve для контроля действий пользователей и передачи логов.

Что на самом деле записывает команды, которые пользователи выполняли на вашем сервере

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

Существует четыре уровня, позволяющих вести достоверный учет, и каждый из них имеет свою цену. sudo записывает по одной строке на каждую команду в syslog. Функция sudo I/O logging захватывает всю сессию для одной учетной записи. Хук оболочки, такой как PROMPT_COMMAND, регистрирует то, что ввел интерактивный пользователь bash. Подсистема аудита ядра записывает сам системный вызов execve, поэтому это единственный уровень, который видит каждый процесс. Это руководство описывает данные уровни, указывает границы их возможностей и завершается частью, определяющей ценность всей системы: передачей записей с машины до того, как проверяемый пользователь сможет получить к ним доступ.

Предупреждение перед началом работы. Подсистема аудита работает на уровне ядра, поэтому ее нельзя протестировать внутри контейнера, использующего ядро хоста. Выполняйте эти команды на KVM VPS, где вы управляете собственным ядром.

Почему история командной оболочки не является журналом аудита

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

Она принадлежит пользователю. Файл имеет права доступа 600 и принадлежит этой учетной записи, поэтому rm ~/.bash_history не требует никаких привилегий. То же самое касается открытия файла в редакторе и удаления двадцати нужных строк.

Она записывается при выходе из оболочки. Сеанс, завершенный командой kill -9 $$ или из-за разрыва соединения, не оставляет записей. Команда history -c перед exit дает тот же результат, и выглядит так, будто ничего не произошло.

Ее можно отключить одной командой. unset HISTFILE предотвращает запись файла для текущего сеанса. set +o history немедленно останавливает запись. HISTCONTROL=ignorespace скрывает любую команду, перед которой стоит пробел. Все это является частью man bash, так как история предназначена для управления пользователем.

Она записывает то, что было введено, а не то, что было выполнено. Псевдоним (alias) или функция оболочки означают, что текст в файле не соответствует программе, которую запустило ядро.

В ней также отсутствуют временные метки, если только HISTTIMEFORMAT не была установлена в момент записи, так как bash записывает свои маркеры #1755043200 только при установленной переменной.

При совместном использовании учетной записи история также не позволяет определить, кто именно совершил действие. Три человека, использующие одну учетную запись deploy, создают один общий файл под одним UID. Ни один уровень логирования не может приписать действие конкретному человеку, если два человека используют один UID. Это практический аргумент в пользу использования одной непривилегированной учетной записи на человека вместо общего логина.

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

Что логирует sudo и где заканчивается его видимость

sudo отправляет строку для каждой выполненной команды в facility authpriv syslog.

sudo grep 'sudo:' /var/log/auth.log | tail -5
journalctl -t sudo -n 5

Каждая строка содержит имя пользователя, терминал, рабочую директорию, целевого пользователя и саму команду:

sudo:    alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt update

Если /var/log/auth.log не существует, значит, в данном образе не установлен rsyslog и записи сохраняются только в journal. Перед тем как полагаться на него, убедитесь, что журнал не является энергозависимым:

journalctl --list-boots

Если отображается только текущая загрузка, значит, /var/log/journal не существует, журнал находится в /run и все записи удаляются при следующей перезагрузке. Сделайте его постоянным:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

Теперь об ограничении. sudo логирует команду, которую его попросили выполнить. Он не логирует то, что эта команда делает впоследствии. Поэтому одна строка завершает цепочку событий:

sudo -i

В лог попадает единственная запись о запуске оболочки. Каждая команда, введенная внутри этой root-оболочки, невидима для sudo, так как sudo больше не участвует в процессе выполнения. sudo su -, sudo bash и sudo vim /etc/shadow, за которыми следует :!bash, имеют одинаковую структуру. Правило в sudoers, разрешающее любую программу с возможностью выхода в shell, такую как vim или find, — это правило, предоставляющее доступ к root без ведения логов. Прежде чем доверять строкам лога, изучите, к чему на самом деле может получить доступ учетная запись:

sudo -l -U alice

Запись полного сеанса для одной учетной записи

Сначала определите, какая версия sudo установлена в системе, так как эта функция отсутствует в реализации на языке Rust:

sudo --version | head -1

Если в выводе указано sudo-rs, пропустите этот раздел и используйте подсистему audit. В официальной документации Ubuntu для релизов 25.10 и 26.04 указано, что ведение логов ввода-вывода и sudoreplay не поддерживаются; это оставалось актуальным по состоянию на август 2026 года. Это важно, так как sudo-rs является стандартным sudo в этих релизах, поэтому обновление может привести к удалению контроля, на который вы рассчитывали. Перед планированием любого логирования на основе sudo стоит ознакомиться с полным списком изменений в поведении sudo-rs.

Для оригинального sudo, который по-прежнему поставляется в Ubuntu 24.04 LTS, включите логирование ввода-вывода для одной учетной записи:

sudo visudo -f /etc/sudoers.d/iolog
Defaults:deploy log_output
Defaults!/usr/bin/sudoreplay !log_output

Используйте visudo вместо обычного текстового редактора, так как эта утилита блокирует сохранение файла при наличии синтаксических ошибок. Поврежденный файл sudoers лишает всех пользователей доступа к sudo. Затем воспроизведите сеанс:

sudo sudoreplay -l user=deploy
sudo sudoreplay 000001

sudoreplay -l выводит список сеансов с их идентификаторами; если log_output никогда не применялся к пользователю, команда ничего не выведет. Особенности использования: каждый байт, проходящий через терминал, сохраняется в /var/log/sudo-io, поэтому подробные сеансы занимают много места. Вторая строка в sudoers предотвращает запись самого процесса воспроизведения. Основная проблема заключается в безопасности данных: лог ввода-вывода содержит все введенные и выведенные символы, включая пароли, набранные в приглашении внутри сеанса, поэтому такие логи требуют защиты, аналогичной хранилищам паролей. Охват также ограничен: записываются только команды, выполненные через sudo. Действия пользователя, который вошел в систему и работает от своего имени, не фиксируются.

Shell-хуки и способы их обхода

Распространенный рецепт для «логирования каждой команды» заключается в добавлении хука PROMPT_COMMAND в файл /etc/profile.d/:

# /etc/profile.d/00-cmdlog.sh
PROMPT_COMMAND='logger -p local6.info -t cmdlog "$(whoami) $$ $(history 1 | sed "s/^ *[0-9]* *//")"'

bash выполняет PROMPT_COMMAND перед отрисовкой каждого приглашения командной строки, поэтому строка попадает в syslog в момент ввода, а не при выходе из сессии. Кроме того, logger записывает данные через системный демон логирования, поэтому права доступа к файлам пользователя не имеют значения. Откройте новую сессию оболочки и проверьте работу с помощью sudo tail -f /var/log/syslog или journalctl -t cmdlog -f, если в образе отсутствует rsyslog.

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

  • Неинтерактивные оболочки не выводят приглашение командной строки. ssh you@server 'id' выполняет команду и завершается, при этом ничего не логируется, так как PROMPT_COMMAND не выполняется.
  • Это переменная. unset PROMPT_COMMAND отключает её до конца сессии, и для этого не требуются привилегии.
  • Файл считывается только при входе в систему. bash --noprofile --norc вообще не выполняет /etc/profile.d/.
  • Это специфично для bash. zsh, sh, python3 -c 'import os; os.system("id")' и :!id внутри vim запускают программы, которые не увидит ни один хук приглашения bash.
  • Логируется строка в том виде, в котором она была введена, поэтому алиас или функция по-прежнему скрывают команду, которая была выполнена на самом деле.

Используйте shell-хуки для удобства. Они помогают ответить на вопрос «что я запускал в прошлый вторник» для добросовестных пользователей. Не позволяйте чек-листам называть это средством контроля.

Подсистема аудита ядра отслеживает каждый вызов execve

Подсистема аудита Linux, управляемая демоном auditd, является единственным уровнем, который пользователь не может обойти, так как запись создается внутри ядра в момент выполнения системного вызова. Если процесс запускает программу, событие фиксируется. Оболочка, язык программирования и наличие терминала не имеют значения.

sudo apt update && sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo auditctl -s

auditctl -s выводит состояние демона. enabled 1 с ненулевым значением pid означает, что он запущен, а lost 0 показывает, что записи пока не терялись. Запомните этот счетчик lost, он нам еще пригодится.

auid — это поле, которое делает аудит по-настоящему полезным. PAM устанавливает login uid при начале сессии, и ядро передает его каждому дочернему процессу в дальнейшем. Проверьте свой:

cat /proc/self/loginuid

Интерактивная SSH-сессия выводит ваш uid, так как /etc/pam.d/sshd включает pam_loginuid.so. Значение 4294967295 означает, что loginuid не был установлен, что является нормальным для процесса, запущенного системным демоном при загрузке. Важно то, что sudo -i не меняет его: root-оболочка, открытая пользователем alice, по-прежнему имеет auid 1000, поэтому каждая команда внутри нее приписывается alice. Это именно тот пробел, который оставляет sudo. Для изменения loginuid после его установки требуются права CAP_AUDIT_CONTROL, которых нет у обычных пользователей, а sudo auditctl --loginuid-immutable закрывает эту возможность даже для root до следующей перезагрузки.

Убедитесь, что /etc/pam.d/sshd, /etc/pam.d/login и /etc/pam.d/cron включают pam_loginuid.so, иначе события будут приходить без привязки к пользователю. Это тот же список файлов, который вы правите при защите SSH-доступа на VPS, поэтому выполняйте эти две задачи одновременно.

Базовый набор правил для auditd

Правила хранятся в /etc/audit/rules.d/*.rules. augenrules объединяет их в один список в алфавитном порядке имен файлов, и этот порядок определяет поведение, так как ядро останавливается на первом совпавшем правиле. Изучите содержимое перед добавлением новых правил, так как -D в последующем файле удаляет все, что было загружено ранее.

ls /etc/audit/rules.d/
cat /etc/audit/rules.d/audit.rules

Затем создайте /etc/audit/rules.d/50-exec.rules:

## Suppressions first: the kernel takes the first matching rule.
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-deb
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-query
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-split
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-trigger

## Every program started by a logged-in human.
-a always,exit -F arch=b64 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
-a always,exit -F arch=b32 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec

## Changes to who may become root.
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity

## Changes to the audit configuration itself.
-w /etc/audit/ -p wa -k auditconfig

Загрузите правила и проверьте результат:

sudo augenrules --load
sudo auditctl -l

auditctl -l выводит ваши правила, подтверждая, что они активны. No rules означает, что загрузка не удалась, а journalctl -u auditd -n 20 указывает файл и строку, которые отверг парсер. Старые версии инструментов audit не поддерживают ключевое слово unset. Если загрузчик выдает ошибку на этом поле, используйте -F auid!=4294967295 — это то же самое значение, записанное в числовом виде.

Теперь просмотрите события:

sudo ausearch -k exec -ts recent -i | tail -40
sudo ausearch -ul 1000 -ts today -i
sudo aureport -k --summary -i

-i преобразует UID и номера системных вызовов в понятные имена, на практике это необходимо. -ts recent ограничивает вывод последними десятью минутами. Каждое выполнение программы приходит как группа записей: запись SYSCALL содержит UID, AUID, статус завершения и ключ, запись EXECVE содержит полный список аргументов, а записи CWD и PATH предоставляют контекст.

Важное ограничение, о котором часто забывают: audit отслеживает системные вызовы, а встроенные команды оболочки (shell builtins) не совершают собственных системных вызовов. cd /root не запускает отдельную программу. echo evil >> /etc/passwd, введенная в bash, также не запускает программу, так как и echo, и перенаправление происходят внутри уже запущенного процесса оболочки. Поэтому правила execve видят запуск программ, а правила -w видят операции записи. По отдельности они не дают полной картины.

В завершение заблокируйте конфигурацию:

## /etc/audit/rules.d/99-finalize.rules
-e 2

-e 2 делает набор правил неизменяемым до следующей перезагрузки. После загрузки этого параметра auditctl -s будет сообщать enabled 2, и любая попытка добавить или удалить правило завершится ошибкой Operation not permitted, даже для пользователя root. Добавляйте этот файл последним и будьте готовы к перезагрузке при каждом изменении правил. В этом и заключается смысл: набор правил, который может незаметно отключить любой злоумышленник, не является надежным доказательством.

Аудиторский лог, который никто не читает — это лишь формальность для соответствия требованиям

Проблема auditd не в том, что он что-то пропускает. Проблема в том, что он записывает так много данных, что их никто не просматривает, и в итоге лог существует только для галочки, а не для поиска ответов на вопросы.

Перед тем как что-либо настраивать, выполните расчеты на своей системе:

sudo aureport -k --summary -i
sudo du -sh /var/log/audit

Один sudo apt upgrade запускает тысячи кратковременных процессов, и каждый из них несет ваш auid, поэтому одно обновление пакетов может перевесить неделю работы пользователя за клавиатурой. Именно поэтому в исключениях выше указаны dpkg и его вспомогательные компоненты. Настраивайте исключения по исполняемому файлу, а не по пользователю: исключение для /usr/bin/dpkg — это дыра в безопасности, которую можно описать одним предложением, тогда как исключение для учетной записи — это дыра, в точности повторяющая форму того, что вы пытались отследить.

Ключ -k в каждом правиле — это то, что позволяет искать по логам спустя месяц. ausearch -k sudoers — это вопрос, на который есть ответ. ausearch без фильтра — это стена текста, которая приучает вас перестать читать логи. Если вашей системе сбора логов требуется формат JSON вместо нативного, используйте laurel — плагин для auditd, который переписывает каждое событие в виде одного JSON-объекта с декодированными аргументами. Он регистрируется в /etc/audit/plugins.d/, как и любой другой плагин, а auditd подхватывает изменения в плагинах при sudo pkill -HUP auditd.

Реальные издержки auditd

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

  • Процессорное время и задержки. Машина, которая постоянно выполняет fork, например, сборочный узел или CI-раннер, создает запись на каждый exec. Когда очередь событий ядра переполняется, --backlog_wait_time заставляет ядро приостановить процесс, породивший событие, пока не освободится место, поэтому audit проявляется как замедление сборки, а не как процент загрузки CPU. Отслеживайте backlog и lost в sudo auditctl -s под реальной нагрузкой. Растущее значение lost означает, что записи были потеряны, а лог с незаметными пропусками хуже, чем отсутствие лога вообще, так как вы все равно будете ему доверять.
  • Диск. Прочитайте /etc/audit/auditd.conf и осознанно решите, что произойдет при заполнении диска, так как значения по умолчанию — это лишь рекомендации. max_log_file, num_logs и max_log_file_action управляют ротацией. space_left_action, admin_space_left_action и disk_full_action управляют аварийными ситуациями, а некоторые из доступных действий, включая halt и single, выведут машину из строя, лишь бы не потерять запись.

Параметр -f в /etc/audit/rules.d/audit.rules — это то же самое решение на уровне ядра: -f 1 сообщает об ошибке аудита в syslog, а -f 2 вызывает kernel panic. Выбирайте 2 только в том случае, если вы действительно предпочтете потерять сервер, чем потерять запись. На VPS, от которого зависят пользователи, лучше настроить ротацию и перенести хранение логов за пределы сервера.

Передача логов с сервера в режиме, близком к реальному времени

Это подтверждается каждым отчетом об инцидентах. Логи, остающиеся на скомпрометированном хосте, могут быть изменены злоумышленником. Пользователь root может переписать /var/log/auth.log, удалить /var/log/audit/audit.log и остановить демон. -e 2 предотвращает выгрузку правил, но никак не влияет на rm. Любой уровень защиты выше дает доказательства только в том случае, если копия данных была предварительно выведена с машины.

Собственный механизм передачи данных в audit — это плагин audisp-remote из пакета audispd-plugins. Включите его в /etc/audit/plugins.d/au-remote.conf:

active = yes
direction = out
path = /usr/sbin/audisp-remote
type = always
format = string

Проверьте path на соответствие command -v audisp-remote перед перезагрузкой, так как неверный путь не приведет ни к чему, кроме одной строки в журнале. Установите remote_server и port в /etc/audit/audisp-remote.conf, а на стороне коллектора задайте tcp_listen_port = 60 в его собственном auditd.conf. Выполните перезагрузку с помощью sudo pkill -HUP auditd. Во многих образах systemctl restart auditd отклоняется, так как юнит-файл устанавливает RefuseManualStop=yes, поэтому отправка сигнала является надежным способом.

Другой вариант — включить аудит в поток syslog, который вы уже пересылаете. /etc/audit/plugins.d/syslog.conf поставляется вместе с active = no. Установите значение yes, перезагрузитесь, и события аудита будут добавлены к строкам sudo и остальным логам. Затем перешлите всё это с помощью rsyslog по протоколу TLS (transport layer security), для чего потребуется пакет rsyslog-gnutls:

# /etc/rsyslog.d/60-forward.conf
*.* action(type="omfwd"
    target="logs.example.net" port="6514" protocol="tcp"
    StreamDriver="gtls" StreamDriverMode="1"
    StreamDriverAuthMode="x509/name"
    StreamDriverPermittedPeers="logs.example.net"
    action.resumeRetryCount="-1"
    queue.type="linkedList" queue.filename="fwd" queue.saveOnShutdown="on")

Настройки очереди — наиболее важная часть. action.resumeRetryCount="-1" выполняет бесконечные повторные попытки, а очередь с поддержкой записи на диск через queue.saveOnShutdown="on" сохраняет записи, пока коллектор недоступен, и отправляет их после восстановления связи. Без этих двух параметров перезагрузка коллектора оставит пробел в доказательствах, и вы даже не узнаете о его существовании. Примените настройки через sudo systemctl restart rsyslog, затем убедитесь, что записи действительно поступают на коллектор, прежде чем доверять этой системе.

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

Проверка невозможности перезаписи записи обычным пользователем

Проверьте это утверждение на практике, а не полагайтесь на предположения. Используйте обычную учетную запись без прав sudo:

echo test >> /var/log/auth.log
cat /var/log/audit/audit.log
auditctl -D
id -nG

Ожидайте следующий результат: Permission denied, так как владельцем auth.log является syslog с группой adm и правами 640; снова Permission denied, так как журнал аудита имеет права 600 и принадлежит root; ошибку выполнения, так как для изменения правил аудита требуются права CAP_AUDIT_CONTROL; и список групп, в котором отсутствуют adm и systemd-journal.

Последняя проверка — это то, на чем часто ошибаются. Членство в adm дает право на чтение /var/log/auth.log, а членство в systemd-journal — право на чтение всего журнала. Ни одно из них не дает прав на запись, поэтому они не позволяют вносить изменения. Оба варианта позволяют пользователю просматривать все строки аутентификации на сервере, и это решение должно приниматься осознанно, а не путем копирования строки usermod -aG из ответа на форуме.

Наконец, подтвердите два условия, которые должны сохраняться после перезагрузки:

sudo auditctl -s
systemctl is-enabled auditd

enabled 2 означает, что набор правил заблокирован до следующей загрузки. enabled в выводе второй команды означает, что auditd снова запустится после этой загрузки. Набор правил, который действует только до следующего обновления ядра, не является полноценным журналом аудита.

FAQ

Как увидеть все команды, выполненные конкретным пользователем?

Найдите его uid с помощью id -u alice, затем выполните поиск в журнале аудита по login uid: sudo ausearch -ul 1000 -ts today -i. Добавьте -k exec, чтобы ограничить выборку правилом execve. Значение login uid устанавливается при входе в систему и сохраняется при выполнении su и sudo -i, поэтому этот метод позволяет отследить команды, запущенные внутри root-оболочки, открытой данным пользователем. Это работает только для команд, выполненных после загрузки правил, так как audit не хранит историю событий, которые не были настроены для записи. sudo aureport -k --summary -i выводит количество записей по каждому правилу, если вы хотите сначала оценить структуру данных.

Может ли пользователь удалить свою историю bash, чтобы скрыть выполненные действия?

Да, и для этого не требуются привилегии. Файл ~/.bash_history принадлежит пользователю с правами 600, поэтому он может редактировать, очищать или удалять его. Пользователь также может отключить запись в файл с помощью unset HISTFILE, остановить ведение истории в текущем сеансе через set +o history или скрыть отдельные команды, вводя их с пробелом в начале, если установлена переменная HISTCONTROL=ignorespace. Bash записывает историю при выходе из оболочки, поэтому сеанс, завершенный через kill -9 $$, не оставляет записей. Рассматривайте историю оболочки как подсказку, а не как доказательство.

Регистрирует ли sudo действия внутри sudo -i?

Нет. sudo записывает только команду, которую его попросили выполнить, поэтому sudo -i создает одну строку для оболочки и ничего после неё. Каждая команда, введенная в этой root-оболочке, невидима для sudo, так как sudo больше не участвует в процессе. sudo su -, sudo bash и любая разрешенная программа с возможностью выхода в оболочку ведут себя аналогично. Пробел в логировании закрывают два метода: правила аудита для execve, которые записывают каждую программу с привязкой к исходному login uid, и правила sudoers, которые изначально не предоставляют доступ к оболочке.

Замедлит ли auditd работу сервера?

Это полностью зависит от количества процессов, запускаемых вашей рабочей нагрузкой, поэтому проводите измерения, а не полагайтесь на абстрактные цифры. Сервер, который в основном отвечает на запросы, выполняет мало операций exec и не заметит нагрузки. Сервер сборки или CI-раннер постоянно выполняет exec и может ощутить влияние, так как при заполнении очереди аудита ядра процесс, породивший событие, приостанавливается до освобождения места. Запустите sudo auditctl -s при реальной нагрузке и следите за backlog и lost. Любое значение lost больше нуля означает, что записи были потеряны, что является худшим исходом, так как в журнале появляются невидимые пробелы.

Где следует хранить журналы аудита?

На другой машине с задержкой в несколько секунд. Любой, кто получил права root на проверяемом хосте, может удалить /var/log/audit/audit.log и перезаписать /var/log/auth.log, поэтому локальные копии отвечают на вопросы только об инцидентах, которые никто не пытался скрыть. Пересылайте данные с помощью плагина audisp-remote на центральный сервер auditd или включите плагин audit syslog и пересылайте весь поток syslog через rsyslog по TLS. Предоставьте сборщику собственные учетные данные и убедитесь, что у проверяемых учетных записей нет к нему доступа.