Security auditing is the practice of recording and reviewing system calls, file accesses, user actions, and configuration changes to detect policy violations, investigate incidents, and demonstrate compliance with standards like PCI DSS, HIPAA, and SOC 2. On RHEL 9, the Linux Audit Framework — provided by the auditd daemon — captures events at the kernel level, making it impossible for unprivileged processes to bypass logging. Every file open, every privileged command, every failed authentication attempt, and every change to a sensitive configuration file can be recorded with the exact timestamp, process ID, user, and command line. This guide covers installing and configuring auditd, writing audit rules with auditctl and /etc/audit/rules.d/, querying logs with ausearch, generating compliance reports with aureport, and configuring log rotation.

Prerequisites

  • RHEL 9 server with root access
  • No prerequisites beyond a standard RHEL 9 installation — auditd is installed and enabled by default

Step 1 — Verify auditd is Running

systemctl status auditd

# View the audit log directly
tail -20 /var/log/audit/audit.log

# Check audit version
auditctl --version

Step 2 — Understand auditd Configuration

vi /etc/audit/auditd.conf

Key settings:

log_file = /var/log/audit/audit.log
log_format = ENRICHED        # Include uid names, not just numbers
max_log_file = 50            # Maximum size per log file in MB
num_logs = 10                # Number of rotated logs to keep
max_log_file_action = ROTATE # Rotate when max_log_file is reached
space_left = 75              # MB of disk space remaining before warning
space_left_action = SYSLOG   # Write warning to syslog
admin_space_left = 50
admin_space_left_action = SUSPEND  # Suspend auditing if critically low
disk_full_action = SUSPEND
disk_error_action = SUSPEND
systemctl restart auditd

Step 3 — Write Audit Rules with auditctl

Audit rules use the -w (watch) and -a (append rule) syntax. Rules loaded with auditctl are active immediately but do not survive a reboot. Place persistent rules in files under /etc/audit/rules.d/.

# Watch a file for all access types
auditctl -w /etc/passwd -p rwxa -k identity

# Watch a directory recursively
auditctl -w /etc/sudoers.d/ -p wa -k sudoers

# System call rules: log all executions by a specific user
auditctl -a always,exit -F arch=b64 -F uid=1001 -S execve -k user1001-exec

# Log all use of the setuid/setgid bits
auditctl -a always,exit -F arch=b64 -S setuid -S setgid -k priv-escalation

# List current active rules
auditctl -l

# Delete all active rules
auditctl -D

Permission flags for -p:

  • r — read
  • w — write
  • x — execute
  • a — attribute change (e.g. chmod, chown)

Step 4 — Create Persistent Audit Rules

Create a rules file that loads automatically on boot:

vi /etc/audit/rules.d/security-baseline.rules
## Delete all existing rules on load
-D

## Set buffer size for high-volume systems
-b 8192

## Failure mode: 0=silent, 1=printk, 2=panic
-f 1

## === Identity and authentication files ===
-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/security/opasswd -p wa -k identity

## === Sudo and privilege escalation ===
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers

## === SSH configuration ===
-w /etc/ssh/sshd_config -p wa -k sshd-config

## === PAM configuration ===
-w /etc/pam.d/ -p wa -k pam

## === Cron jobs ===
-w /var/spool/cron/ -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /etc/crontab -p wa -k cron

## === System calls: privilege escalation ===
-a always,exit -F arch=b64 -S setuid -S setgid -S setreuid -S setregid -k priv-escalation
-a always,exit -F arch=b32 -S setuid -S setgid -S setreuid -S setregid -k priv-escalation

## === System calls: file deletions by non-root users ===
-a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=unset -k delete

## === All commands run as root ===
-a always,exit -F arch=b64 -F euid=0 -S execve -k root-commands

## === Make the configuration immutable (uncomment for production) ===
## -e 2
# Load the rules
augenrules --load

# Verify rules are loaded
auditctl -l

Step 5 — Query Logs with ausearch

# Search by key (the -k tag set in rules)
ausearch -k identity

# Search by key for today only
ausearch -k sudoers --start today

# Search for events involving a specific file
ausearch -f /etc/passwd

# Search for events by a specific user
ausearch -ua 1001

# Search for failed events
ausearch --success no

# Search for events in a time range
ausearch --start "11/01/2025 00:00:00" --end "11/01/2025 23:59:59"

# Interpret UIDs, PIDs into names
ausearch -k root-commands -i | tail -20

Step 6 — Generate Reports with aureport

# Summary of all audit events
aureport

# Report on authentication events
aureport -au

# Report on failed logins
aureport --login --failed

# Report on file access events
aureport -f

# Report on executable runs
aureport -x

# Summary report for today
aureport --summary --start today

# Report on events using the 'identity' key
aureport -k --start today

Step 7 — Verify the Audit System

# Check audit status
auditctl -s

# Test: make a change to a watched file
touch /etc/passwd   # Modifies mtime, triggers audit event
ausearch -k identity -i | tail -5

# Check audit log is growing
ls -lh /var/log/audit/audit.log

Troubleshooting

  • Audit log not growing — check auditctl -s for enabled: 1. If enabled: 0, restart auditd. If -e 2 (immutable mode) was set, the rules cannot be changed without a reboot.
  • Too many events, performance impact — avoid watching high-frequency paths like /proc or /sys. Use specific file watches rather than broad syscall watches. Increase the buffer size (-b) if audit events are being dropped.

Conclusion

Your RHEL 9 server now has a comprehensive audit framework: auditd capturing file access, identity changes, privilege escalation, and root command execution, with persistent rules in /etc/audit/rules.d/, and querying tools (ausearch, aureport) for both incident investigation and compliance reporting. The -k key tags make it easy to filter the audit trail by category.

Next steps: How to Manage System Packages with dnf on RHEL 9, How to Configure Network Interface Settings with nmcli/ip on RHEL 9, and How to Set Up SELinux in Enforcing Mode on RHEL 9.