Skip to content

auditd: Audit Framework & Security Logging

Chapter 19: auditd: Audit Framework & Security Logging

Section titled “Chapter 19: auditd: Audit Framework & Security Logging”
  • Understand the Linux audit framework architecture
  • Configure auditd for compliance (PCI-DSS, HIPAA, SOX)
  • Write effective audit rules
  • Search and analyze audit logs with ausearch and aureport

ACLs (Access Control Lists) allow for complex file permissions (like giving exactly three specific users access to a file). Auditd is the system’s security camera—it records a detailed, tamper-proof log of exactly who touched what and when.

Audit Architecture
───────────────────
┌──────────────────────────────────────────────────────┐
│ KERNEL │
│ │
│ Audit Subsystem (CONFIG_AUDIT=y) │
│ Hooks into: │
│ • System calls │
│ • File access │
│ • Network events │
│ • User/group changes │
│ • SELinux AVC events │
│ │
└──────────────────────────┬───────────────────────────┘
│ Kernel → netlink socket
┌──────────────────────────────────────────────────────┐
│ auditd (user-space daemon) │
│ PID 1 of audit subsystem │
│ Receives kernel audit events │
│ Writes to: /var/log/audit/audit.log │
│ Can forward to: syslog, remote server (audisp) │
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────────────────┐
│ Analysis Tools: │
│ ausearch — search audit records │
│ aureport — generate reports │
│ sealert — analyze SELinux events │
└──────────────────────────────────────────────────────┘

Terminal window
# ── Install and Start ─────────────────────────────────────
apt-get install auditd # Debian/Ubuntu
yum install audit # RHEL/CentOS
systemctl enable --now auditd
# ── Main Configuration ────────────────────────────────────
cat /etc/audit/auditd.conf
/etc/audit/auditd.conf
log_file = /var/log/audit/audit.log
log_format = ENRICHED # Include extra info (user, hostname)
log_group = root
priority_boost = 4 # Higher scheduling priority for auditd
flush = INCREMENTAL_ASYNC # Async flush for performance
freq = 50 # Flush every 50 records
max_log_file = 50 # Max log file size (MB)
max_log_file_action = ROTATE # Rotate when max reached (or SYSLOG/SUSPEND)
num_logs = 10 # Keep 10 rotated log files
space_left = 250 # Alert when 250MB free
space_left_action = SYSLOG # Log warning when space low
admin_space_left = 50 # Emergency threshold
admin_space_left_action = SUSPEND # Stop audit if < 50MB (or HALT for compliance)
disk_full_action = SUSPEND
disk_error_action = SYSLOG

Audit rules tell the kernel WHAT to monitor.

Terminal window
# ── Rule Types ────────────────────────────────────────────
# -a: Add a rule
# -d: Delete a rule
# -w: Watch a file or directory
# -D: Delete all rules
# Syntax:
# -a [list],[action] -F [field=value] -S [syscall] -k [key]
# Lists:
# exit: rules evaluated at syscall exit
# entry: rules evaluated at syscall entry
# always: always audit
# Actions:
# always: always create audit record
# never: never create audit record
Terminal window
# ── Watch Critical Files ──────────────────────────────────
# -w: watch a file
# -p: permissions to watch (r=read, w=write, x=execute, a=attribute change)
# -k: key (tag for search)
# Watch password files (compliance requirement)
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers_changes
-w /etc/sudoers.d/ -p wa -k sudoers_changes
# Watch SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd_config
# Watch audit configuration itself (detect tampering)
-w /etc/audit/audit.rules -p wa -k audit_rules
-w /etc/audit/auditd.conf -p wa -k audit_config
# Watch cron jobs (privilege escalation vector)
-w /etc/cron.d/ -p wa -k cron
-w /etc/cron.daily/ -p wa -k cron
-w /etc/crontab -p wa -k cron
# ── Syscall Rules ─────────────────────────────────────────
# Monitor privileged command execution
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k privileged_exec
# Monitor setuid/setgid programs
-a always,exit -F arch=b64 -S execve -C uid!=euid -F euid=0 -k setuid_execution
# Monitor privilege escalation
-a always,exit -F arch=b64 -S setuid -S setgid -S setresuid -S setresgid -k priv_esc
# Monitor file deletions by users
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -k file_deletion
# Monitor system time changes (PCI-DSS requirement)
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time_change
-w /etc/localtime -p wa -k time_change
# Monitor kernel module loading/unloading
-a always,exit -F arch=b64 -S init_module -S finit_module -S delete_module -k kernel_modules
# Monitor network configuration changes
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system_locale
# Monitor mount operations
-a always,exit -F arch=b64 -S mount -F auid>=1000 -k mounts
# Monitor failed file access (intrusion detection)
-a always,exit -F arch=b64 -S open -F dir=/etc -F exit=-EACCES -k access_denied
-a always,exit -F arch=b64 -S open -F dir=/etc -F exit=-EPERM -k access_denied
# Lock audit rules (prevent tampering at runtime)
# MUST be the LAST rule (cannot change rules after -e 2):
-e 2 # Makes rules immutable until reboot
Terminal window
# ── Apply Rules ───────────────────────────────────────────
# Rules file location
# /etc/audit/rules.d/99-audit.rules (drop-in rules)
# /etc/audit/audit.rules (generated by augenrules)
# Generate combined rules file from rules.d/
augenrules --load
# Apply rules without restarting auditd
auditctl -R /etc/audit/audit.rules
# View current active rules
auditctl -l
# Check rule status
auditctl -s

