Linux Audit System: Complete Guide to auditd and System Monitoring
The Linux Audit Framework is the kernel-level system that records security-relevant events on your system. Unlike application-level logging, audit events are generated by the kernel itself, making them extremely difficult for an attacker to tamper with or bypass. If someone modifies a critical file, executes a suspicious binary, changes user permissions, or attempts to access a resource they should not, the audit system captures it.
This guide covers the complete audit stack: configuring the auditd daemon, writing audit rules for real-world security scenarios, analyzing events with ausearch and aureport, integrating with SIEM platforms, and applying audit rules specifically for Docker environments.
Installing and Configuring auditd
The audit daemon is included in most enterprise Linux distributions. On Debian/Ubuntu systems, you need to install it explicitly:
# Debian/Ubuntu
sudo apt install auditd audispd-plugins
# RHEL/CentOS/Fedora (usually pre-installed)
sudo dnf install audit audit-libs
# Enable and start the daemon
sudo systemctl enable --now auditd
# Check status
sudo auditctl -s
# enabled 1
# failure 1
# pid 1234
# rate_limit 0
# backlog_limit 8192
# lost 0
# backlog 0
Core Configuration: auditd.conf
The main configuration file controls how audit logs are stored and rotated:
# /etc/audit/auditd.conf
log_file = /var/log/audit/audit.log
log_format = ENRICHED
log_group = adm
priority_boost = 4
flush = INCREMENTAL_ASYNC
freq = 50
num_logs = 10
max_log_file = 50
max_log_file_action = ROTATE
space_left = 75
space_left_action = SYSLOG
admin_space_left = 50
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND
tcp_listen_queue = 5
tcp_max_per_addr = 1
tcp_client_max_idle = 0
transport = TCP
krb5_principal = auditd
distribute_network = no
| Setting | Recommended Value | Purpose |
|---|---|---|
log_format |
ENRICHED | Resolves UIDs/GIDs to names in log entries |
flush |
INCREMENTAL_ASYNC | Balance between performance and data safety |
max_log_file |
50 (MB) | Rotate before files get unwieldy |
num_logs |
10 | Keep 10 rotated log files |
space_left_action |
SYSLOG | Alert when disk space is low |
disk_full_action |
SUSPEND | Stop logging rather than crash the system |
disk_full_action = HALT. This halts the system when audit logs can no longer be written, ensuring that no security events go unrecorded. This is extreme but may be required by your compliance framework.
Writing Audit Rules
Audit rules tell the kernel which events to record. There are three types: control rules (configure the audit system), file system rules (watch files/directories), and system call rules (monitor specific syscalls).
File and Directory Monitoring
# /etc/audit/rules.d/10-file-monitoring.rules
# Watch critical system files for any changes
-w /etc/passwd -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
# Watch SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd_config
-w /etc/ssh/ssh_config -p wa -k ssh_config
-w /root/.ssh/ -p wa -k root_ssh
# Watch cron configuration
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /var/spool/cron/ -p wa -k cron
# Watch system binaries for tampering
-w /usr/bin/ -p wa -k system_binaries
-w /usr/sbin/ -p wa -k system_binaries
-w /usr/local/bin/ -p wa -k local_binaries
-w /usr/local/sbin/ -p wa -k local_binaries
# Watch kernel modules
-w /etc/modprobe.d/ -p wa -k kernel_modules
-w /lib/modules/ -p wa -k kernel_modules
The -p flag specifies which permissions to watch: r (read), w (write), x (execute), a (attribute change). The -k flag assigns a key for easier searching.
System Call Auditing
# /etc/audit/rules.d/20-syscall-monitoring.rules
# Monitor process execution
-a always,exit -F arch=b64 -S execve -k exec
-a always,exit -F arch=b32 -S execve -k exec
# Monitor file deletion
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -k file_deletion
-a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -k file_deletion
# Monitor mount operations
-a always,exit -F arch=b64 -S mount -S umount2 -k mounts
-a always,exit -F arch=b32 -S mount -S umount -S umount2 -k mounts
# Monitor changes to system time
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -S clock_settime -k time_change
-a always,exit -F arch=b32 -S adjtimex -S settimeofday -S stime -S clock_settime -k time_change
-w /etc/localtime -p wa -k time_change
# Monitor network configuration changes
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k network_config
-a always,exit -F arch=b32 -S sethostname -S setdomainname -k network_config
-w /etc/hosts -p wa -k network_config
-w /etc/hostname -p wa -k network_config
-w /etc/resolv.conf -p wa -k network_config
# Monitor kernel module loading
-a always,exit -F arch=b64 -S init_module -S finit_module -S delete_module -k kernel_modules
-a always,exit -F arch=b32 -S init_module -S finit_module -S delete_module -k kernel_modules
User Activity Tracking
# /etc/audit/rules.d/30-user-monitoring.rules
# Monitor login/logout events
-w /var/log/lastlog -p wa -k logins
-w /var/log/faillog -p wa -k logins
-w /var/log/wtmp -p wa -k logins
-w /var/log/btmp -p wa -k logins
-w /var/run/utmp -p wa -k session
# Monitor privilege escalation
-a always,exit -F arch=b64 -S setuid -S setgid -S setreuid -S setregid -k privilege_escalation
-a always,exit -F arch=b32 -S setuid -S setgid -S setreuid -S setregid -k privilege_escalation
# Monitor sudo usage
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k sudo_commands
-a always,exit -F arch=b32 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k sudo_commands
# Monitor user/group management commands
-w /usr/sbin/useradd -p x -k user_management
-w /usr/sbin/userdel -p x -k user_management
-w /usr/sbin/usermod -p x -k user_management
-w /usr/sbin/groupadd -p x -k user_management
-w /usr/sbin/groupdel -p x -k user_management
-w /usr/sbin/groupmod -p x -k user_management
Loading and Managing Rules
# Load rules from files
sudo augenrules --load
# Or load a specific rule temporarily
sudo auditctl -w /etc/myapp.conf -p wa -k myapp_config
# List all active rules
sudo auditctl -l
# Delete all rules (for testing)
sudo auditctl -D
# Make rules immutable (cannot be changed without reboot)
# Add this as the LAST line in your rules
-e 2
-e 2 rule makes the audit configuration immutable until the next reboot. This prevents an attacker who gains root access from disabling audit logging. Always add this as the very last rule after all other rules are configured and tested.
Analyzing Audit Logs with ausearch
ausearch is the primary tool for querying audit logs. It understands the audit log format and provides powerful filtering:
# Search by key
sudo ausearch -k identity --start today
# Search by event type
sudo ausearch -m USER_LOGIN --start recent
# Search for failed events
sudo ausearch --success no --start today
# Search by user
sudo ausearch -ua 1000 --start this-week
# Search by file
sudo ausearch -f /etc/passwd --start today
# Search by time range
sudo ausearch --start 04/25/2025 08:00:00 --end 04/25/2025 17:00:00
# Search for specific syscall
sudo ausearch -sc execve --start today
# Interpret results (resolve UIDs, syscall numbers)
sudo ausearch -k exec --start today --interpret
Generating Reports with aureport
aureport generates summary reports from audit logs:
# Summary report
sudo aureport --summary
# Authentication report
sudo aureport --auth --start today
# Auth Report
# ============================================
# date time acct host term exe success event
# 04/25/25 08:12 root ssh pts/0 /usr/sbin/sshd yes 125
# Failed authentication report
sudo aureport --auth --failed --start this-week
# File access report
sudo aureport --file --start today
# Executable report (what was executed)
sudo aureport -x --start today
# User report
sudo aureport -u --start today
# System event anomalies
sudo aureport --anomaly
# Generate a report for a specific key
sudo ausearch -k identity --raw | aureport --file
Docker Audit Rules
Docker introduces unique audit requirements. The Docker daemon runs as root and controls container lifecycles, making it a critical target for monitoring:
# /etc/audit/rules.d/40-docker.rules
# Monitor Docker daemon configuration
-w /etc/docker/ -p wa -k docker_config
-w /etc/docker/daemon.json -p wa -k docker_config
-w /etc/default/docker -p wa -k docker_config
# Monitor Docker service files
-w /usr/lib/systemd/system/docker.service -p wa -k docker_service
-w /usr/lib/systemd/system/docker.socket -p wa -k docker_service
# Monitor Docker socket access
-w /var/run/docker.sock -p wa -k docker_socket
# Monitor Docker binary
-w /usr/bin/docker -p x -k docker_commands
-w /usr/bin/dockerd -p x -k docker_daemon
# Monitor container runtime
-w /usr/bin/runc -p x -k container_runtime
-w /usr/bin/containerd -p x -k container_runtime
-w /usr/bin/containerd-shim -p x -k container_runtime
# Monitor Docker data directory
-w /var/lib/docker/ -p wa -k docker_data
# Monitor Docker Compose files in common locations
-w /opt/docker/ -p wa -k docker_compose
-w /home/ -p wa -k home_changes
Performance note: Monitoring broad directories like
/var/lib/docker/with write watches can generate significant audit volume on busy Docker hosts. For production, consider monitoring only the configuration directories and using container-level monitoring tools for runtime activity.
SIEM Integration
Audit logs need to be shipped to a centralized log management system for correlation, alerting, and long-term retention. There are several approaches:
Using audisp-remote
# /etc/audisp/plugins.d/au-remote.conf
active = yes
direction = out
path = /sbin/audisp-remote
type = always
format = string
# /etc/audisp/audisp-remote.conf
remote_server = siem.example.com
port = 60
transport = tcp
queue_file = /var/spool/audit/remote.log
mode = immediate
Using Filebeat
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /var/log/audit/audit.log
tags: ["auditd"]
fields:
log_type: auditd
- type: log
enabled: true
paths:
- /var/log/audit/audit.log
multiline:
pattern: '^type='
negate: true
match: after
output.elasticsearch:
hosts: ["https://elasticsearch.example.com:9200"]
index: "auditd-%{+yyyy.MM.dd}"
# Or output to Logstash for processing
output.logstash:
hosts: ["logstash.example.com:5044"]
Using rsyslog with the audit plugin
# /etc/rsyslog.d/audit.conf
module(load="imfile")
input(type="imfile"
File="/var/log/audit/audit.log"
Tag="auditd:"
Facility="local6"
Severity="info")
local6.* action(type="omfwd"
target="siem.example.com"
port="514"
protocol="tcp"
template="RSYSLOG_SyslogProtocol23Format")
Compliance Mappings
Different compliance frameworks require specific audit rules. Here are the key mappings:
| Requirement | PCI DSS | HIPAA | CIS Benchmark |
|---|---|---|---|
| Login/logout monitoring | 10.2.1 | 164.312(b) | 4.1.3 |
| Failed authentication | 10.2.4 | 164.312(b) | 4.1.4 |
| Privilege escalation | 10.2.2 | 164.312(a)(1) | 4.1.11 |
| File integrity | 10.5, 11.5 | 164.312(c)(2) | 4.1.5 |
| System time changes | 10.4 | 164.312(b) | 4.1.3 |
| Log tampering detection | 10.5.2 | 164.312(b) | 4.1.18 |
Practical Alert Scenarios
Set up real-time alerting for high-priority events. Here is a script that watches the audit log and sends alerts:
#!/bin/bash
# audit-alerter.sh - Real-time audit event alerting
ALERT_WEBHOOK="https://hooks.slack.com/services/YOUR/WEBHOOK/URL"
tail -F /var/log/audit/audit.log | while read line; do
# Alert on unauthorized access attempts
if echo "$line" | grep -q 'type=AVC.*denied'; then
MESSAGE="SELinux denial detected: $line"
curl -s -X POST "$ALERT_WEBHOOK" \
-H 'Content-type: application/json' \
-d "{\"text\": \"$MESSAGE\"}"
fi
# Alert on new user creation
if echo "$line" | grep -q 'type=ADD_USER'; then
MESSAGE="New user created on $(hostname): $line"
curl -s -X POST "$ALERT_WEBHOOK" \
-H 'Content-type: application/json' \
-d "{\"text\": \"$MESSAGE\"}"
fi
# Alert on Docker socket access by non-root
if echo "$line" | grep -q 'key="docker_socket".*success=yes' && \
echo "$line" | grep -qv 'uid=0'; then
MESSAGE="Non-root Docker socket access on $(hostname): $line"
curl -s -X POST "$ALERT_WEBHOOK" \
-H 'Content-type: application/json' \
-d "{\"text\": \"$MESSAGE\"}"
fi
done
Performance Tuning
Audit logging has a measurable performance impact, especially with many syscall rules. Here are strategies for keeping the overhead acceptable:
- Be specific with rules. Monitoring
-S allis catastrophically expensive. Target specific syscalls relevant to your security model. - Use exit filters. Rules with
-a always,exitonly fire when the syscall completes, which is cheaper than entry-based rules. - Exclude known-safe processes. Use
-F exe!=/usr/bin/safe_daemonto exclude trusted high-volume processes from specific rules. - Increase the backlog buffer. Set
-b 8192or higher if you see lost events under load. - Use INCREMENTAL_ASYNC flush. This batches disk writes instead of flushing per-event.
# Set backlog buffer (place at top of rules)
-b 8192
# Exclude high-volume trusted processes from execve monitoring
-a always,exit -F arch=b64 -S execve -F exe!=/usr/lib/monitoring-agent -k exec
# Rate limit events from a noisy subsystem
-a always,exit -F arch=b64 -S open -F dir=/tmp -F success=0 -k tmp_access
The Linux audit system is one of the most powerful tools available for security monitoring and compliance. When properly configured and integrated with a SIEM, it provides a tamper-resistant record of every security-relevant event on your system. The investment in writing good audit rules pays dividends every time you need to investigate an incident or satisfy an auditor.