Linux auditd Deep Dive: Rules, ausearch, and SIEM Integration in 2026
A hands-on auditd guide for 2026: write persistent audit.rules, search events with ausearch, ship records to Wazuh, Elastic, or Splunk, and tune performance.
The Linux auditd daemon is the kernel-backed audit subsystem that records security-relevant events (syscalls, file accesses, user logins, and policy violations) to a tamper-evident log that compliance frameworks like CIS, STIG, PCI-DSS, and HIPAA depend on. This guide walks through writing persistent audit.rules, searching events with ausearch and aureport, dispatching records through audispd plugins to Wazuh, Elastic, or Splunk, and tuning the framework so it doesn't melt your I/O budget. Every example targets audit-userspace 4.0+ on kernel 6.x.
auditd consumes kernel audit messages over a netlink socket and writes them to /var/log/audit/audit.log; rules are loaded with auditctl and persisted through files in /etc/audit/rules.d/.
The 2026 audit-userspace 4.0 release replaces the legacy audispd binary with built-in dispatcher threads inside auditd, and ships modern plugins for syslog, remote af_unix sockets, and the Elastic/Wazuh agents.
Use immutable mode (-e 2) on production hosts so an attacker with root cannot delete or rewrite the rule set without rebooting. That reboot itself becomes a detection signal.
CIS Benchmark and DISA STIG ship reference rule packs (~70 rules) covering identity changes, sudoers edits, kernel module loads, time-of-day changes, and discretionary access control modifications.
Performance impact is dominated by -a always,exit rules on hot syscalls (open, execve). Scope rules with -F filters and audit only what your detection logic actually consumes.
Ship audit events off-box in near real time. Local logs are the first thing ransomware operators wipe.
What is auditd in Linux?
auditd is the user-space daemon that receives audit messages from the kernel audit subsystem and writes them to disk in a structured, append-only log. The kernel side is enabled at boot via audit=1 on the command line (set by default in RHEL, Ubuntu Server LTS, and SUSE) and exposes an AUDIT_NETLINK socket. Only one process can hold that socket, and that process is auditd. Without auditd running, audit messages back up in a fixed-size kernel buffer and are eventually dropped.
The framework predates eBPF, but it remains the only mechanism in the kernel that can record arbitrary syscall events with full argument context and ship them through a binary protocol that survives PID reuse. Where journald records application messages and eBPF tools like Falco and Tetragon record runtime behavior, auditd records policy: every event matches a rule you wrote, with a known reason for being captured. Honestly, that mapping from rule to event is exactly what compliance auditors want to see, and it's the main reason auditd refuses to die.
Records are written in key=value form with a leading type=. A single user action can fan out into a dozen records (SYSCALL, EXECVE, CWD, PATH, PROCTITLE) tied together by an event ID. Tools like ausearch reassemble those into human-readable groups.
auditd architecture and audit-userspace 4.0
The 2026 audit-userspace 4.0 release (shipped in RHEL 9.4+, Ubuntu 24.04, Fedora 40+) consolidates the old multi-process design. Earlier versions used a separate audispd binary that auditd piped events to; 4.0 folds that dispatcher into auditd itself with one thread per plugin. The result: fewer context switches, lower latency, and a simpler systemd unit graph. See the upstream linux-audit/audit-userspace release notes for the 4.0 migration details.
The flow on a modern system looks like:
Kernel: a syscall matches a rule, audit_log_*() fires a netlink message.
auditd: reads the message, applies rate-limit and disk-full policy from /etc/audit/auditd.conf, writes to /var/log/audit/audit.log.
Dispatcher: copies the event to each enabled plugin in /etc/audit/plugins.d/ (syslog, af_unix, remote, custom).
Consumer: a SIEM forwarder (Wazuh agent, Elastic Agent, syslog-ng, rsyslog with imfile) reads the destination and ships to a central store.
Two files control daemon behavior. /etc/audit/auditd.conf sets log rotation, disk-full action, and network parameters. /etc/audit/audit.rules is the canonical persistent rule file generated by augenrules from fragments in /etc/audit/rules.d/. Edit the fragments, never audit.rules directly. Your changes will then survive package upgrades and the rule order stays predictable.
Writing audit rules: syntax, filters, and persistence
Audit rules come in three flavors: control rules (set globals like buffer size), file watches (-w on a path), and syscall rules (-a action,filter -S syscall). Load them at runtime with auditctl; make them survive reboot by placing a numbered fragment in /etc/audit/rules.d/ and running augenrules --load.
A practical starter ruleset that covers identity changes, sudoers edits, and kernel module loading:
# /etc/audit/rules.d/30-baseline.rules
## Control: 8192-entry backlog, panic-on-failure off
-D
-b 8192
-f 1
--backlog_wait_time 60000
## Identity files
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k privilege
-w /etc/sudoers.d/ -p wa -k privilege
## Time of day (CIS 4.1.4)
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -S clock_settime -k time-change
-w /etc/localtime -p wa -k time-change
## Kernel module load/unload
-a always,exit -F arch=b64 -S init_module -S finit_module -S delete_module -k modules
-w /usr/sbin/insmod -p x -k modules
-w /usr/sbin/rmmod -p x -k modules
-w /usr/sbin/modprobe -p x -k modules
## Suspicious exec from world-writable dirs
-a always,exit -F arch=b64 -S execve -F dir=/tmp -F perm=x -k tmp-exec
-a always,exit -F arch=b64 -S execve -F dir=/var/tmp -F perm=x -k tmp-exec
## Lock the rule set (uncomment in production)
# -e 2
Three details often get missed. First, -D at the top of a fragment deletes the existing ruleset. Useful when reloading, dangerous if you stack fragments expecting them to merge. Second, every file watch is a syscall rule under the hood; -w on a directory expands to a path-prefix watch but does not recurse into mount points. Third, -e 2 makes the kernel reject all further rule modifications until reboot. Set it as the last line of your highest-numbered fragment (e.g., 99-finalize.rules) once you have validated the policy.
I hit this exact gotcha shipping a hardened image last year: a colleague duplicated -D in two fragments, and we ended up loading only the last 12 rules out of 80. Always validate before locking:
A non-zero lost counter means the backlog overflowed. Raise -b or narrow your rules.
CIS Benchmark and STIG audit rule packs
You don't need to write a hundred rules from scratch. Two reference rule packs cover almost everything an auditor will ask for:
CIS Distribution Independent Linux Benchmark v3.0: sections 4.1.3 through 4.1.18 specify audit rules for date/time, network environment, MAC policy, login events, session initiation, DAC modifications, unsuccessful file access, privileged command execution, mount syscalls, file deletions, sudoers, and kernel modules. The reference .rules fragments ship with OpenSCAP content packs (see the ComplianceAsCode/content repository).
DISA STIG for RHEL 9: V-258197 through V-258262 cover the same ground with stricter wording and explicit -F auid>=1000 -F auid!=unset filters that scope syscall rules to real user activity instead of system services.
Pair this with a scheduled OpenSCAP scan for drift detection. If someone removes a rule, the next scan flags the failed control. It's a cheap feedback loop that catches a surprising amount of operational drift.
Searching events with ausearch and aureport
ausearch is the primary query tool. It reads raw audit logs, reassembles related records by event ID, and accepts filters for time, key, user, executable, and result. aureport is the summarization tool: counts, top-N, and report-style output for humans.
Daily triage queries that should be in every responder's muscle memory:
# All events tagged 'identity' in the last 24 hours
sudo ausearch -k identity --start recent
# Every privileged command run today, grouped
sudo ausearch -k privilege --start today -i
# Failed syscalls for a specific user
sudo ausearch -ui $(id -u alice) --success no -i
# Executions from /tmp triggered by our baseline rule
sudo ausearch -k tmp-exec --start this-week -i
# Top 10 users by audit event volume
sudo aureport --summary -u | head
# Login report
sudo aureport --login --summary -i
# Failed authentications
sudo aureport --auth --failed -i --start week-ago
The -i flag is critical. It translates numeric uids, syscall numbers, and sockaddrs to symbolic names. Without it you'll be staring at syscall=257 wondering what openat looks like in decimal (it isn't fun).
For ad-hoc analysis on shipped logs, feed JSON to jq. The ausearch --format json flag added in audit-userspace 3.1 produces one JSON object per event, which is perfect for jq, DuckDB, or pandas in a Jupyter notebook during live Linux incident response:
Local logs are necessary but not sufficient. Ship events off-box so a host compromise doesn't destroy your evidence. audit-userspace 4.0 ships three production-grade plugins in /etc/audit/plugins.d/:
syslog.conf: forwards every event to syslog at a configurable facility/priority. Pair with rsyslog's omfwd or syslog-ng's destination(network()) for TLS-encrypted relay.
af_unix.conf: writes the raw event stream to a unix socket. The Wazuh agent and the Elastic Agent both consume this directly.
au-remote.conf: uses the dedicated audit-remote protocol with GSSAPI/Kerberos auth. Heavyweight; only worth it in classified environments that mandate it.
The Wazuh integration is the cleanest path for most teams. Enable the plugin and tell Wazuh to read it:
# /etc/audit/plugins.d/af_unix.conf
active = yes
direction = out
path = builtin_af_unix
type = builtin
args = 0640 /var/ossec/queue/ossec/audit
format = string
# /var/ossec/etc/ossec.conf snippet on the agent
<localfile>
<log_format>audit</log_format>
<location>/var/ossec/queue/ossec/audit</location>
</localfile>
Restart auditd with service auditd restart (note: systemctl restart on the audit unit is intercepted, and service auditd restart is the historically blessed path. Both work on modern systemd, but the latter avoids confusing warnings). Wazuh's system-calls monitoring documentation includes ready-made decoders that turn raw audit records into searchable JSON fields. If you're building a broader pipeline, our walkthrough on a multi-layer Linux IDS with AIDE, Auditd, Wazuh, and Suricata shows how this fits in.
For Elastic, the Elastic Agent's auditd integration consumes the same af_unix socket and ships ECS-normalized events. For Splunk, use the Linux Audit add-on (TA-linux-auditd) which extracts fields via props/transforms.
Does auditd impact performance?
Yes, but the impact is bounded and predictable. The overhead comes from two places: the kernel hook walking the rule list for every syscall, and the user-space write to disk. On modern hardware (NVMe, 6.x kernel) a CIS-compliant ruleset of ~70 rules costs about 1–3% CPU on a typical web server. The numbers explode when you do one of three things:
Audit hot syscalls without filters.-a always,exit -S openat with no -F filter on a database server can generate tens of thousands of events per second. Always scope with -F dir=, -F auid>=1000, or -F exe=.
Synchronous disk writes with slow storage. The default flush = INCREMENTAL_ASYNC in auditd.conf is fine for SSDs. SYNC mode on a spinning disk will create perceptible latency on any auditable syscall.
Backlog set too low. Under burst load, kernel events queue in the backlog buffer. If they overflow, the kernel either drops them silently (-f 0), prints to dmesg (-f 1), or panics the system (-f 2). Most teams run -f 1 with -b 8192 or higher.
Benchmark with auditctl -s after a representative load run. The lost field should stay at 0. If it climbs, either raise the backlog, narrow rules, or move to eBPF for high-volume telemetry while keeping auditd for the compliance subset.
Troubleshooting backlog, lost events, and rule conflicts
Three problems account for nearly all auditd support tickets.
Lost events climbing. Run auditctl -s; if lost is non-zero and growing, the backlog is overflowing. Short-term fix: auditctl -b 16384. Long-term fix: prune rules. The aureport --syscall --summary command shows which syscalls dominate your event volume. That's where to add -F filters.
Rules silently not loading. A syntax error in any fragment under /etc/audit/rules.d/ causes augenrules to skip the broken file but proceed with the rest. Always run augenrules --check after editing, and compare auditctl -l | wc -l to the expected count.
Cannot disable or modify rules. If you set -e 2 (immutable mode), the kernel rejects all rule changes until reboot. This is intentional, but it surprises people during incident response. Confirm with auditctl -s | grep enabled; a value of 2 means immutable. Plan ahead: keep your detection ruleset in a separate, looser 50-detection.rules file that you reload without immutability, and lock only the compliance baseline. For tamper-evident chain-of-custody on logs, see Red Hat's RHEL 9 audit system documentation.
Frequently Asked Questions
How do I view auditd logs?
Raw logs live in /var/log/audit/audit.log. Read them with sudo ausearch -i (interpreted) for human-readable output, or sudo aureport for summaries. Avoid cat/less directly, because you'll miss the multi-record event reassembly that ausearch handles for you.
What is the difference between auditd and syslog?
syslog/journald record application log messages, which are text strings emitted by programs. auditd records kernel-mediated events: syscalls, file accesses, and policy decisions, with structured fields and event correlation IDs. The two complement each other; you typically forward auditd events into syslog for centralized collection, but auditd is the authoritative source for compliance evidence.
How do I make audit rules persistent across reboots?
Place rule fragments in /etc/audit/rules.d/ using numeric prefixes (e.g., 30-baseline.rules, 50-detection.rules) to control merge order. Run sudo augenrules --load to regenerate /etc/audit/audit.rules and load the active set. The auditd service replays this file on every boot.
Can I run auditd inside a container?
Not effectively. The kernel audit netlink socket is global; only the host can hold it, and the events it produces describe host-wide activity. Run auditd on the container host, then use the contid field (audit-userspace 3.0+) to attribute events to specific containers. For in-container syscall visibility, use eBPF tools like Tetragon or Falco instead.
How do I rotate audit logs without losing events?
Configure rotation in /etc/audit/auditd.conf with max_log_file = 50, num_logs = 10, and max_log_file_action = ROTATE. auditd handles rotation internally and signals itself to reopen the file. Never use logrotate on audit.log, since it bypasses the daemon's coordination and can drop events during the rename.
Deploy Linux IMA and EVM for kernel-enforced file integrity. Learn appraisal policy, EVM key sealing to TPM 2.0, IMA digest lists, and Keylime remote attestation with working configs.
A practical, layered guide to Linux USB security in 2026: block rogue devices with USBGuard, udev rules, and kernel module blacklisting. Includes BadUSB defense, audit logging, and SIEM integration.
Deploy confidential VMs on Linux with AMD SEV-SNP and Intel TDX. Covers BIOS setup, QEMU launch flags, remote attestation with snpguest and configfs-tsm, attested LUKS unlock, and an operational hardening checklist for production workloads in 2026.