Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Subscribe and receive upto $1000 discount on checkout. Learn more
Configure Auditd for Security and Compliance on Linux

A slow Tuesday that turns into an audit

It usually starts quietly. A single Linux server becomes two. Two become a fleet. A few admins become a rotating on-call schedule. Then one day, a compliance request lands in our inbox: “Show who changed privileged access, when it happened, and what exactly changed.”

At first, we try to reconstruct the story from shell history, scattered logs, and memory. But systems don’t scale on memory. As environments grow, the risk isn’t only attackers—it’s ambiguity. When we cannot prove what happened, we end up treating everything as suspicious, and that is expensive.

This is where the Linux Audit Framework (auditd) earns its place. It gives us a tamper-resistant, kernel-level record of security-relevant events: authentication, privilege use, sensitive file changes, and policy modifications. Done well, it becomes a calm, predictable backbone for security and compliance. Done poorly, it becomes noisy, fragile, or worse—silently incomplete.

Prerequisites and system assumptions

Before we touch configuration, we need to be explicit about the environment we are operating in. Audit is foundational, and small differences in OS defaults, storage, and log rotation can change outcomes.

  • Platform: Linux. The steps below assume a modern systemd-based distribution (common in enterprise Linux). Commands are written to work on Debian/Ubuntu and RHEL/Rocky/Alma families with minimal adjustments.
  • Privileges: We need root access. We will use sudo for commands. If sudo is not available, we must run as root.
  • Packages: We will install auditd and supporting tools (audispd-plugins on Debian/Ubuntu; included or separate on some distros).
  • Time sync: Audit trails are only credible when timestamps are correct. We should have NTP/chrony/systemd-timesyncd enabled and stable.
  • Disk capacity: Audit logs can grow quickly. We need a plan for log size, rotation, and retention. We will configure safe defaults and verify behavior.
  • Kernel audit support: Most enterprise kernels support auditing. We will verify audit status and enable it persistently where needed.
  • Change control: In production, we should schedule a maintenance window. Some changes (like enabling auditing at boot) are best done with a controlled reboot.

Step 1: Confirm OS family and baseline health

Before installing anything, we will confirm what distribution we are on and ensure systemd is managing services. This matters because package names and service units differ slightly across Linux families.

set -euo pipefail

cat /etc/os-release
ps -p 1 -o comm=

We just printed the OS identification and confirmed the init system. If the second command returns systemd, the service management commands in this guide will apply directly.

Step 2: Install auditd and supporting tools

Now we will install the Linux Audit Framework components. We are doing this first because everything else—rules, persistence, and verification—depends on the daemon and its tooling being present.

Debian/Ubuntu family installation

On Debian/Ubuntu, we will install auditd and the dispatcher plugins package. The dispatcher is useful for forwarding audit events to syslog or other consumers in enterprise setups.

sudo apt-get update
sudo apt-get install -y auditd audispd-plugins

We just installed the audit daemon and its plugin framework. The system now has auditctl, augenrules, and ausearch available for rule management and querying.

RHEL/Rocky/Alma family installation

On RHEL-like systems, we will install audit (which provides auditd and tools). Some distributions also package dispatcher plugins separately; installing audispd-plugins is safe when available.

sudo dnf install -y audit audispd-plugins || sudo dnf install -y audit

We just installed the audit subsystem packages. If audispd-plugins was not available, the command fell back to installing audit only, which is still sufficient for local auditing.

Step 3: Enable and start auditd with persistence across reboots

Next we will enable the audit daemon so it starts at boot, and we will start it immediately. This is essential for compliance: a control that only works after someone remembers to start it is not a control.

sudo systemctl enable --now auditd
sudo systemctl status auditd --no-pager

We just made auditd persistent across reboots and confirmed it is running. The status output should show active (running). If it is not active, we will address it in the troubleshooting section.

Step 4: Verify kernel audit is active and understand the current state

Auditd can be running while the kernel audit subsystem is disabled or constrained. Before we define rules, we will check the kernel audit status and the current rule set. This prevents a false sense of coverage.

sudo auditctl -s
sudo auditctl -l || true

The first command printed the kernel audit status, including whether auditing is enabled and the current backlog settings. The second command listed loaded rules; on a fresh system it may be empty, which is expected.

Step 5: Configure auditd behavior for production stability

Now we will configure how auditd writes logs, how it behaves under pressure, and how it reacts when disk space becomes constrained. This is where many deployments fail: either they drop events silently, or they fill disks and cause outages. We will choose controlled behavior.

We will first back up the existing configuration so we can roll back safely.

sudo cp -a /etc/audit/auditd.conf /etc/audit/auditd.conf.bak.$(date +%F_%H%M%S)

