How to make sudo leave a trace: a single auditd rule and logrotate config

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