Skip to content

auditd Basics

Every other tool in this module so far either grants access (sudo, PAM) or blocks it (firewalls, SELinux/AppArmor, fail2ban). auditd does neither — it watches, at the kernel level, and records exactly who did what, to which file or syscall, whether or not the action was actually permitted. When least privilege fails, when a sudo rule turns out to have been too broad, or when an incident response team needs to know precisely what a compromised account touched, auditd's log is often the only record detailed enough to answer the question.

What You Will Learn

By the end of this article you will be able to:

  • explain what the Linux Audit Framework records, and how it differs from ordinary syslog/journald logging;
  • write a persistent audit rule watching a specific file or syscall;
  • search recorded events with ausearch and summarize them with aureport;
  • explain why an audit rule alone doesn't stop anything, and how that's different from SELinux/AppArmor;
  • avoid the most common way auditd rules quietly stop taking effect.

What auditd Records That syslog Doesn't

Ordinary application logging — journalctl, /var/log/auth.log — records what an application chose to log, in whatever format that application's authors decided on. The Linux Audit Framework operates one level below that: it hooks directly into the kernel's syscall table, and can record events like "this specific file was opened for writing, by this UID, at this exact time, using this exact syscall" regardless of whether the application involved logs anything about it at all.

sudo systemctl status auditd
● auditd.service - Security Auditing Service
     Loaded: loaded (/lib/systemd/system/auditd.service; enabled)
     Active: active (running)

This is precisely why SELinux denials are recorded as AVC (Access Vector Cache) events in the audit log rather than in an application's own log file — the denial happens inside the kernel's security module, before the application ever gets a chance to log anything about the attempt at all. SELinux and AppArmor already used ausearch -m AVC for exactly this reason.

Writing a Rule

Rules can be added temporarily with auditctl, or persistently in /etc/audit/rules.d/audit.rules (recommended for anything meant to survive a reboot):

sudo nano /etc/audit/rules.d/audit.rules
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/sudoers -p wa -k sudoers_changes
  • -w <path> — watch this specific file or directory;
  • -p wa — which types of access trigger a record: w (write), a (attribute change, such as chmod/chown), r (read), x (execute);
  • -k <key> — a searchable label attached to every event this rule generates, making later searches (ausearch -k passwd_changes) far easier than grepping raw audit output.
sudo augenrules --load
No rules
enabled 1
failure 1

augenrules --load compiles every file under /etc/audit/rules.d/ into the running kernel ruleset — editing the rules file alone has no effect until this step (or a reboot) applies it.

Beyond watching a specific path, a rule can watch a syscall directly, which catches an action regardless of which specific file it targets:

-a always,exit -F arch=b64 -S execve -F auid>=1000 -F auid!=4294967295 -k user_commands

This records every program execution (execve) by a real, logged-in user (auid>=1000 excludes system accounts; auid!=4294967295 excludes processes with no login session at all, such as most system services) — effectively a system-wide record of every command a human account actually ran, independent of whether that command happened to touch a watched file.

auid versus uid

auid (audit UID, sometimes called "login UID") is set once at login and, critically, does not change when a user runs sudo or su — this is precisely what makes it possible to trace an action back to the original account that logged in, even after several privilege escalations. uid is the current effective user ID, which does change with sudo/su. A rule filtering on auid therefore survives privilege escalation in a way a uid filter wouldn't.

Searching Recorded Events: ausearch

sudo ausearch -k sudoers_changes
type=PATH msg=audit(1753776042.118:381): item=0 name="/etc/sudoers" inode=131094 dev=fd:00 mode=0100440 ouid=0 ogid=0 rdev=00:00
type=SYSCALL msg=audit(1753776042.118:381): arch=c000003e syscall=2 success=yes exit=3 a0=... auid=1000 uid=0 gid=0 euid=0

The auid=1000 field here, alongside uid=0, tells the real story even though the syscall itself ran with root privileges (uid=0, euid=0): whoever logged in as UID 1000 is the one who ultimately triggered this write to /etc/sudoers, most likely via sudo visudo.

sudo ausearch -k sudoers_changes -ts today -i

-ts today restricts the search to today's events; -i (interpret) translates raw numeric UIDs and syscall numbers into readable names where possible:

type=SYSCALL msg=audit(07/29/2026 09:41:02.118:381) : arch=x86_64 syscall=open success=yes exit=3 a0=... auid=deploy uid=root gid=root euid=root

Summarizing: aureport

For a higher-level view than individual event records, aureport aggregates:

