Skip to content

auditd

auditd is the Linux audit system: a kernel component that records system calls against rules, and a daemon that writes them to /var/log/audit/audit.log. It's the closest thing Linux has to the Windows Security log, and on most images it isn't installed. The whole section is Level 2 in the benchmark (CIS 6.2.x); it's still worth doing, because it's what makes the Reading the Logs page answer questions.

Install and enable

sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo auditctl -s

auditctl -s shows enabled 1 when it's working (CIS 6.2.1.1, 6.2.1.2). The Bootloader page adds audit=1 and audit_backlog_limit=8192 to the kernel line so events before the daemon starts are kept (6.2.1.3, 6.2.1.4).

auditd.conf

/etc/audit/auditd.conf controls the log files and what happens when they fill. The dangerous values are the ones that quietly stop logging.

Setting Value Why
max_log_file 32 (MB) or more (CIS 6.2.2.1) Room per file
num_logs 5 or more How many files are kept
max_log_file_action keep_logs (CIS 6.2.2.2) or ROTATE; never IGNORE When a file fills, start a new one and keep the old ones. keep_logs never deletes; ROTATE keeps num_logs.
space_left_action email or syslog (CIS 6.2.2.4; never ignore) Warn when the disk is getting full
admin_space_left_action single or halt (CIS 6.2.2.4) Drop to single-user mode when it's nearly full; a hardened machine would rather stop than run unlogged
disk_full_action halt or single (CIS 6.2.2.3; never ignore) Same when it is full
disk_error_action syslog, single, or halt (CIS 6.2.2.3)
action_mail_acct root, or an administrator named in the README (never nobody) Who gets the email
log_format ENRICHED Usernames are resolved in the log
F=/etc/audit/auditd.conf
sudo sed -i -E 's/^max_log_file_action.*/max_log_file_action = keep_logs/; s/^space_left_action.*/space_left_action = email/; s/^admin_space_left_action.*/admin_space_left_action = single/; s/^disk_full_action.*/disk_full_action = halt/; s/^disk_error_action.*/disk_error_action = halt/; s/^action_mail_acct.*/action_mail_acct = root/; s/^num_logs.*/num_logs = 5/; s/^max_log_file .*/max_log_file = 32/' $F

Rules

