auditd for people who mostly run Windows
On a network that runs mostly Windows, the Linux servers tend to be the quietest machines in the SIEM. The authentication log arrives — who logged on over SSH, who ran sudo — and very little else. The equivalent of process creation, account changes and persistence events exists on Linux too, in the kernel’s audit subsystem. It is just not configured by default.
This article is a short auditd baseline for readers who know the Windows side better. It maps what you already collect on Windows to Linux, explains each rule in linux-auditd-baseline.rules, and shows how to check what a server records. It follows the audit policy and Sysmon articles in this series.
What you need before you start
- The audit package:
auditdon Debian and Ubuntu,auditon Red Hat family systems. It is installed by default on many server distributions;auditctl -stells you whether it runs. - Root on a test server that runs your typical workload.
- A collector for
/var/log/audit/audit.log. Most SIEM agents have an audit log input. Check whether yours reads the file or talks to the kernel directly: two consumers of the kernel audit stream can conflict, and the documentation of your agent says which mode it uses.
Windows terms, Linux terms
| On Windows you collect | On Linux the closest source is |
|---|---|
4624/4625 logons |
/var/log/auth.log or /var/log/secure, and auditd USER_LOGIN / USER_AUTH records |
4688 process creation |
auditd rules on the execve system call |
4720, 4738, 4728 account and group changes |
auditd watches on /etc/passwd, /etc/shadow, /etc/group |
4698 scheduled task created |
watches on cron files and systemd unit directories |
4697 service installed |
watches on /etc/systemd/system/ |
| Sysmon event 6, driver loaded | auditd rules on init_module / finit_module |
The rest of the article explains the rules that produce these.
How auditd rules work, briefly
Rules live in files under /etc/audit/rules.d/. augenrules compiles them into /etc/audit/audit.rules, and augenrules --load loads the result into the kernel. There are two kinds of rule that matter here:
- File watches (
-w path -p wa -k key): record writes (w) and attribute changes (a) to a file, or anything under a directory. - System call rules (
-a always,exit -F arch=b64 -S syscall -F filter -k key): record a system call when the filters match.
Every rule has a key (-k). Keys are how you search later — ausearch -k identity — and how your SIEM rules will filter, so name them for what they mean, not for the file they watch. The full syntax is in audit.rules(7).
The baseline, rule by rule
Identity and privileges
Watches on /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow, /etc/sudoers and /etc/sudoers.d/, keys identity and sudoers. Any account, password, group or sudo rights change writes one of these files, whether it was done with useradd, usermod, visudo or an editor.
Remote access and persistence
Watches on the SSH server configuration, on /etc/crontab, /etc/cron.d/ and /var/spool/cron/, on /etc/systemd/system/ (where new or overridden services land), and on /etc/ld.so.preload, which makes every program load a library — rarely used legitimately, and a known persistence method. Keys sshd, cron, systemd and preload.
The audit configuration itself
A watch on /etc/audit/, key auditconfig. Changing the rules to stop recording is the obvious first move for someone who notices them.
Kernel modules
init_module, finit_module and delete_module system calls, key modules. Loading a kernel module is rare on a stable server, and a malicious module is one of the hardest things to find afterwards.
Commands run by people
execve for processes with an audit user ID (auid) of 1000 or more, excluding the unset value 4294967295, key exec_user. The audit user ID is set at login and survives sudo and su, so a command run as root through sudo is still attributed to the person who logged in. This is the closest equivalent to 4688 for interactive work, and its volume grows with how much people work on the server — usually modest.
Commands run by a service account
The rule above has a large blind spot: a web shell or an exploited application runs as the service account, outside any login session, with no audit user ID. The baseline adds execve for one effective user ID — 33, which is www-data on Debian and Ubuntu — key exec_service. ADAPT it to the account your internet-facing service runs as (id -u <user>). A web server account that starts sh, curl or python is one of the clearest signals you can collect on Linux.
What is deliberately not in the baseline
execvefor every process. Automation, monitoring and package managers start thousands of processes per hour. If you need it, add it per server role after measuring.- File reads. Watching reads of sensitive files (
-p r) is possible and very noisy on files that services read constantly, such as/etc/passwd. - Network system calls.
connectrules exist; a firewall or network sensor is usually a better source. - The immutable flag (
-e 2). It makes the rules unchangeable until reboot — good against tampering, painful while you are still tuning. Enable it last.
Checking what a server records
auditctl -s # enabled, failure mode, backlog, lost events
auditctl -l # rules loaded in the kernel right now
augenrules --check # do rules.d and audit.rules differ?
ausearch -k identity -i --start today
aureport -k --summary # events per key: where the volume is
auditctl -s shows a lost counter. If it grows, the kernel buffer (-b) is too small for the load, and events are being dropped. aureport -k --summary after a working day is the quickest way to see which rule produces most of the volume.
Testing that events arrive
- Identity:
sudo useradd ew-auditd-test, thensudo userdel ew-auditd-test. Expect events with keyidentity. - Commands: log in over SSH as a regular user and run
sudo id. Expectexec_userevents forsudoandid, with your user asauid. - Service account:
sudo -u www-data /bin/true(or the account you configured). Expect anexec_serviceevent. Note that this one also matchesexec_user, because you started it from your login session; a real web shell would only matchexec_service. - Find them in the SIEM by key, and check that the key field is parsed. A SIEM rule that filters on the key is far cheaper than one that searches raw audit text.
Limitations
- auditd records system calls and file changes. It does not inspect what a script does internally; a Python script that edits
/etc/shadowshows as a write bypython3, which is the correct and sometimes confusing answer. - A root user can stop auditd or change the rules unless
-e 2is set, and even then can reboot. Forwarding and a silent-source alert are the backstop. - Containers share the host kernel. Rules on the host see system calls from containers, but paths and user IDs are the container’s view, which makes attribution harder.
- We have not measured the volume on your servers.
aureport -k --summaryon a test server is how you measure it.
Adapting this to your environment
ADAPTauid>=1000if regular users start at a different UID (UID_MINin/etc/login.defs).ADAPTthe service account rule: one line per internet-facing service account, with its UID.ADAPTthe architecture lines: keeparch=b32on x86_64, remove it where 32-bit system calls do not exist.- Check for other files in
/etc/audit/rules.d/. Distributions and hardening tools add their own; keep one-D, one-band one-foverall.
The rules are linux-auditd-baseline.rules (MIT). Record the result for each server role in your log source inventory. If something here is wrong, write to hello@entropywatch.dev and we will correct it in the open.