sudo aureport -au --summary
Authentication Summary Report
================================
# total  success  failed
================================
142      138      4
sudo aureport -x --summary
Executable Summary Report
================================
# total  file
================================
84       /usr/bin/sudo
19       /usr/bin/su

aureport is the tool to reach for first when the question is "what's the overall pattern" rather than "show me every matching event" — ausearch for the latter, aureport for the former.

auditd Records; It Does Not Block

This is the single most important distinction between auditd and SELinux/AppArmor, and worth stating precisely: an audit rule watching /etc/shadow for writes generates a record every time it's written, but it does nothing to prevent the write itself. Blocking unauthorized access is DAC's and MAC's job (Least Privilege, SELinux and AppArmor); auditd's job is exclusively visibility — proving, after the fact, exactly what happened and who did it.

Interview angle: why record something you can't prevent

An interviewer might ask why a security team would bother recording an action instead of just blocking it outright. The answer: many legitimate actions need to remain possible — an administrator does need to be able to edit /etc/sudoers — and the value of an audit trail is in accountability and incident response, not prevention. When something does go wrong, "prevent everything" isn't achievable (a legitimate admin account can always be used maliciously by whoever controls it), but "know exactly what happened, in what order, by which account" is achievable, and that's what makes recovery and root-cause analysis possible at all.

A Rule That Isn't Actually Persistent

Rules added directly with auditctl -w ... apply immediately but vanish on reboot — a very easy trap, since the command appears to work and the rule is genuinely active right up until the next restart:

sudo auditctl -w /etc/shadow -p wa -k shadow_test
sudo auditctl -l
-w /etc/shadow -p wa -k shadow_test

This looks identical to a persistent rule in every way that matters right now — but only a rule written into a file under /etc/audit/rules.d/ and loaded with augenrules --load survives a reboot. auditctl is the right tool for quick, temporary testing; /etc/audit/rules.d/ is the right place for anything meant to remain in effect.

Practical Scenario: Who Modified /etc/sudoers

Problem. A sudoers rule that shouldn't exist was discovered during a routine review (the same scenario worked through in sudo Security). Auditd was already configured with a watch on /etc/sudoers, and the question now is who actually added it, and when.

Search the audit log for every recorded change:

sudo ausearch -k sudoers_changes -i
type=SYSCALL msg=audit(03/14/2026 11:02:17.442:2201) : ... auid=admin_jane uid=root exe=/usr/sbin/visudo

Conclusion. auid=admin_jane identifies the account that logged in and triggered the change — regardless of the fact that the syscall itself ran as uid=root through visudo — giving a specific person and timestamp to follow up with, rather than an anonymous "root did it" that every sudo-elevated action would otherwise look identical to.

Common Mistakes

  • Adding a rule with auditctl and assuming it's permanent. As covered above, only rules loaded from /etc/audit/rules.d/ via augenrules --load survive a reboot.
  • Filtering on uid instead of auid when trying to trace an action back to a person. uid changes with every sudo/su; auid doesn't, which is exactly what makes it useful for accountability.
  • Assuming an audit rule prevents anything. auditd only records; blocking a write requires DAC or MAC (file permissions, SELinux/AppArmor), a distinct and complementary control.
  • Watching too much, too broadly. A syscall-level rule with no filtering (-S execve with no auid restriction, for instance) generates enormous log volume on a busy server, making the genuinely important events harder to find rather than easier — scope rules to what actually needs accountability.

Exercises

  1. Add a persistent rule watching /etc/passwd for write and attribute-change events, load it with augenrules --load, make a trivial change (adding a comment with a text editor, for example), and confirm the event with ausearch.
  2. Explain, using a concrete example, why a rule filtering on auid is more useful for accountability than one filtering on uid.
  3. Run aureport -au --summary on a system with some authentication history and interpret the ratio of successful to failed attempts.
  4. Explain why auditd recording a security-relevant event and SELinux blocking it are not redundant with each other, even when both are triggered by the same underlying action.

Summary

auditd hooks into the kernel to record security-relevant events — file access, syscalls, authentication — independent of what any individual application chooses to log, and its auid field survives privilege escalation in a way ordinary uid tracking doesn't. ausearch finds specific recorded events and aureport summarizes patterns across many of them, but auditd itself never blocks anything — it is a visibility tool, not an access-control one, and rules only persist across a reboot when written to /etc/audit/rules.d/ rather than added ad hoc with auditctl. The next article, Permission Audit, turns the kind of periodic review this module keeps returning to — who has what access, and does it still match what's actually needed — into a repeatable process.

References