Linux auditd: Rules, auditctl and ausearch Investigations - 夜莺博客

Linux auditd: Rules, auditctl and ausearch Investigations

auditd sees things no userspace tool can: syscalls, file access, privilege changes and the exact command line a user ran. It is also the subsystem most often deployed badly — so noisy that nobody reads it, or so narrow that it misses the one event that mattered. This guide covers rule design that survives production, the ordering rules that keep CPU cost sane, and the investigation commands that turn raw audit records into an answer.

The rule types you actually need

Rule class Purpose Cost
Control Backlog size, failure mode, immutability (-e 2) None
Exclusions Drop high-volume, low-value record types first Reduces cost
File watches Sensitive files: /etc/shadow, /etc/sudoers, SSH keys, cron Low–moderate
Syscall rules Privilege escalation, module loading, refused opens Moderate–high
High-volume network rules Outbound connection logging High — enable only when needed

A ruleset that holds up

# /etc/audit/rules.d/hardening.rules
# === 1. Exclusions first: they cut volume before any matching ===
-a always,exclude -F msgtype=CWD
-a always,exclude -F msgtype=EOE
-a always,exclude -F msgtype=PROCTITLE

# === 2. Sensitive file integrity ===
-w /etc/shadow      -p rwa -k shadow_access
-w /etc/passwd      -p rwa -k passwd_access
-w /etc/group       -p rwa -k group_access
-w /etc/sudoers     -p rwa -k sudoers_access
-w /etc/sudoers.d   -p rwa -k sudoers_access
-w /etc/ssh/sshd_config -p rwa -k sshd_config
-w /root/.ssh       -p rwa -k root_ssh_keys

# === 3. Scheduled task tampering ===
-w /etc/crontab   -p rwa -k cron_access
-w /etc/cron.d    -p rwa -k cron_access
-w /var/spool/cron -p rwa -k cron_access

# === 4. User and group modification ===
-w /usr/sbin/useradd -p x -k user_modification
-w /usr/sbin/usermod -p x -k user_modification
-w /usr/sbin/userdel -p x -k user_modification
-w /usr/sbin/groupadd -p x -k group_modification

# === 5. Privilege escalation (euid 0 by a real user) ===
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k privilege_escalation
-w /usr/bin/su   -p x -k su_usage
-w /usr/bin/sudo -p x -k sudo_usage

# === 6. Kernel module load/unload ===
-a always,exit -F arch=b64 -S init_module -S finit_module -k module_load
-a always,exit -F arch=b64 -S delete_module -k module_unload

# === 7. Lock the configuration once you trust it (requires reboot to change) ===
# -e 2
sudo augenrules --load          # or: sudo auditctl -R /etc/audit/rules.d/hardening.rules
sudo auditctl -l                # list active rules
sudo auditctl -s                # status: enabled, backlog, lost counters

Why ordering is not cosmetic

Rules are evaluated in order, and the never-match rule installed by default on many distributions (-a never,task) short-circuits everything after it. If your rules appear loaded but nothing is recorded, that is the first thing to check; on those systems you remove 10-no-audit.rules and add a base config instead. Exclusions go first because they prevent events from ever being generated, which is cheaper than generating and discarding them.

Tuning auditd.conf

# /etc/audit/auditd.conf
log_file = /var/log/audit/audit.log
log_format = ENRICHED            # readable names alongside numeric IDs
max_log_file = 50
num_logs = 10
backlog_limit = 32768            # default 8192 is low for busy hosts
space_left = 100
space_left_action = syslog       # use 'halt' only if audit integrity beats availability
admin_space_left_action = syslog
freq = 50

Also set log_format = ENRICHED: it adds UID-to-username resolution so investigations do not require translating numbers by hand.

Investigation with ausearch and aureport

# Find by the key you assigned
sudo ausearch -k shadow_access --format text
sudo ausearch -k privilege_escalation -ts today

# Everything a user did
sudo ausearch -ua alice
sudo ausearch -ua alice -sc execve --format text | tail -40

# By file, by time window
sudo ausearch -f /etc/sudoers
sudo ausearch -ts '2026-09-18 22:00:00' -te '2026-09-19 02:00:00' -k privilege_escalation

# Summary reporting
sudo aureport --summary
sudo aureport --auth --summary
sudo aureport --key --summary
sudo ausearch -k access --raw | aureport --user --summary

The workflow that produces answers: start with aureport --key --summary to see which rule sets are firing, then pivot into ausearch filtered by key and user, then read the underlying event with ausearch -a <event_id> -i to get decoded syscall arguments.

Failure modes and their symptoms

  1. Lost eventsauditctl -s shows lost > 0. Raise backlog_limit, narrow high-volume rules, or both.
  2. Disk full, audit stops or the host halts — depends on space_left_action. Ship logs off-box; a full /var must never be able to take down a production host silently.
  3. auditd burning CPU — a rule matching all syscalls without an -F arch and -F auid filter. Narrow it.
  4. Rules cannot be changed-e 2 is set. That is intentional; boot to change, so keep the reboot option available.
  5. A watch on a directory stops working after a remount — watches are attached to the mount; re-apply rules or use a filesystem-level exclusion rule.

Design the rules around investigations you can actually imagine running, keep the keys meaningful, watch the lost counter, and auditd stops being shelfware and starts being evidence.

Related Reading on This Site

原文链接:https://www.systemshardening.com/articles/linux/auditd-deep-dive/ (Systems Hardening - Linux Audit Framework deep dive)