Rules live in /etc/audit/rules.d/*.rules and are compiled into /etc/audit/audit.rules by augenrules --load. There are two shapes, and once you can read them you can write any rule the benchmark asks for.

A file watch logs writes and attribute changes to one path:

-w /etc/sudoers -p wa -k scope

-w the path, -p wa the permissions to watch (w write, a attribute change, r read, x execute), -k a key you choose so you can search for it later with ausearch -k scope.

A syscall rule logs a system call when its conditions match:

-a always,exit -F arch=b64 -S execve -C euid!=uid -F auid!=unset -k user_emulation

-a always,exit means log it after the call returns. -F arch=b64 is the CPU architecture (on a 64-bit kernel each rule wants a matching arch=b32 twin, because a 32-bit program uses a different syscall table). -S the syscall names. -F and -C are filters: auid>=1000 restricts to real users, auid!=unset skips system processes, -C euid!=uid compares two fields (this one means "running as someone other than who logged in", which is sudo or su). -F path=… -F perm=x on a syscall rule watches execution of one binary.

Start a file, sudo nano /etc/audit/rules.d/50-hardening.rules, and write the rules for the table below. Do the file watches first; they're the shape you'll use most. For the syscall rules, write the b64 line, then copy it and change b64 to b32.

What to log CIS Type Targets Key
Account and group changes 6.2.3.8 watch, -p wa /etc/passwd, /etc/shadow, /etc/group, /etc/gshadow, /etc/security/opasswd, /etc/nsswitch.conf, /etc/pam.conf, /etc/pam.d identity
Changes to who can sudo 6.2.3.1 watch /etc/sudoers, /etc/sudoers.d scope
Commands run as another user 6.2.3.2 syscall execve with -C euid!=uid -F auid!=unset user_emulation
Changes to the sudo log 6.2.3.3 watch /var/log/sudo.log sudo_log_file
Sessions and logins 6.2.3.11, 6.2.3.12 watch /var/run/utmp, /var/log/wtmp, /var/log/btmp, /var/log/lastlog, /var/run/faillock, /var/log/faillog session for the first three, logins for the rest
Permission and owner changes 6.2.3.9 syscall chmod,fchmod,fchmodat,chown,fchown,fchownat,lchown,setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr with -F auid>=1000 -F auid!=unset perm_mod
Failed file access 6.2.3.7 syscall creat,open,openat,truncate,ftruncate with -F exit=-EACCES (and a second pair with -F exit=-EPERM), auid>=1000, auid!=unset access
Deletions 6.2.3.13 syscall rename,unlink,unlinkat,renameat, auid>=1000, auid!=unset delete
Mounts 6.2.3.10 syscall mount, auid>=1000, auid!=unset mounts
Privileged commands 6.2.3.6, 6.2.3.15 to 6.2.3.18; STIG UBTU-22-654010 to 654125 -a always,exit -F path=<binary> -F perm=x -F auid>=1000 -F auid!=unset /usr/bin/chcon, /usr/bin/setfacl, /usr/bin/chacl, /usr/sbin/apparmor_parser, /usr/sbin/usermod, /usr/bin/chage, /usr/bin/chfn, /usr/bin/chsh, /usr/bin/crontab, /usr/sbin/fdisk, /usr/bin/gpasswd, /usr/bin/mount, /usr/bin/umount, /usr/bin/newgrp, /usr/sbin/pam_timestamp_check, /usr/bin/passwd, /usr/bin/ssh-agent, /usr/lib/openssh/ssh-keysign, /usr/bin/su, /usr/bin/sudo, /usr/bin/sudoedit, /usr/sbin/unix_update privileged (or one key per command, as the STIG does)
AppArmor policy 6.2.3.14 watch /etc/apparmor, /etc/apparmor.d MAC-policy
The files you hardened watch /etc/ssh/sshd_config, /etc/ssh/sshd_config.d, /etc/pam.d, /etc/security, /etc/login.defs, /etc/sysctl.conf, /etc/sysctl.d, /etc/cron.d, /etc/crontab, /var/spool/cron, /etc/systemd/system your choice
Journal STIG UBTU-22-654190 watch /var/log/journal systemd_journal
Kernel modules 6.2.3.19; STIG UBTU-22-654055, 654060 syscall init_module,finit_module,delete_module,create_module,query_module, auid>=1000, auid!=unset; plus a path=/usr/bin/kmod -F perm=x rule kernel_modules
Time changes 6.2.3.4 syscall adjtimex,settimeofday,clock_settime; watch /etc/localtime time-change
Network identity 6.2.3.5 syscall sethostname,setdomainname; watch /etc/issue, /etc/issue.net, /etc/hosts, /etc/hostname, /etc/networks, /etc/network, /etc/netplan system-locale
The audit config itself watch /etc/audit, /var/log/audit auditconfig, auditlog

The full benchmark rule for privileged commands generates a line for every setuid and setgid binary on the system: sudo find / -perm /6000 -type f lists them, and a short shell loop that prints a -a always,exit -F path= line for each is a good first script to write.

Load and check:

sudo augenrules --load
sudo auditctl -l | wc -l
sudo auditctl -l | grep identity

The last one prints your file watches back in the kernel's own spelling:

-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity

A rule the kernel rejected is reported by augenrules --load with the file and line number; a typo in a syscall name is the usual cause.

Making the rules immutable (-e 2 as the last line of the last rules file, CIS 6.2.3.20) means nothing can change them until reboot; do that at the end if the README doesn't need auditing changed later. augenrules --check confirms the loaded rules match the files on disk (6.2.3.21).

Protect the audit files

The log, the config, and the tools themselves have permissions the benchmark checks (CIS 6.2.4.1 to 6.2.4.10):

sudo chmod 750 /var/log/audit; sudo chown root:root /var/log/audit
sudo find /var/log/audit -type f -exec chmod 640 {} +; sudo chown root:root /var/log/audit/*
sudo chmod 640 /etc/audit/auditd.conf /etc/audit/audit.rules /etc/audit/rules.d/*.rules; sudo chown root:root /etc/audit/*.conf /etc/audit/*.rules /etc/audit/rules.d/*
sudo chmod 755 /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/augenrules; sudo chown root:root /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/augenrules

Verify

systemctl is-active auditd
sudo auditctl -s | grep enabled
sudo auditctl -l | grep -c user_emulation          # 2
grep -E '^(max_log_file_action|disk_full_action|action_mail_acct)' /etc/audit/auditd.conf
sudo ausearch -k user_emulation --start today | tail -n 5

Example

systemctl is-active auditd says inactive: not installed. Install it. auditd.conf (from a previous install) has max_log_file_action = IGNORE, disk_full_action = ignore, action_mail_acct = nobody. Fix all three, write the rules file, augenrules --load. ausearch -k user_emulation a minute later shows your own sudo commands, which is the proof it works.

Try it

  1. Write the five identity file watches by hand, load them, edit /etc/passwd with nano (change nothing), and find the event with ausearch -k identity.
  2. Write the user_emulation syscall rule, run sudo true, and find it.

Build it

Your rules file, written from the table, is the tool. Add a rules-check.sh that runs augenrules --check, auditctl -l | wc -l, and ausearch -k user_emulation --start today | tail.

Next

Reading the Logs