auditd is the Linux audit daemon that operates at the kernel level and logs all critical events: user logins, file changes, execution of privileged commands, and system calls. It's the foundation of compliance (PCI DSS, SOC 2, ISO 27001) and forensic analysis.
Installing auditd
apt install auditd audispd-plugins -y
systemctl enable --now auditd
auditctl -s # Service status
Audit rules (/etc/audit/rules.d/audit.rules)
# Login monitoring
-w /var/log/auth.log -p wa -k auth_log
-w /etc/passwd -p wa -k user_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/group -p wa -k group_changes
-w /etc/sudoers -p wa -k sudoers_changes
# Web directory monitoring
-w /var/www/ -p wa -k web_changes
# Privileged commands
-a always,exit -F arch=b64 -S execve -F euid=0 -k root_commands
# Network settings changes
-w /etc/hosts -p wa -k host_changes
-w /etc/network/ -p wa -k network_changes
# Apply rules
augenrules --load
Analyzing audit logs
ausearch -k auth_log --start today
ausearch -k web_changes -i | grep "name=" | tail -20
ausearch -ua 0 --start "1 hour ago" # Commands from root in the last hour
aureport --summary
aureport --login --start today
aureport --file --start this-week | head -30
Real-time monitoring
tail -f /var/log/audit/audit.log | grep -E "type=USER_LOGIN|type=USER_AUTH"
audispd # Real-time event forwarding
audisp-remote. This protects logs from deletion by an attacker who gained root on your server.
Common auditd errors and messages explained
Five messages you run into most often while setting up auditd, and what they actually mean.
No rules— the output ofauditctl -lwhen the kernel has no rules loaded. The usual cause: edits were made to a file under/etc/audit/rules.d/butaugenrules --loadwas never run — auditd.service assembles the final ruleset from those fragments at startup, it doesn't read them live.You must be root to run this program.—auditctlandausearchread the audit log, which only root can access; run them withsudo.Error sending enable request (Operation not permitted)— an attempt to change rules while audit is in immutable mode (-e 2). That mode can only be cleared by rebooting the server — a deliberate protection against an attacker with root disabling auditing.<no matches>— howausearchreports that no events were found for the given key or time range. Check the-kname and whether the rule is actually loaded (auditctl -l).audit: backlog limit exceeded— this line indmesgorjournalctl -kmeans the kernel is dropping audit records faster than the daemon can pick them up. Increase the buffer with a-b 8192line inaudit.rules.
auditd compared to other monitoring tools
auditd is not the only way to watch a server, and it usually works alongside other tools rather than replacing them.
| Tool | Observation level | What it sees | Where it stores data |
|---|---|---|---|
| auditd | Kernel (system calls) | Every action covered by a rule: logins, execs, writes to a watched file | /var/log/audit/audit.log |
| syslog/rsyslog | Applications | Only what the application itself chose to log | /var/log/syslog or its own files |
| osquery | Periodic SQL queries | State snapshots: processes, packages, network connections on a schedule | Local database or forwarded to an external system |
| Wazuh / SIEM agent | Aggregator | Collects auditd events, logs, and FIM results in one place | Central SIEM server |
Periodic state snapshots are covered in osquery for server inventory, and pulling events from different sources into one system is covered in the Wazuh SIEM article.
When auditd is not the right fit
auditd does not cover every monitoring task, and relying on it alone is a mistake.
- It does not see network traffic reaching the server — that is a job for a firewall or an IPS-level system, not auditd.
- Broad rules like
-S execvewith no filters create noticeable overhead on a busy server and fill the backlog buffer faster than narrow rules filtered byeuidor path. - Inside a Docker container with no access to the host kernel, auditd is useless: the audit policy applies to the entire host kernel, not to an individual namespace.
- On a single server with no log shipping to external storage, the audit log is not protected: once an attacker has root, they can edit or delete
audit.logas easily as any other file.
Verifying that auditing actually works
Check not that the service is running, but that events really reach the log.
# Add a temporary test rule (lives only in kernel memory)
auditctl -w /tmp/audit-test -p wa -k audit_test
# Trigger an event
touch /tmp/audit-test
# Confirm the event was written to the log
ausearch -k audit_test --start recent
# Remove the test rule
auditctl -W /tmp/audit-test -p wa -k audit_test
If ausearch returns a record with type=PATH and the name /tmp/audit-test, instead of <no matches> — the whole chain of rule, kernel, daemon, and log is working, not just on paper.