We just created a timestamped backup of the auditd configuration file. This gives us a clean rollback point.

Next we will write a production-ready baseline configuration. This configuration focuses on predictable log handling, safe rotation, and explicit actions when disk space is low.

sudo tee /etc/audit/auditd.conf >/dev/null <<'EOF'
#
# Production baseline for Linux Audit Framework (auditd)
# Focus: predictable logging, safe rotation, and controlled failure modes.
#

log_file = /var/log/audit/audit.log
log_format = RAW
log_group = root

# Keep permissions tight; audit logs are sensitive.
priority_boost = 4
flush = INCREMENTAL_ASYNC
freq = 50

# Rotation and retention behavior
num_logs = 10
max_log_file = 50
max_log_file_action = ROTATE

# Disk space safety
space_left = 200
space_left_action = SYSLOG
admin_space_left = 100
admin_space_left_action = SUSPEND
disk_full_action = SUSPEND
disk_error_action = SUSPEND

# Name formatting
name_format = NONE

# Dispatcher (audisp) integration is handled separately if needed.
EOF

We just replaced /etc/audit/auditd.conf with a controlled baseline. Logs will rotate at 50 MB, keep 10 rotated files, and the daemon will suspend logging when disk space becomes dangerously low rather than pretending everything is fine. In regulated environments, “fail closed” is often preferable to silent loss of evidence.

Now we will restart auditd so the configuration takes effect, and we will verify the service is still healthy.

sudo systemctl restart auditd
sudo systemctl status auditd --no-pager

We just applied the new auditd configuration. If the service is active, auditd accepted the configuration and is writing logs under the new policy.

Step 6: Enable auditing early at boot for stronger compliance posture

In many environments, we want auditing enabled as early as possible during boot. Otherwise, events that occur before auditd starts can be missed. The kernel parameter audit=1 ensures auditing is enabled at boot.

We will first check the current kernel command line so we do not duplicate settings.

cat /proc/cmdline

We just printed the active boot parameters. If audit=1 is already present, we can skip the next step.

Now we will add audit=1 persistently using the distro’s GRUB defaults file, then rebuild the GRUB configuration. This is a controlled change and typically requires a reboot to take effect.

if [ -f /etc/default/grub ]; then
  sudo cp -a /etc/default/grub /etc/default/grub.bak.$(date +%F_%H%M%S)
  if ! grep -q 'audit=1' /etc/default/grub; then
    sudo sed -i 's/^(GRUB_CMDLINE_LINUX=.*)"/1 audit=1"/' /etc/default/grub
  fi
fi

if command -v update-grub >/dev/null 2>&1; then
  sudo update-grub
elif command -v grub2-mkconfig >/dev/null 2>&1; then
  if [ -d /boot/grub2 ]; then
    sudo grub2-mkconfig -o /boot/grub2/grub.cfg
  elif [ -d /boot/efi/EFI ]; then
    sudo grub2-mkconfig -o /boot/efi/EFI/$(ls /boot/efi/EFI | head -n 1)/grub.cfg
  fi
fi

We just ensured audit=1 is included in GRUB’s kernel parameters and rebuilt the GRUB configuration using the available toolchain. This change becomes active after a reboot.

We will verify after the next reboot by checking the kernel command line again and confirming audit status:

cat /proc/cmdline
sudo auditctl -s

We just confirmed whether audit=1 is active and whether the kernel audit subsystem is enabled. This closes the loop on persistence.

Step 7: Define real-world audit use-cases and implement focused rules

Audit rules are where intent becomes evidence. The goal is not to log everything. The goal is to log the events that answer real questions during an investigation or an audit, without drowning operations in noise.

We will implement a focused set of rules aligned to common compliance and security needs:

  • Identity and authentication changes: changes to users, groups, and authentication policy.
  • Privilege use: tracking execution of privileged commands and changes to sudoers.
  • System integrity: changes to critical configuration and scheduled tasks.
  • Kernel and module changes: module load/unload attempts.
  • Time changes: time manipulation is a classic anti-forensics move.

We will store rules in /etc/audit/rules.d/ and compile them using augenrules. This is the standard, persistent approach on systemd-based systems.

First we will back up any existing rules directory so we can revert if needed.

sudo mkdir -p /etc/audit/rules.d
sudo tar -C /etc -czf /root/audit_rules_backup_$(date +%F_%H%M%S).tgz audit/rules.d 2>/dev/null || true

We just created a backup archive of the current rules directory (if it existed). This gives us a safe rollback point.

Now we will write a complete rules file that targets the use-cases above. We will keep it readable and keyed so searches are consistent.

sudo tee /etc/audit/rules.d/10-niilaa-security-compliance.rules >/dev/null <<'EOF'
#
# NIILAA baseline audit rules for security and compliance
# Focused, real-world coverage without "log everything" noise.
#

