Where to start First steps track · 15 stages
Linux Labs

auditd — security auditing

8 min Ubuntu 24.04 · auditd

Kernel-level auditing — who did what and when; watch rules and event search.

Cheat sheet

6 commands Printable version
  • sudo auditctl -w /etc/passwd -p wa -k passwd_changes watch a file
  • sudo auditctl -a always,exit -F arch=b64 -S execve -F euid=0 -k root_cmd
  • sudo auditctl -l current rules
  • sudo auditctl -s subsystem status
  • sudo ausearch -k passwd_changes -i by key, readable
  • sudo aureport --summary
  • permanent: /etc/audit/rules.d/*.rules → augenrules --load

Overview

auditd performs kernel-level auditing: who opened/changed a file, ran a command, changed permissions. It is a security and investigation (compliance) tool, not ordinary logging. Events go to /var/log/audit/audit.log; search with ausearch/aureport.

bash
sudo systemctl status auditd
sudo auditctl -s                  # enabled, backlog, losses

Configuration

The daemon itself is configured in /etc/audit/auditd.conf — not the same thing as audit rules (those live in rules.d, see "Recipes").

log_file = /var/log/audit/audit.log
max_log_file = 8                  # MB, rotation threshold
max_log_file_action = ROTATE     # ROTATE · KEEP_LOGS · SUSPEND · SYSLOG
num_logs = 5
space_left_action = SYSLOG        # what to do when disk space runs low
admin_space_left_action = SUSPEND

Apply changes:

bash
sudo systemctl restart auditd     # reread auditd.conf
sudo auditctl -s                  # subsystem healthy again, no losses

Important. max_log_file_action = SUSPEND and admin_space_left_action = SUSPEND stop recording events once the disk fills up — a compliance system would rather go silent than lose events unnoticed. For looser requirements use ROTATE/SYSLOG; the choice trades audit reliability against availability.

Recipes

4

Rules: watch and syscall

bash
# watch a file or dir: -p = r read, w write, x exec, a attr
sudo auditctl -w /etc/passwd -p wa -k passwd_changes
sudo auditctl -w /etc/sudoers -p wa -k sudoers
sudo auditctl -w /etc/ssh/sshd_config -p wa -k sshd_conf

# syscall rules (-a always,exit): catch actions
sudo auditctl -a always,exit -F arch=b64 -S execve -F euid=0 \
  -k root_cmd                     # root commands
sudo auditctl -a always,exit -F arch=b64 -S unlink,unlinkat \
  -F dir=/etc -k etc_delete

sudo auditctl -l                  # current rules
sudo auditctl -D                  # delete all (temporarily)
# permanent — /etc/audit/rules.d/*.rules + sudo augenrules --load
# lock rules against change until reboot: last rule -e 2 (immutable)

Searching events

bash
sudo ausearch -k passwd_changes           # by key (-k)
sudo ausearch -k passwd_changes -i        # -i: names, not numbers
sudo ausearch -f /etc/passwd -ts today    # by file, for today
sudo ausearch -ui 1000 -ts recent         # UID, last 10 minutes
sudo ausearch -m USER_LOGIN --start today # by event type (logins)
sudo aureport --summary                   # summary report
sudo aureport -au                         # authentication report
sudo aureport -f -i                       # file-event report

Reading an event

On the lab machine the auditd service is off: sudo systemctl enable --now auditd. The rule -w /etc/demo.conf -p wa -k democonf caught a write to the file from a cron job of the user deploy. One event is several records with a common number; the main ones are PROCTITLE and SYSCALL:

text
student@ubuntu:~$ sudo ausearch -k democonf -i \
> | grep -E '^type=(SYSCALL|PROCTITLE)'
type=PROCTITLE msg=audit(10/21/26 05:49:01.453:288) :
  proctitle=/bin/sh /usr/local/bin/tweak.sh
type=SYSCALL msg=audit(10/21/26 05:49:01.453:288) : arch=x86_64
  syscall=openat success=yes exit=3 … auid=deploy uid=deploy gid=deploy
  euid=deploy … tty=(none) ses=4 comm=tweak.sh exe=/usr/bin/dash
  subj=unconfined key=democonf
Field Meaning
auid who logged in — it does not change after sudo or su
uid, euid which user the process ran as at that moment
comm the process name (15 characters)
exe the executable; for a script it is the interpreter, dash here
proctitle the whole command line — for a script it holds the script's path
tty, ses the terminal and login session number; cron has no terminal
key the rule key from -k

The auid of a cron job is the crontab owner: cron opens a session for them through PAM (pam_loginuid). A write through sudo sh -c 'echo … >> /etc/demo.conf' gives uid=root, while auid is the user who logged in; processes without a login (services, commands through the guest agent) have auid=unset. The per-file summary is aureport -f -i:

text
# date time file syscall success exe auid event
1. 10/21/26 05:48:29 /etc/ openat yes /usr/bin/dash unset 279
2. 10/21/26 05:49:01 /etc/ openat yes /usr/bin/dash deploy 288

Permanent rules: rules.d

bash
echo '-w /etc/demo.conf -p wa -k democonf' \
  | sudo tee /etc/audit/rules.d/demo.rules
sudo augenrules --load
sudo auditctl -l

augenrules builds /etc/audit/audit.rules from all the rules.d/*.rules files and loads it into the kernel; auditd does the same at start. A rule written straight into audit.rules is gone after the next augenrules --load: the file is rebuilt, and auditctl -l does not list the rule. Only root can read audit.rules. augenrules --load prints the subsystem state (enabled 1, backlog …) — that is not an error.

Troubleshooting

6

Who changed an important file?

Set a watch (auditctl -w file -p wa -k label), then ausearch -k label -i → uid/command/time. For something that already happened (no watch was set), there are no events — auditing is not retroactive. That's why key watches are set in advance (in rules.d).

Too many events / noise / losses (lost)

auditctl -s shows lost/backlog. Write narrow rules (specific files/syscalls/keys), raise -b (backlog), and watch the size of /var/log/audit/ (its own rotation is in auditd.conf: max_log_file, num_logs).

Rules disappeared after a reboot

auditctl -w/-a rules are temporary. Permanent ones go in /etc/audit/rules.d/*.rules, applied with augenrules --load (or when auditd starts).

I can't change or delete rules

Immutable mode is on (-e 2) — rules are locked until reboot (by design, to protect against tampering).

auditd vs journald

journald handles operational service logs (journalctl); auditd handles who-did-what for security (an immutable trail). Different subsystems.

AppArmor denials are gone from journalctl -k

While auditd runs, kernel audit messages, apparmor="DENIED" included, go to it and are written to /var/log/audit/audit.log (type=AVC), and journalctl -k gets no new lines. Find them with sudo ausearch -m AVC -i (see apparmor).

Terms

1
audit rule
A line for auditd: which file or system call to watch and with which key to record the event — auditctl -w /etc/hosts -p wa -k hosts. Permanent rules live in /etc/audit/rules.d; ausearch -k finds events.

See also

  • journalctl — Reading the systemd journal (journald) — filters by service, time, priority.
  • permissions — The Unix permission model — read/write/execute, owner/group/other, special bits.
  • sudo — Running commands as root or another user; sudoers and NOPASSWD.
Loading…