Terminal window
# ── ausearch: Search Audit Records ───────────────────────
# Basic search
ausearch -k identity # By key tag
ausearch -k identity -ts today # Today only
ausearch -k identity -ts "2024-01-15" --until "2024-01-16"
# Search by event type
ausearch -m USER_LOGIN # Login events
ausearch -m USER_AUTH -sv no # Failed auth attempts
# Search by user
ausearch -ua root # Events from UID=root
ausearch -ua 1000 # Events from UID=1000
ausearch -n alice # Events from user 'alice'
# Search by file
ausearch -f /etc/passwd # Events touching /etc/passwd
# Interpret output (human-readable)
ausearch -k identity -ts today -i # -i = interpret (show names not IDs)
ausearch -m EXECVE -ts recent -i | head -40
# ── Output Formats ────────────────────────────────────────
ausearch -k identity -ts today --format text # Text summary
ausearch -k identity -ts today --format csv # CSV for spreadsheet
ausearch -k identity -ts today --format json # JSON for SIEM
# ── aureport: Generate Reports ────────────────────────────
aureport # Summary report
aureport --login # Login report
aureport --auth # Authentication report
aureport --failed # Failed events
aureport --user # User events
aureport --executable # Executable events
aureport --anomaly # Anomalous events (login failures etc.)
# Summary for the last day
aureport --start today --end now --summary
# Login failures report
aureport --login --failed --start this-month
# Who escalated privileges
aureport --tty --start this-week