# Increase buffer to reduce event loss under load
-b 8192

# Failure mode: 1=printk, 2=panic. We choose 1 for production stability.
-f 1

# Ignore noisy, low-value events (optional; keep minimal)
# (We intentionally keep this light to avoid hiding useful evidence.)

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

-w /etc/pam.d/ -p wa -k auth
-w /etc/nsswitch.conf -p wa -k auth
-w /etc/ssh/sshd_config -p wa -k ssh
-w /etc/ssh/ssh_config -p wa -k ssh

# --- Privilege and sudo policy ---
-w /etc/sudoers -p wa -k sudo
-w /etc/sudoers.d/ -p wa -k sudo

# Track execution of sudo (works across distros)
-a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=4294967295 -k priv_cmd

# --- System integrity: critical configs and scheduled tasks ---
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron
-w /etc/cron.daily/ -p wa -k cron
-w /etc/cron.hourly/ -p wa -k cron
-w /etc/cron.weekly/ -p wa -k cron
-w /etc/cron.monthly/ -p wa -k cron
-w /var/spool/cron/ -p wa -k cron

-w /etc/systemd/system/ -p wa -k systemd
-w /lib/systemd/system/ -p wa -k systemd

# --- Kernel modules (common persistence technique) ---
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module -k kernel_modules
-a always,exit -F arch=b32 -S init_module,delete_module -k kernel_modules

# --- Time changes (anti-forensics) ---
-a always,exit -F arch=b64 -S adjtimex,settimeofday,clock_settime -k time_change
-a always,exit -F arch=b32 -S adjtimex,settimeofday,clock_settime -k time_change
-w /etc/localtime -p wa -k time_change

# --- Audit configuration protection ---
-w /etc/audit/ -p wa -k audit_config
-w /etc/audit/rules.d/ -p wa -k audit_config

# Make the rules immutable until reboot (prevents runtime tampering).
# Use with care: changes require reboot to take effect.
-e 2
EOF

We just created a complete, focused ruleset for common audit and security questions. We also set the rules to immutable mode (-e 2), which prevents an attacker—or an accidental admin action—from unloading rules at runtime. The tradeoff is operational: rule changes require a reboot.

Now we will compile and load the rules. We are doing this through augenrules so the rules persist and are managed in the standard way.

sudo augenrules --load
sudo auditctl -s

We just loaded the compiled rules into the kernel audit subsystem and printed the audit status. If immutable mode is active, the status output will reflect that rules are locked until reboot.

Finally, we will verify that the rules are present and searchable by key.

sudo auditctl -l | sed -n '1,120p'

We just listed the first portion of the active rules. We should see watches for files like /etc/passwd and keys like identity, sudo, and audit_config.

Step 8: Generate controlled test events and verify evidence collection

Now we will create a few safe, reversible events so we can confirm the pipeline end-to-end: event occurs, audit captures it, and we can query it reliably. We will avoid risky changes and keep everything minimal.

Test 1: Touch a watched file in /etc

We will append a comment to /etc/ssh/sshd_config only if it exists, then revert it. This triggers a watched write event under the ssh key.

if [ -f /etc/ssh/sshd_config ]; then
  echo "# auditd-test $(date -Is)" | sudo tee -a /etc/ssh/sshd_config >/dev/null
  sudo sed -i '$d' /etc/ssh/sshd_config
fi

sudo ausearch -k ssh -ts recent | tail -n 30

We just created and reverted a harmless change to a watched SSH configuration file, then searched for recent events tagged with the ssh key. The output should show the write attempt and metadata about the actor.

Test 2: Execute sudo and confirm privileged command tracking

We will run a benign command through sudo and then search for the priv_cmd key. This confirms we can prove privileged command execution by real users.

sudo -n true 2>/dev/null || true
sudo id -u

sudo ausearch -k priv_cmd -ts recent | tail -n 50

We just executed a privileged command and searched for the corresponding audit events. If the environment requires a password for sudo, the sudo -n true line may fail harmlessly; the sudo id -u will prompt as needed and still generate an auditable event.

Test 3: Confirm audit logs are being written and rotated

We will confirm the audit log file exists, check permissions, and confirm auditd is writing to it. This is the simplest operational check and catches many misconfigurations.

sudo ls -l /var/log/audit/
sudo tail -n 20 /var/log/audit/audit.log

We just verified the audit log directory and inspected recent entries. If the file is updating as we generate events, the logging pipeline is functioning.

Firewall considerations

