Why a single auditd rule is better than scattered syslog entries
When you run sudo, you’re stepping into privileged territory. Most distros ship a sudo wrapper that dumps a message into syslog. That message can be noisy, hard to sift through, and it doesn’t survive a clean‑up or a reboot. A dedicated auditd rule, on the other hand, captures every sudo invocation in a structured, tamper‑evident format. Couple that with a tiny logrotate config, and you get a reliable audit trail that sticks around long after the machine has been rebooted or the disk wiped.
Below is a step‑by‑step guide to setting up a single auditd rule that watches the sudo binary, plus a logrotate file that keeps the audit logs tidy. The instructions assume a recent Debian‑based system (Ubuntu 24.04, Debian 12) but the concepts work on any distro that ships auditd.
1. Install and enable auditd
sudo apt update
sudo apt install auditd audispd-plugins
sudo systemctl enable --now auditd
Auditd is the userspace daemon that receives events from the kernel audit subsystem. The audispd-plugins package contains the auditd plugin that writes events to /var/log/audit/audit.log.
Check that the daemon is running:
systemctl status auditd
If auditd is disabled or not running, sudo commands won’t be logged. I’ve seen this happen on fresh installs where the service was left in the “disabled” state.
2. Create a single audit rule for sudo
Audit rules live in /etc/audit/rules.d/. Create a file called sudo.rules:
sudo nano /etc/audit/rules.d/sudo.rules
Add the following two lines:
# Capture all execve calls to /usr/bin/sudo
-a always,exit -F arch=b64 -S execve -F path=/usr/bin/sudo -k sudo_exec
-a always,exit -F arch=b32 -S execve -F path=/usr/bin/sudo -k sudo_exec
-a always,exit– log every exit from the syscall.-F arch=b64/b32– cover both 64‑bit and 32‑bit syscalls.-S execve– the syscall that launches a program.-F path=/usr/bin/sudo– only the sudo binary.-k sudo_exec– a key that makes searching easier.
The rule is intentionally narrow: it only watches the sudo binary, not every execve. This keeps audit traffic low while still capturing the exact command line arguments that sudo passes to the target program.
Reload auditd to apply the rule:
sudo augenrules --load
Verify that the rule is active:
sudo auditctl -l | grep sudo_exec
You should see both the 64‑bit and 32‑bit entries.
3. Verify that sudo is being logged
Run a sudo command:
sudo -v
Then search the audit log:
sudo ausearch -k sudo_exec | less
You should see an event similar to:
type=EXECVE msg=audit(1707261234.567:1234): argc=3 a0="/usr/bin/sudo" a1="-v" a2="--"
type=SYSCALL msg=audit(1707261234.567:1234): arch=0x40000003 syscall=59 success=yes exit=0 a0=0x7f8c3b1a2b3c a1=0x7f8c3b1a2b3c a2=0x7f8c3b1a2b3c a3=0x7f8c3b1a2b3c items=0 ppid=1233 pid=1234 auid=1000 uid=0 gid=0 euid=0 ...
The EXECVE record contains the full command line, and the SYSCALL record shows the exit status. This is the audit trail you want.
4. Logrotate configuration
Auditd writes to /var/log/audit/audit.log. By default, auditd rotates the log itself, but the rotation policy can be tweaked with logrotate. Create a dedicated logrotate file:
sudo nano /etc/logrotate.d/auditd
Add:
/var/log/audit/audit.log {
daily
rotate 7
compress
delaycompress
missingok
notifempty
create 0640 root root
postrotate
/usr/sbin/service auditd reload > /dev/null 2>&1 || true
endscript
}
Explanation
| Directive | Meaning |
|---|---|
daily |
Rotate every day. |
rotate 7 |
Keep seven rotated files (audit.log.1 … audit.log.7). |
compress |
gzip the old logs. |
delaycompress |
Compress only after the next rotation, so the most recent rotated file is still readable. |
missingok |
Do nothing if the log is missing. |
notifempty |
Skip rotation if the log is empty. |
create 0640 root root |
Create a fresh log with the right permissions. |
postrotate |
Tell auditd to reload its configuration after rotation; this forces it to close the old file and open a new one. |
The postrotate block is critical. Without it, auditd would keep writing to the old file until the next reboot, causing the rotated file to grow indefinitely.
5. Trade‑offs and tuning
| Aspect | Benefit | Caveat |
|---|---|---|
| Single rule | Minimal audit traffic; easier to maintain. | If you later need to audit other binaries, you’ll need additional rules. |
execve syscall |
Captures the exact command line and arguments. | Does not capture environment variables or shell expansions. |
| Rotation daily | Keeps logs small; quick recovery. | If your system runs many sudo commands per day, you might want to rotate hourly. |
| Compression | Saves disk space. | Decompression adds a small CPU cost when reading old logs. |
| Auditd reload | Ensures auditd writes to the new file immediately. | If auditd is misconfigured, the reload may fail silently. |
If you notice a performance hit, check the auditd kernel buffer size (auditctl -s). The default is usually fine for typical workloads. For high‑throughput environments, consider tuning max_log_file_action to keep_logs or rotate in /etc/audit/auditd.conf.
6. Common troubleshooting steps
| Symptom | Check | Fix |
|---|---|---|
No events appear in ausearch |
Is auditd running? | systemctl start auditd |
| Rule not loaded | Did you reload? | sudo augenrules --load |
| Audit log missing | Did you create the logrotate file? | Ensure the file exists and has correct syntax. |
| Audit log grows too fast | Are you rotating too infrequently? | Adjust daily to hourly or increase rotate. |
| Audit log permissions wrong | Did you set create 0640? |
Run chmod 0640 /var/log/audit/audit.log and chown root:root /var/log/audit/audit.log. |
See also
- When /usr Shows 100 % Used but df Says Space Is Fine: Spotting Inode Exhaustion
- When /tmp fills a 1‑GB VPS in 15 minutes – how a simple tmpfs mount stops crashes
- When systemd‑resolved ignores /etc/hosts: a quick fix for local hostname resolution
- How to use journalctl to pinpoint why a scheduled rsync job stalls during authentication
- Fixing GNOME’s broken audio output after an ALSA upgrade