Skip to content
shellhacks.dev
Security

How to Use Linux Audit Rules for Sensitive Files Safely

Use Linux audit rules with auditd to record who touches sensitive files: write watch rules, load them, search with ausearch and avoid noisy rules.

6 min read
Summarize in AI
Illustration for "How to Use Linux Audit Rules for Sensitive Files Safely": a terminal session, a scrolling log, file permission bits.

When a file changes unexpectedly, the question is always who did it. File integrity tools such as AIDE say that it changed; the audit system says which process and which user did it, and when. It is built into the kernel and configured with a short rules file. This post gives the rules worth having, and the search commands, in the context of checking who changed a file. The commands assume auditd 3.1 on Debian 13.

Install and add rules

Shell
sudo apt install auditd
sudo systemctl enable --now auditd
/etc/audit/rules.d/50-sensitive.rulesText
# identity and authentication
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers

# remote access
-w /etc/ssh/sshd_config -p wa -k sshd
-w /etc/ssh/sshd_config.d/ -p wa -k sshd

# scheduled jobs
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /var/spool/cron/ -p wa -k cron

# time changes
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time-change
Shell
sudo augenrules --load
sudo auditctl -l

A watch rule has a path (-w), the kinds of access to log (-p with r read, w write, x execute, a attribute change) and a key (-k) that tags the events. Watching wa logs modification and permission changes, which is what you care about for configuration files. Reading is too noisy for most files: /etc/passwd is read constantly by every login and ls. The last rule is a syscall rule that records time changes, a classic anti-forensics step.

Shell
sudo touch /etc/sudoers.d/test
sudo ausearch -k sudoers -i --start recent
Text
type=SYSCALL msg=audit(11/03/2026 10:14:02.311:512) : arch=x86_64 syscall=openat success=yes exit=3 a0=AT_FDCWD a1=0x7ffc... items=2 ppid=2210 pid=2231 auid=ada uid=root gid=root euid=root comm=touch exe=/usr/bin/touch key=sudoers
type=PATH msg=audit(11/03/2026 10:14:02.311:512) : item=1 name=/etc/sudoers.d/test inode=1048693 ... nametype=CREATE

-i turns numeric IDs into names. The field that answers "who" is auid, the audit user ID, which stays as the original login user across sudo: here the process ran as root, but auid=ada shows who logged in. The summary tools give an overview: sudo aureport --key --summary counts events per key and sudo aureport -f -i --start today lists file events.

Keep the volume manageable

Every event is a few lines of log, and busy systems write a lot. Keep rules specific: watch configuration files and directories, not /var/log or home directories. Exclude noisy processes with exclusion rules, for example -a never,exit -F exe=/usr/bin/rsync placed before the matching rule. Set rotation in /etc/audit/auditd.conf (max_log_file, num_logs), and ship the logs off the host so a compromise cannot erase them; see centralizing logs. Check auditctl -s for the lost-events counter: a non-zero lost means the buffer overflowed.

Make the rules tamper-resistant

/etc/audit/rules.d/99-finalize.rulesText
-e 2

With -e 2 at the very end of the last rules file, the configuration is locked: not even root can change the rules until the next reboot. That protects the audit setup from an intruder, and it means you reboot to change a rule, so enable it only after the rules are tested.

Where this does not apply

Auditing every file read or every command execution on a busy server is expensive in CPU and disk; use targeted rules. Audit logs show kernel-level events, not what happened inside an application. In containers, the audit subsystem belongs to the host. For alerting, forward events to a monitoring system and alert on specific keys, as in basic alerting.

What audit watches versus what logs record

The Linux audit system lives in the kernel, and auditd writes its events to a log. Where ordinary logs record what programs choose to say, audit records what the kernel observed: a file opened for writing, a system call made, a user ID changed. Rules tell the kernel what to record. A file watch rule, written -w /etc/passwd -p wa -k identity, records writes and attribute changes to that path and tags the events with a key, so searching later is easy. A syscall rule, such as one on execve for commands run by logged-in users, records activity regardless of file. Each event carries who did it, using the login user ID, which stays the same across sudo and su, so you can tell which person was behind a command run as root. That identity field is the main reason audit is valued for accountability and for investigating incidents after the fact.

A subtlety of path watches: they follow the file system object, so replacing a watched file by renaming a new one over it can escape the watch in some cases. Watch the directory too when that matters.

Searching and reading events

Raw audit records are dense lines of key and value pairs, and the tools exist to make them readable. ausearch -k identity with its interpret option finds events by key and turns numeric IDs into names, ausearch -ts today restricts by time, and aureport summarizes by category, such as authentication, anomalies and file events. A single action produces several records tied together by an event ID, one for the syscall, one for the path, one for the working directory, and the tools group them. Read the record for the process name and executable, the user's login ID and the result, success or failure. Failed attempts are often more interesting than successes, since they show someone trying something they were not allowed to do. Practice on a test machine by touching a watched file and finding the event, so the commands are familiar when you need them in earnest.

Keeping the volume manageable

An audit configuration with too many rules fills the disk and slows the machine, and a flood of records can overflow the kernel's buffer, which is controlled by the backlog setting. Choose rules that answer specific questions: changes to account and authentication files, changes to SSH and sudo configuration, loading of kernel modules, use of privileged commands, time changes and failed access to sensitive paths. Filter by user, so rules apply to real logins and not to system daemons, using a condition on the login user ID. Set the log size and rotation in auditd.conf, and decide what the daemon does when the disk is full, which for some compliance regimes is to halt the machine and for most deployments is to log a warning and continue. Ship the records to a central server, since local audit logs are a prime target for an intruder who wants to erase traces. Put rules in files under /etc/audit/rules.d/ and load them with augenrules, and consider the immutable setting -e 2 at the end, which locks the rules until a reboot, so an intruder cannot disable auditing without restarting the machine.

A useful starter rule set

A first set of rules that answers real questions is short. Watch writes and attribute changes on the account and authentication files, /etc/passwd, /etc/shadow, /etc/group and /etc/sudoers with its drop-in directory. Watch the SSH daemon configuration and the cron and systemd unit directories, since persistence usually passes through one of them. Record the loading and unloading of kernel modules and changes to the system clock, and log every command run as root by a person who logged in under another account. Give each rule a key that says what it protects, such as identity, sshd, persistence and time, so a search by key reads as a question you wanted to ask. Run the machine for a week, look at the volume, and tune the rules that produce noise by narrowing them to the paths and users that matter.

See auditctl(8) and ausearch(8).

Taggedlinux
Share

Keep reading

Get new posts by email

One email when a new post is published. No spam.

Unsubscribe in one click. No spam, ever.