For a local-only auditd deployment, firewall changes are typically not applicable because auditd writes locally and does not require inbound network access. If we later forward audit events to a remote collector (for example via syslog or an agent), we should treat that as a separate design decision with explicit egress rules, TLS, and authentication. For this baseline, we keep the footprint minimal and avoid opening ports unnecessarily.

Operational notes for enterprise environments

  • Log retention: The rotation settings in auditd.conf are a baseline. In regulated environments, we should align retention with policy and ensure logs are shipped to a central, access-controlled system.
  • Immutability: -e 2 is powerful. We should only enable it when we have a change process that can tolerate reboot-based rule updates.
  • Performance: Audit rules should be intentional. If we expand scope, we should measure overhead and backlog behavior under peak load.
  • Access control: Audit logs contain sensitive information. We should restrict access to /var/log/audit and ensure backups and collectors enforce least privilege.

Troubleshooting

auditd is running but no events appear in /var/log/audit/audit.log

Symptoms: systemctl status auditd shows active, but tail /var/log/audit/audit.log does not change after test events.

  • Likely cause: Kernel auditing disabled or audit backlog issues.
  • Fix: Check kernel audit status and enable auditing at boot.
sudo auditctl -s
cat /proc/cmdline

If enabled is 0 or the kernel command line lacks audit=1, we should apply the boot parameter step and reboot during a maintenance window.

augenrules –load fails or rules do not appear

Symptoms: sudo augenrules --load returns errors, or auditctl -l does not show expected rules.

  • Likely cause: Syntax error in a rules file, or rules are immutable (-e 2) and cannot be changed at runtime.
  • Fix: Validate rules, and if immutable is enabled, plan a reboot after updating rules.
sudo auditctl -s
sudo grep -R --line-number --no-messages '' /etc/audit/rules.d/*.rules | head -n 50

If the status indicates immutability, we should remove or adjust -e 2 in the rules file, then reboot to apply the new rule state. If there is a syntax error, auditd will often log details in system logs.

Disk fills up or auditd suspends logging

Symptoms: System logs mention low disk space, auditd reports suspend actions, or compliance checks show gaps.

  • Likely cause: Insufficient disk allocation for /var/log, overly aggressive auditing, or retention settings too large.
  • Fix: Increase disk space, reduce rule scope, or adjust rotation/retention. Then restart auditd.
df -h /var/log /var/log/audit
sudo systemctl restart auditd
sudo systemctl status auditd --no-pager

We just checked filesystem capacity and restarted auditd to recover from a suspended state after addressing disk pressure.

Time-based searches look wrong or inconsistent

Symptoms: ausearch -ts recent misses events we just generated, or timestamps do not align with other logs.

  • Likely cause: System time drift or timezone confusion.
  • Fix: Confirm time sync and timezone, then re-test.
timedatectl status

We just confirmed time synchronization and timezone settings. Once time is stable, audit timelines become defensible.

Common mistakes

Mistake: Locking rules with -e 2 before the ruleset is validated

Symptom: Attempts to load or modify rules fail, and changes do not take effect until reboot.

Fix: During initial rollout, we can temporarily omit -e 2, validate coverage and noise levels, then re-enable immutability and reboot as a controlled change.

Mistake: Auditing “everything” and creating operational noise

Symptom: Audit logs grow rapidly, performance degrades, and teams stop looking at alerts because the signal is buried.

Fix: Keep rules aligned to real audit use-cases: identity changes, privilege use, sensitive configuration, and persistence mechanisms. Expand only with measured intent and verified value.

Mistake: Assuming auditd running means auditing is complete

Symptom: auditd is active, but early-boot events are missing, or kernel auditing is disabled.

Fix: Verify with auditctl -s and ensure audit=1 is set for early boot coverage, then confirm after reboot.

Mistake: Leaving audit logs readable by non-privileged users

Symptom: Sensitive command lines, usernames, and paths are visible to users who should not have access.

Fix: Keep /var/log/audit restricted to root, and validate permissions regularly.

sudo ls -ld /var/log/audit
sudo ls -l /var/log/audit/audit.log

We just verified directory and file permissions. If they are too permissive, we should correct them and investigate why they drifted.

How do we at NIILAA look at this

This setup is not impressive because it is complex. It is impressive because it is controlled. Every component is intentional. Every configuration has a reason. This is how infrastructure should scale — quietly, predictably, and without drama.

At NIILAA, we help organizations design, deploy, secure, and maintain audit-ready Linux environments in production—whether that means defining evidence-driven audit use-cases, standardizing rules across fleets, integrating centralized log retention, or hardening systems so controls remain trustworthy under pressure.

Website: https://www.niilaa.com
Email: [email protected]
LinkedIn: https://www.linkedin.com/company/niilaa
Facebook: https://www.facebook.com/niilaa.llc

Leave A Comment

All fields marked with an asterisk (*) are required