Audit Log Record Anatomy
─────────────────────────
type=SYSCALL msg=audit(1705312800.123:456): arch=c000003e syscall=2
success=yes exit=3 a0=7f1234 a1=0 a2=0 a3=0 items=1
ppid=1234 pid=5678 auid=1000 uid=33 gid=33 euid=33 suid=33
fsuid=33 egid=33 sgid=33 fsgid=33 tty=(none) ses=7
comm="nginx" exe="/usr/sbin/nginx"
subj=system_u:system_r:httpd_t:s0
key="identity"
Breaking it down:
─────────────────
type=SYSCALL → Event type (SYSCALL, PATH, EXECVE, etc.)
audit(timestamp:serial)→ Event timestamp and serial number
arch=c000003e → Architecture (c000003e = x86_64)
syscall=2 → System call number (2 = open on x86_64)
success=yes → Did the syscall succeed?
exit=3 → Return value (3 = fd number)
auid=1000 → Audit UID (the real user who started the session)
uid=33 gid=33 → Current UID/GID (may differ if setuid)
comm="nginx" → Command name
exe="/usr/sbin/nginx" → Full path of executable
subj=...httpd_t... → SELinux context
key="identity" → Audit rule key that matched
Related records (same serial number):
type=PATH → File that was accessed
type=EXECVE → Command and arguments (when exec'ing)
type=CWD → Working directory

Terminal window
# PCI-DSS 10.2 — Log all access to cardholder data
-a always,exit -F arch=b64 -S open -F dir=/var/data/pci -k pci_data_access
# PCI-DSS 10.2.1 — Individual user actions
-a always,exit -F arch=b64 -S execve -F auid>=1000 -k user_exec
# PCI-DSS 10.2.2 — Root/admin actions
-a always,exit -F arch=b64 -S execve -F uid=0 -k root_exec
# PCI-DSS 10.2.4 — Invalid logical access
-a always,exit -F arch=b64 -S open -F exit=-EACCES -k access_denied
-a always,exit -F arch=b64 -S open -F exit=-EPERM -k access_denied
# PCI-DSS 10.2.5 — Identification/authentication
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
# PCI-DSS 10.2.6 — Audit log initialization
-w /var/log/audit/ -p wa -k audit_log
# PCI-DSS 10.2.7 — System-level object creation/deletion
-a always,exit -F arch=b64 -S mkdir -S rmdir -F auid>=1000 -k dir_operations
/etc/audisp/plugins.d/au-remote.conf
# Forward audit logs to central SIEM (audisp-remote)
active = yes
direction = out
path = /sbin/audisp-remote
type = always
# /etc/audisp/audisp-remote.conf
remote_server = siem.example.com
port = 60
transport = tcp # Or use TLS: transport = tls
# Restart
service auditd restart

Terminal window
# Scenario: Investigate whether a user ran commands as root
# Find all sudo usage
ausearch -m USER_CMD -ts today -i | grep -v "type=PROCTITLE"
# Find all failed sudo attempts
ausearch -m USER_AUTH -sv no -ts today -i
# Find all files touched by a specific user
ausearch -ua 1001 -ts "last week" -i | grep "type=PATH"
# Find commands run in a specific time window
ausearch -m EXECVE -ts "2024-01-15 10:00:00" --until "2024-01-15 10:30:00" -i
# Find if /etc/shadow was accessed
ausearch -f /etc/shadow -ts this-year -i
# Generate timeline of events for a user session
ausearch -ua 1001 -ts "2024-01-15 09:00:00" --until "2024-01-15 11:00:00" \
--format text | sort -k1

Q1: What is the difference between -w and -a audit rules?

Answer: -w (watch) creates a filesystem watch rule for a specific file or directory. It automatically generates rules for read, write, execute, and attribute changes. Example: -w /etc/passwd -p wa -k identity watches /etc/passwd for writes and attribute changes. -a (always) is more powerful — it specifies explicit system call rules with filters. Example: -a always,exit -F arch=b64 -S execve -F uid=0 -k root_exec audits all exec syscalls made by UID=0. -a rules allow filtering by UID, GID, success/failure, return value, arguments, etc. For compliance, you typically use -w for file monitoring and -a for syscall monitoring.

Q2: What does -e 2 mean in audit rules and why is it important?

Answer: -e 2 makes audit rules immutable — no rules can be added, removed, or modified until the system reboots. This is critical for compliance (PCI-DSS, SOX): if an attacker compromises root, they cannot tamper with audit rules to hide their tracks. Without -e 2, a root-level attacker could run auditctl -D (delete all rules) before performing malicious actions. Always put -e 2 as the LAST line in your audit rules file because once set, you cannot modify rules without rebooting.


ComponentPurpose
auditdDaemon that receives and stores audit events
audit rules (-w)Watch files for changes
audit rules (-a)Filter syscalls to audit
ausearchSearch audit log by key, user, event
aureportGenerate summary reports
audispForward events to remote servers
-e 2Make rules immutable

Chapter 14 (Security Fundamentals).


Advantages: ACLs allow fine-grained access, auditd provides tamper-proof compliance logs. Disadvantages: Auditd can consume massive disk space and CPU if rules are too broad.


  • Using standard chmod and breaking ACLs.
  • Overloading auditd with too many rules, filling the disk.

SymptomCauseDiagnosisFix
Can’t access file despite group membershipACL overrides or mask is too restrictivegetfacl filenamesetfacl to correct permissions
Auditd dropping eventsBuffer full or disk slowausearch -m DAEMON_ERRIncrease disp_qos or backlog limit in audit.rules

Objective: Manage ACLs and audit rules.

Terminal window
# 1. Set and get an ACL
touch testfile
setfacl -m u:nobody:r testfile
getfacl testfile
ls -l testfile # Notice the '+' sign
# 2. Add an audit rule to watch a file
auditctl -w /etc/passwd -p wa -k passwd_changes
# 3. Search audit logs
ausearch -k passwd_changes

  1. Set up a directory where user A has read-write access, user B has read-only access, and group C has no access, using ACLs.
  2. Configure auditd to track all execve system calls made by a specific user (by UID).

  • ACLs provide finer-grained permissions than standard user/group/others.
  • auditd is the kernel-level auditing system for tracking security-relevant events.
  • Use ausearch and aureport to query audit logs effectively.

  • man acl, man setfacl
  • man auditd, man auditctl


Last Updated: July 2026