Overview
3 AM, woken up by an alert. You log into the server and find a critical configuration file has been modified, but last shows no one logged in during that window, and bash_history has nothing. You know something happened, but you don’t know who did it or how.
This is when you need auditd—the audit system built into the Linux kernel. It’s like an airplane’s black box, recording every critical action on the system: who executed what command, which files were accessed, what configurations were changed, and when privilege escalation occurred. And these records are generated at the kernel level, independent of shell history or application logs—even if an attacker deletes ~/.bash_history, they can’t delete auditd’s logs.
This article covers everything from installation and deployment to rule writing, log analysis, and production tuning. It’s not a manual translation—it’s hands-on experience from the trenches.
What Is auditd and How Does It Differ from syslog
Let’s clear up a common confusion first. Many people think “I already have syslog/journald, why do I need auditd?”
These two record fundamentally different things:
| Comparison | syslog/journald | auditd |
|---|---|---|
| Recording Level | Application layer | Kernel layer |
| Content Recorded | Service start/stop, application logs, login records | System calls, file access, privilege changes |
| Granularity | Coarse (per event) | Fine (per system call) |
| Tamper Resistance | None (root can freely modify) | Yes (checksums before writing logs) |
| Performance Impact | Minimal | Depends on rule count and complexity |
| Typical Use | Daily operations logging | Security auditing, compliance checks, incident response |
To use an analogy: syslog is like the visitor log at a building entrance—records who comes and goes. auditd is like per-apartment door access logs plus indoor cameras—when which door was opened, who opened it, and for how long, precise to the second.
auditd originated from Solaris’s audit subsystem, introduced in Linux kernel 2.6 (2004), developed primarily by Red Hat and IBM. It has since become a mandatory component for security compliance standards like CIS Benchmark, PCI-DSS, and HIPAA.
auditd has become an integral part of security standards like CIS benchmarks, PCI-DSS, and HIPAA. Source: Demystifying Auditd: A Complete Guide for Linux Security Monitoring
auditd Core Component Architecture
auditd is not a single program—it’s a toolchain:
┌─────────────────────────────────────────────────┐
│ Application Layer │
│ auditctl (temp rules) augenrules (perm rules) │
├─────────────────────────────────────────────────┤
│ Audit Daemon │
│ auditd │
│ (receives kernel audit events, writes to │
│ /var/log/audit/audit.log) │
├─────────────────────────────────────────────────┤
│ Kernel Layer │
│ Linux Audit Subsystem │
│ (hooks syscalls, generates audit events, │
│ sends to auditd) │
├─────────────────────────────────────────────────┤
│ Log Analysis Tools │
│ ausearch (query) aureport (reports) │
└─────────────────────────────────────────────────┘
| Component | Purpose | Usage |
|---|---|---|
| auditd | Background daemon, receives kernel audit events and writes logs | Core, always running |
| auditctl | Configure temporary audit rules (lost on reboot) | Testing rules, ad-hoc investigation |
| augenrules | Load permanent rules from /etc/audit/rules.d/ | Production rule management |
| ausearch | Query audit logs by conditions | Daily queries, incident response |
| aureport | Generate audit log summary reports | Compliance reports, periodic audits |
| audispd | Audit event dispatcher (forward to external systems) | SIEM/ELK integration |
Installation and Basic Configuration
Installation
Most mainstream Linux distributions come with auditd pre-installed. If not:
# Ubuntu/Debian
sudo apt update && sudo apt install -y auditd audispd-plugins
# CentOS/RHEL 7
sudo yum install -y audit audit-libs
# CentOS/RHEL 8+/Fedora
sudo dnf install -y audit audit-libs
Start and enable on boot:
sudo systemctl enable --now auditd
sudo systemctl status auditd
# Confirm it shows active (running)
Note: In CentOS 7, auditd is marked as non-restartable (
RefuseManualStop=yes), sosystemctl restart auditdwill fail. Useservice auditd restartinstead.
auditd.conf Main Configuration File
The main configuration file is at /etc/audit/auditd.conf, controlling log storage and behavior:
# /etc/audit/auditd.conf key parameters
# Log file path
log_file = /var/log/audit/audit.log
# Max single log file size (MB), default 8, production recommends at least 100
max_log_file = 100
# Action when log reaches max size:
# ROTATE - rotate (keep old logs, create new file)
# KEEP_LOGS - don't overwrite, keep growing (will fill disk)
# IGNORE - don't record, continue writing current file (may corrupt)
max_log_file_action = ROTATE
# Number of rotated log files to keep
# Total space = num_logs × max_log_file
num_logs = 10
# Trigger warning when disk free space falls below this (percentage or size)
space_left = 20%
space_left_action = SYSLOG
# Critical low space threshold
admin_space_left = 10%
# SUSPEND - pause logging (default, prevents system crash)
# HALT - shut down immediately (very high security, prevents log overwriting)
# SINGLE - switch to single-user mode
admin_space_left_action = SUSPEND
# Data flush frequency to disk
# INCREMENTAL - with freq parameter, balances performance and safety
# DATA - flush each record immediately (safest but slowest)
# SYNC - synchronous writes (safest, worst performance)
flush = INCREMENTAL
freq = 50
# Log format: RAW or ENRICHED (enriched resolves UID/syscall names)
log_format = ENRICHED
# Whether to set immutability flag on audit log files
# Once set, even root cannot directly delete log files (must stop auditd first)
# Recommended for high-security environments, but adds operational complexity
# disk_full_action = HALT
These parameters need adjustment based on actual conditions. I’ve seen two common pitfalls: first, keeping max_log_file at the default 8MB, causing audit logs to rotate dozens of times per day, making it impossible to piece together complete event chains during investigation; second, setting admin_space_left_action to HALT, which shuts down the server when disk fills up, waking up ops at 3 AM to power it back on.
Verify Kernel Audit Functionality
# Check audit system status
sudo auditctl -s
# Example output:
# enabled 1
# flag -f 1
# rate_limit 0
# backlog_limit 8192
# lost 0
# backlog 0
# Check kernel audit backlog queue size
cat /proc/sys/kernel/audit_backlog_limit
# Default 64, production recommends at least 8192
# If 0, add audit=1 to /etc/default/grub and update grub
# Permanently set audit backlog queue size
echo "kernel.audit_backlog_limit=8192" | sudo tee -a /etc/sysctl.d/99-audit.conf
sudo sysctl -p /etc/sysctl.d/99-audit.conf
Writing Audit Rules
Rules are the soul of auditd. Without rules, auditd records nothing; with too many rules, CPU and disk suffer. The core principle is minimal necessity—only audit high-risk behaviors, avoid full monitoring.
Rule Storage Location
/etc/audit/audit.rules # Old format, single file (deprecated)
/etc/audit/rules.d/ # New format, directory (recommended)
├── 10-base.rules # Base rules
├── 20-user.rules # User behavior rules
├── 30-services.rules # Service-related rules
├── 40-custom.rules # Custom rules
└── 99-finalize.rules # Finalization rules (lock config, etc.)
After writing rules, load with augenrules:
# Load all rules from /etc/audit/rules.d/
sudo augenrules --load
# Verify rules are loaded
sudo auditctl -l
# Restart auditd to apply configuration
sudo service auditd restart
Filesystem Rules: Monitoring File/Directory Access
Filesystem rules use the -w parameter to monitor access to specified paths:
# Basic syntax
# -w <path> Path to monitor
# -p <perms> Permissions to monitor: r=read, w=write, x=execute, a=attribute change
# -k <key> Keyword tag (for log filtering)
Identity Layer: Monitor User Account Files
# /etc/audit/rules.d/10-identity.rules
# Monitor /etc/passwd write and attribute changes
-w /etc/passwd -p wa -k identity
# Monitor /etc/shadow (password hash file, high sensitivity)
-w /etc/shadow -p wa -k identity
# Monitor /etc/group
-w /etc/group -p wa -k identity
# Monitor /etc/gshadow
-w /etc/gshadow -p wa -k identity
# Monitor login history
-w /var/log/wtmp -p wa -k login_history
-w /var/log/btmp -p wa -k failed_login
Why use -p wa instead of -p rwxa? Because read operations (r) generate massive log volumes—every ls command reading /etc/passwd would trigger a record. What we care about is who modified these files, not who read them. Write (w) and attribute changes (a) are the high-risk behaviors.
Privilege Control Layer: Monitor sudo and Privilege Escalation
# /etc/audit/rules.d/20-privilege.rules
# Monitor sudoers config file modifications
-w /etc/sudoers -p wa -k sudoers_modify
-w /etc/sudoers.d/ -p wa -k sudoers_modify
# Monitor sudo command execution
-w /usr/bin/sudo -p x -k sudo_exec
# Monitor su command execution
-w /bin/su -p x -k su_exec
# Monitor pkexec (PolKit privileged execution)
-w /usr/bin/pkexec -p x -k pkexec_exec
# Monitor permission modification tools
-w /usr/bin/chmod -p x -k perm_change
-w /usr/bin/chown -p x -k perm_change
-w /usr/bin/chgrp -p x -k perm_change
Remote Access Layer: Monitor SSH Configuration
# /etc/audit/rules.d/30-remote.rules
# Monitor SSH service config file
-w /etc/ssh/sshd_config -p wa -k sshd_config
# Monitor authorized_keys file (for root and key users)
-w /root/.ssh/authorized_keys -p wa -k ssh_keys
-w /home/admin/.ssh/authorized_keys -p wa -k ssh_keys
# Monitor PAM configuration
-w /etc/pam.d/ -p wa -k pam_config
Sensitive Files: Monitor Configuration Change Pathways
# /etc/audit/rules.d/40-custom.rules
# Monitor network configuration files
-w /etc/hosts -p wa -k network_config
-w /etc/resolv.conf -p wa -k network_config
-w /etc/sysconfig/network -p wa -k network_config
# Monitor environment configuration
-w /etc/profile -p wa -k profile_modify
-w /etc/bashrc -p wa -k bashrc_modify
# Monitor cron jobs (common backdoor vector)
-w /etc/crontab -p wa -k cron_modify
-w /etc/cron.d/ -p wa -k cron_modify
-w /var/spool/cron/ -p wa -k cron_modify
# Monitor systemd service files
-w /etc/systemd/system/ -p wa -k systemd_service
-w /usr/lib/systemd/system/ -p wa -k systemd_service
Syscall Rules: Monitoring Lower-Level Operations
Filesystem rules can only monitor file paths. Syscall rules capture lower-level behaviors:
# Basic syntax
# -a <action>,<filter> Action and filter
# action: always (always record) / never (never record)
# filter: exit (on syscall exit) / entry (on entry) / task (on task creation)
# -F <field=value> Filter conditions
# arch: architecture (b64/b32)
# -S: syscall name (execve/open/chmod etc.)
# -F uid: user ID
# -F auid: actual user ID (tracks original user even after privilege escalation)
# -k <key> Keyword tag
# Monitor all command executions by non-root users
-a always,exit -F arch=b64 -S execve -F auid!=0 -k user_cmd
# Monitor setuid/setgid calls (privilege escalation)
-a always,exit -F arch=b64 -S setuid,setgid,setreuid,setregid -k privilege_change
# Monitor reads of /etc/shadow by non-root
-a always,exit -F arch=b64 -S open -F path=/etc/shadow -F uid!=0 -k shadow_read
# Monitor file deletion operations
-a always,exit -F arch=b64 -S unlink,unlinkat,rmdir -k file_delete
# Monitor network connection establishment
-a always,exit -F arch=b64 -S connect -k network_connect
The distinction between auid and uid is critical: uid is the current user ID (changes to 0 after privilege escalation), while auid is the original user ID at login time. Using auid, you can trace “which real user executed what operation through sudo privilege escalation,” even if the user has switched to root.
Finalization Rules: Tamper-Proof Configuration
# /etc/audit/rules.d/99-finalize.rules
# Set audit rules to immutable (-e 2)
# Once set, any modification to audit rules requires a system reboot
# This prevents attackers from temporarily disabling auditing
# But also increases operational complexity—changing rules requires reboot
-e 2
# Set behavior on audit buffer overflow
# -f 1: only log failures
# -f 2: log failures and trigger panic (kernel crash, only for extreme security)
-f 1
# Set rate limit (max audit events per second)
# 0 means unlimited; production recommends 100-500 to prevent event storms
-r 200
-e 2 is a critical security setting—it puts audit rules into immutable mode. Even if an attacker gains root access, they can’t clear rules with auditctl -D to hide their tracks. The trade-off is that changing rules requires a system reboot. For high-security environments (finance, government), this trade-off is worth it.
Rule Writing Best Practices
| Principle | Description | Anti-Pattern |
|---|---|---|
| Only audit high-risk behaviors | Focus on writes, executions, privilege escalation | Monitoring reads of /var/log, causing log explosion |
Every rule must have -k tag | Enables easy filtering and querying | No -k tag, requiring full log scan during investigation |
| Avoid high-traffic paths | /tmp, /proc, /var/log read operations are too frequent | -w /tmp -p rwx generates massive log volume |
Use -F for precise filtering | Specify specific users, paths to reduce match scope | No filtering, recording all execve calls |
| Test before persisting | Use auditctl for temporary rules, confirm no issues before writing files | Writing directly to rules.d, causing auditd startup failure from bad rules |
Log Analysis in Practice
Rules are configured, logs are being generated. But audit.log’s format is not human-friendly—each record is a line of key=value text with abbreviated field names. Reading it manually is painful.
Audit Log Format Parsing
A typical audit log entry looks like this:
type=SYSCALL msg=audit(1721000000.123:456): arch=c000003e syscall=2 success=yes exit=3 a0=7fff5a3b2c10 a1=0 a2=1b6 a3=0 items=1 ppid=1234 pid=5678 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=1 comm="cat" exe="/usr/bin/cat" key="shadow_read"
Field meanings:
| Field | Meaning | Example |
|---|---|---|
| type | Event type | SYSCALL, PATH, USER_LOGIN |
| msg | timestamp:sequence | 1721000000.123:456 |
| arch | Architecture | c000003e (x86_64) |
| syscall | Syscall number | 2 (open) |
| success | Whether successful | yes/no |
| auid | Original user ID | 1000 (stays 1000 even after privilege escalation) |
| uid | Current user ID | 0 (escalated to root) |
| comm | Process command name | cat |
| exe | Executable file path | /usr/bin/cat |
| key | Rule tag | shadow_read |
ausearch: Conditional Query
ausearch is the most commonly used query tool, supporting filtering by time, keyword, user, etc.:
# Query by keyword (most common)
sudo ausearch -k identity
# Query all audit events with the identity tag
# Query by time range
sudo ausearch -ts today -k sudo_exec
sudo ausearch -ts "07/15/2026" "02:00" -te "07/15/2026" "06:00"
sudo ausearch -ts yesterday -te today
# Query by user
sudo ausearch -ua 1000 # Query all events with auid=1000
sudo ausearch -ui 0 # Query all events with uid=0 (root)
# Query by event type
sudo ausearch -m USER_LOGIN # Query login events
sudo ausearch -m USER_AUTH # Query authentication events
sudo ausearch -m SYSCALL # Query syscall events
# Combined query: commands executed by non-root users today
sudo ausearch -ts today -k user_cmd -m SYSCALL
# Only failed authentications
sudo ausearch -m USER_AUTH -sv no
# Check modifications to a specific file
sudo ausearch -f /etc/passwd
# Output in more readable format (-i resolves UID/syscall names)
sudo ausearch -k identity -i
The -i parameter is important—it resolves numeric UID, GID, and syscall numbers into readable names.
aureport: Summary Reports
aureport generates statistical reports, ideal for periodic audit reporting:
# Generate today's summary report
sudo aureport -ts today
# Summarize command execution count by user
sudo aureport -x --summary -ts today
# Summarize file access count
sudo aureport -f -ts today
# Summarize by event type
sudo aureport -e -ts today
# Summarize failed events
sudo aureport --failed -ts today
# Generate readable login report
sudo aureport -l -i -ts today
Example output:
Summary Report
======================
Range of time in log: 07/15/2026 02:00:00 - 07/15/2026 06:00:00
Number of changes in configuration: 0
Number of changes to user, group, role, or SElinux user: 2
Number of logins: 3
Number of failed logins: 17
Number of authentications: 12
Number of failed authentications: 17
Number of users: 3
Number of terminals: 5
Number of host names: 4
Number of executables: 23
Number of commands: 156
Number of files: 89
Number of AVC's: 0
Number of events: 1245
Incident Response: Tracing Attack Paths
Suppose you discover /etc/passwd has been modified. Here’s how to reconstruct the attack chain with auditd:
# Step 1: Find who modified /etc/passwd
sudo ausearch -k identity -i -ts today
# Find the auid and pid
# Step 2: Check what commands this user executed before the modification
sudo ausearch -ua <auid> -i -ts today | grep execve
# Step 3: Check if this user escalated privileges
sudo ausearch -k privilege_change -ua <auid> -i
# Step 4: Check if a backdoor user was created
sudo ausearch -k user_cmd -m SYSCALL -i -ts today | grep -E "useradd|usermod"
# Step 5: Check if SSH config was modified to inject public keys
sudo ausearch -k sshd_config -i
sudo ausearch -k ssh_keys -i
# Step 6: Check if cron jobs were modified
sudo ausearch -k cron_modify -i
# Step 7: Export complete audit logs for forensics
sudo ausearch --start today --end now -i > /tmp/incident-$(date +%Y%m%d).log
In one incident response, auditd successfully reconstructed the complete attack chain from vulnerability exploitation to privilege escalation—ten times more efficient than reviewing regular system logs. Source: Linux Security Auditing in Practice: auditd Rule Configuration and Log Analysis
Integrating auditd with SIEM Systems
The limitation of single-machine audit logs is that once an attacker gains root, they can attempt to tamper with local logs. Production environments should forward audit logs in real-time to a centralized log platform (SIEM).
Forwarding via audispd to Remote Log Server
audispd (audit dispatcher daemon) is auditd’s event dispatch plugin, capable of forwarding audit events to syslog, remote log servers, or custom programs:
# Install audispd plugins
sudo apt install -y audispd-plugins # Ubuntu/Debian
sudo yum install -y audispd-plugins # CentOS/RHEL
# Configure remote forwarding
sudo vi /etc/audisp/audisp-remote.conf
## remote_ending = single
## remote_server = 10.0.1.100 # Remote log server IP
## remote_port = 60 # Port
## local_port = any
## transport = tcp
## queue_file = /var/spool/audit/remote.log
## mode = forward
## network_retry_time = 1
## initial_tries = 3
## enable_krb5 = no
# Enable remote plugin
sudo vi /etc/audisp/plugins.d/au-remote.conf
## active = yes
## direction = out
## path = /sbin/audisp-remote
## type = always
## args = /etc/audisp/audisp-remote.conf
## format = string
# Restart auditd
sudo service auditd restart
Integrating with ELK/Loki
A more common approach is to relay through rsyslog to ELK or Loki:
# Configure rsyslog to receive auditd logs
# /etc/rsyslog.d/audit.conf
# Receive logs from auditd (via syslog method)
$ModLoad imfile
$InputFileName /var/log/audit/audit.log
$InputFileTag auditd
$InputFileStateFile audit-state
$InputFileSeverity info
$InputRunFileMonitor
# Forward to remote ELK/Loki
*.* @@10.0.1.100:514 # Forward via TCP to remote syslog server
Using auditbeat for Collection (ELK Ecosystem)
If your log platform is ELK, Elastic’s official auditbeat is more convenient:
# auditbeat.yml
auditd.audit_rules: |
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k sudoers_modify
-a always,exit -F arch=b64 -S execve -F auid!=0 -k user_cmd
# Output to Elasticsearch
output.elasticsearch:
hosts: ["es-node:9200"]
index: "auditd-logs-%{+yyyy.MM.dd}"
# Or output to Logstash
output.logstash:
hosts: ["logstash:5044"]
Performance Tuning
auditd’s performance impact is real. Poorly written rules can spike CPU from 2% to 30% and double disk I/O.
Performance Impact Testing
Run baseline tests before adding rules:
# Baseline test: record current CPU and disk I/O
mpstat 1 60 # 60 seconds CPU usage
iostat -x 1 60 # 60 seconds disk I/O
# Add test rule
sudo auditctl -a always,exit -F arch=b64 -S open -k test_open
# Test again
mpstat 1 60
iostat -x 1 60
# Remove test rule
sudo auditctl -d always,exit -F arch=b64 -S open -k test_open
Performance Optimization Tips
| Optimization | Approach | Effect |
|---|---|---|
| Reduce syscall rules | Prefer filesystem rules (-w), minimize syscall rules (-a -S) | Syscall rules have far greater performance impact than file rules |
| Avoid high-traffic paths | Don’t monitor reads of /tmp, /proc, /var/log | Prevents log explosion and CPU spikes |
Use -F for precise filtering | Specify specific users, paths to reduce match scope | Reduces kernel-space filtering overhead |
| Set rate limit | -r 200 limits max events per second | Prevents event storms from overwhelming the system |
| Increase backlog queue | audit_backlog_limit=8192 | Prevents event loss |
| Reasonable log rotation | max_log_file=100 + num_logs=10 | Prevents disk from filling up |
| Use ENRICHED format | log_format=ENRICHED | Resolves UID/syscall at log generation time, reducing post-processing overhead |
Microsoft Defender for Endpoint from version 101.2408.0000 no longer uses auditd as an event provider, switching to eBPF sensors. Main reasons include reducing audit log noise, reducing application rule conflicts, lowering file event monitoring overhead, and improving event throughput with reduced memory usage. This demonstrates that auditd’s performance has real bottlenecks under high load, and eBPF is a direction worth watching. Source: Using eBPF sensors for Microsoft Defender for Endpoint on Linux
auditd vs eBPF: Future Trends
auditd’s core limitation is that its syscall hooking approach is relatively “heavy”—each rule must be matched in kernel space, and overhead grows linearly with rule count. eBPF offers a lighter-weight alternative:
| Comparison | auditd | eBPF |
|---|---|---|
| Implementation | Kernel audit subsystem hooks syscalls | BPF programs attached to kernel hook points |
| Performance Impact | Significant (noticeable with many rules) | Minimal (JIT compiled, kernel-space execution) |
| Flexibility | Fixed rule syntax | Programmable, supports complex logic |
| Ecosystem Maturity | Mature, widely used for compliance | Rapidly developing, used in Falco, Tracee |
| Compliance Recognition | Explicitly required by CIS/PCI-DSS/HIPAA | Not yet widely recognized by compliance standards |
In the short term, auditd remains the standard for compliance auditing. eBPF is better suited for runtime security monitoring (HIDS scenarios). The two are complementary, not replacement.
Compliance Requirements
MLPS 2.0 (China’s Multi-Level Protection Scheme) Audit Requirements
MLPS Level 3 and above requires “logging of network device operations, network traffic, and user behavior in network systems.” For host-level:
| MLPS Requirement | Corresponding auditd Rules |
|---|---|
| Record user login and logout | Monitor /var/log/wtmp, /var/log/btmp |
| Record system administrator operations | Monitor sudo, su execution, record execve syscalls |
| Record access and modification of important files | Monitor /etc/passwd, /etc/shadow, /etc/sudoers |
| Record audit logs of security events | All rules + -k tag classification |
| Log retention period no less than 6 months | Configure num_logs and max_log_file for sufficient retention |
| Log integrity protection | -e 2 immutable mode + remote forwarding |
CIS Benchmark Reference
CIS Red Hat Enterprise Linux 8 Benchmark recommended auditd rules (excerpt):
# CIS 4.1.3 - Ensure auditd service is enabled
systemctl is-enabled auditd
# CIS 4.1.4 - Ensure audit log file permissions are correct
# audit.log permissions should be 600
ls -l /var/log/audit/audit.log
# CIS 4.1.9 - Ensure audit system behavior on insufficient disk space
# Set in /etc/audit/auditd.conf
space_left_action = email
admin_space_left_action = halt
# CIS 4.1.10 - Ensure audit configuration is immutable
auditctl -e 2
# CIS 4.1.11 - Ensure login and logout events are recorded
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins
# CIS 4.1.13 - Ensure session start information is recorded
-w /var/run/utmp -p wa -k session
-w /var/log/wtmp -p wa -k session
-w /var/log/btmp -p wa -k session
# CIS 4.1.14 - Ensure permission modification events are recorded
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=-1 -F key=perm_mod
# CIS 4.1.15 - Ensure unauthorized access events are recorded
-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F auid>=1000 -F auid!=-1 -F exit=-EACCES -F key=access
-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F auid>=1000 -F auid!=-1 -F exit=-EPERM -F key=access
Refer to the complete CIS Benchmark rule set—auditd is a mandatory component for CIS, PCI-DSS, HIPAA, and other security compliance standards. Source: Linux Audit System Configuration Introduction
Automation Scripts
Batch Deploy auditd Rules to Multiple Servers
#!/bin/bash
# deploy-auditd-rules.sh
# Batch deploy auditd rules across multiple servers
SERVERS=("web01.prod" "web02.prod" "db01.prod" "cache01.prod")
RULES_DIR="./audit-rules"
for server in "${SERVERS[@]}"; do
echo ">>> Deploying auditd rules to $server"
# Create rules directory
ssh "$server" "sudo mkdir -p /etc/audit/rules.d"
# Transfer rule files
scp -r "$RULES_DIR"/* "$server:/tmp/audit-rules/"
# Install auditd (if not installed)
ssh "$server" "sudo apt install -y auditd audispd-plugins 2>/dev/null || sudo yum install -y audit audit-libs"
# Backup existing rules
ssh "$server" "sudo cp -r /etc/audit/rules.d /etc/audit/rules.d.bak.$(date +%Y%m%d)"
# Deploy new rules
ssh "$server" "sudo cp /tmp/audit-rules/*.rules /etc/audit/rules.d/"
# Load rules
ssh "$server" "sudo augenrules --load && sudo service auditd restart"
# Verify rules
echo ">>> Rules loaded on $server:"
ssh "$server" "sudo auditctl -l"
echo ">>> Done: $server"
done
echo ">>> All servers deployed."
Audit Log Periodic Cleanup Script
#!/bin/bash
# audit-log-cleanup.sh
# Periodically clean old audit logs to free disk space
# Keep logs from the last 180 days (compliance requirement)
RETENTION_DAYS=180
AUDIT_LOG_DIR="/var/log/audit"
# Clean old rotated log files
find "$AUDIT_LOG_DIR" -name "audit.log.*" -mtime +$RETENTION_DAYS -delete
# Compress logs older than 30 days
find "$AUDIT_LOG_DIR" -name "audit.log.*" -mtime +30 ! -name "*.gz" -exec gzip {} \;
# Output current disk usage
echo "=== Audit log disk usage ==="
du -sh "$AUDIT_LOG_DIR"
ls -lh "$AUDIT_LOG_DIR" | head -20
echo "=== Total files: $(find $AUDIT_LOG_DIR -type f | wc -l) ==="
Audit Anomaly Detection Script
#!/bin/bash
# audit-anomaly-check.sh
# Periodically check audit logs for anomalous behavior
REPORT_FILE="/var/log/audit-anomaly-$(date +%Y%m%d).log"
echo "=== Audit Anomaly Report - $(date) ===" > "$REPORT_FILE"
# Check 1: After-hours (22:00-06:00) sudo executions
echo "--- After-hours sudo executions ---" >> "$REPORT_FILE"
sudo ausearch -k sudo_exec -ts today | \
awk -F"audit\(" '{print $2}' | \
awk -F":" '{print $1}' | \
while read ts; do
hour=$(date -d @${ts%.*} +%H 2>/dev/null)
if [ "$hour" -ge "22" ] || [ "$hour" -lt "06" ]; then
echo " Suspicious: sudo at $hour:00 (timestamp: $ts)"
fi
done >> "$REPORT_FILE" 2>/dev/null
# Check 2: Failed authentication count exceeding threshold
echo "--- Failed authentications (>5 times) ---" >> "$REPORT_FILE"
sudo ausearch -m USER_AUTH -sv no -ts today -i 2>/dev/null | \
grep "uid=" | \
awk -F'uid="' '{print $2}' | \
awk -F'"' '{print $1}' | \
sort | uniq -c | sort -rn | \
awk '$1 > 5 {print " User "$2": "$1" failed attempts"}' >> "$REPORT_FILE"
# Check 3: New user creation
echo "--- New user creation ---" >> "$REPORT_FILE"
sudo ausearch -k identity -ts today -i 2>/dev/null | \
grep -E "useradd|adduser" >> "$REPORT_FILE"
# Check 4: SSH configuration file modifications
echo "--- SSH config changes ---" >> "$REPORT_FILE"
sudo ausearch -k sshd_config -ts today -i >> "$REPORT_FILE"
# Check 5: Cron job modifications (possible backdoor)
echo "--- Cron modifications ---" >> "$REPORT_FILE"
sudo ausearch -k cron_modify -ts today -i >> "$REPORT_FILE"
# Check 6: Whether audit rules were cleared (attacker may try to disable auditing)
echo "--- Audit rule count check ---" >> "$REPORT_FILE"
RULE_COUNT=$(sudo auditctl -l 2>/dev/null | wc -l)
if [ "$RULE_COUNT" -lt 5 ]; then
echo " WARNING: Only $RULE_COUNT audit rules active! Possible tampering." >> "$REPORT_FILE"
else
echo " OK: $RULE_COUNT audit rules active." >> "$REPORT_FILE"
fi
echo "" >> "$REPORT_FILE"
echo "=== End of report ===" >> "$REPORT_FILE"
cat "$REPORT_FILE"
Add this script to crontab for daily execution:
# Check yesterday's audit anomalies every day at 8 AM
0 8 * * * /usr/local/bin/audit-anomaly-check.sh
Summary
auditd is the infrastructure for Linux system auditing. It costs nothing and comes pre-installed, but using it well requires effort. Key takeaways from practice:
- Audit first, lock later. In the first phase, configure rules and run for a week to check if log volume is reasonable and if there are false positives. Once confirmed, add
-e 2to lock. If you lock immediately and something goes wrong, you can’t change rules without a reboot—shooting yourself in the foot. - Filesystem rules over syscall rules.
-whas far less performance impact than-a -S. Use file rules whenever a scenario can be covered by them. - Logs must be forwarded. Local logs become untrustworthy once an attacker gains root. At minimum, configure audispd to forward to a remote syslog server, or use auditbeat to send to ELK. Ideally, logs should be append-only and stored on a separate server.
- Audit regularly, not just when something happens. Run that anomaly detection script and review the report weekly. If you wait until an incident to check logs, they may have already been rotated and overwritten.
-ktags are your best friend. Every rule should have a-ktag. During investigation,ausearch -k xxxfilters relevant events in one command. Rules without tags have no classification, making investigation much less efficient.- Watch the eBPF trend. auditd has clear performance bottlenecks under high load. Falco, Tracee, and other eBPF security tools are maturing rapidly and may become a complement or even replacement for auditd in the future. But for now, compliance auditing still relies on auditd.
One final point: security auditing isn’t “install a tool and forget.” It’s a continuous process—regularly check whether rules cover newly emerging attack techniques, regularly review anomalous patterns in logs, and regularly update anomaly detection script rules. An audit system that’s been running for a year is more valuable than one just deployed, because you already know what’s normal and what warrants vigilance.
References & Acknowledgments
The following resources were referenced during the writing of this article. We thank the original authors for their contributions:
- Linux auditd Command — Runoob, auditd core component introduction and basic command usage
- Demystifying Auditd: A Complete Guide for Linux Security Monitoring — CSDN, complete auditd guide covering security compliance standards and best practices
- Linux Security Auditing in Practice: auditd Rule Configuration and Log Analysis — CSDN, auditd rule configuration and incident response cases
- Linux Audit System Configuration Introduction — CSDN, auditd configuration parameter details and CIS Benchmark rule references
- Linux User Behavior Audit System: auditd Configuration and Operations Practice — php.cn, user behavior audit layered monitoring strategy and rule configuration
- Linux Security Auditing in Practice: auditd Rule Templates and Log Analysis — CSDN, scenario-based auditd rule templates and monitoring strategies
- Linux Audit in Practice: From Rule Configuration to Log Analysis, Comparing syslog and Security Monitoring — CSDN, auditd vs syslog comparison and SIEM integration
- Using eBPF Sensors for Microsoft Defender for Endpoint on Linux — Microsoft Learn, eBPF replacing auditd performance advantages analysis
- Linux Security Auditing Tutorial: auditd Log Monitoring and Anomaly Detection — Jianshu, auditd anomaly detection and ELK integration practices