Installing and Configuring AIDE on CentOS Stream 9: File Integrity Monitoring and Tamper Detection

CentOS tutorial - IT technology blog
CentOS tutorial - IT technology blog

File Integrity Monitoring on Linux: Which Tool Is Right for RHEL/CentOS?

Whenever preparing for a PCI-DSS audit (Requirement 11.5) or ISO 27001 compliance, File Integrity Monitoring (FIM) is always a mandatory item. In reality, once an attacker successfully exploits an RCE vulnerability, their next target is almost certainly critical system files. They typically alter binaries like /usr/bin/login, inject malware into /etc/crontab, or establish backdoors inside /etc/ssh/sshd_config.

To catch these modifications before it is too late, sysadmins generally consider three approaches:

  • Custom Bash script + sha256sum: Periodically hashing files and comparing them with diff. Fast to set up, but crude and brittle.
  • Centralized SIEM/FIM cluster (Wazuh, OSSEC): Excellent real-time monitoring. However, the architecture is heavyweight, requiring at least 2–4 GB of RAM for the management server alone.
  • AIDE (Advanced Intrusion Detection Environment): Lightweight, reliable, and available directly from the standard RHEL/CentOS AppStream repositories.

Practical Comparison of the Three Approaches

Here is a quick breakdown based on real-world operational experience:

Criteria Custom Script (Bash + Hash) Centralized Agent (Wazuh/OSSEC) AIDE
Deployment Complexity Easy at first, a maintenance nightmare at scale Complex; requires setting up a manager, database, and dashboard Done with a single dnf command
CPU/RAM Usage Low for few files; freezes the host during deep scans Runs continuous background daemons, consumes RAM 0% idle RAM; only uses CPU and I/O during scheduled scans
Inspection Scope Usually checks file content hashes only Real-time events, log correlation, audit rules Checks hashes (SHA256/SHA512), permissions, inodes, SELinux, mtime
Best Fit Temporary stopgap Large environments with 50–100+ servers Standalone servers, gateways, VPS instances, or Ansible-managed fleets

Homegrown scripts often overlook key security metrics: they fail to inspect file permissions, suspicious symlinks, or SELinux contexts. Conversely, deploying a full Wazuh stack just to monitor two or three web/database VPS instances is often overkill.

When Should You Choose AIDE for CentOS Stream 9?

On public gateway servers or standalone database instances running CentOS Stream 9, AIDE stands out for its practicality. It does not run persistent background processes that consume valuable RAM, while thoroughly auditing attributes from ownership (UID/GID) and timestamps to file size and cryptographic hashes.

Best of all, you fulfill audit compliance requirements without the overhead and cost of maintaining dedicated management infrastructure.

How to Deploy AIDE on CentOS Stream 9

Step 1: Install AIDE from AppStream

The package is readily available in the default system repositories. Run the following command:

sudo dnf install -y aide aide-selinux

Do not omit the aide-selinux package. Without it, SELinux in Enforcing mode will block AIDE from reading sensitive system files.

Step 2: Fine-Tune the Configuration Rules

Open the primary configuration file:

sudo nano /etc/aide.conf

By default, this file predefines macros specifying which attributes to inspect:

# Standard macro: check SHA256 hash, permissions, inode, user, group, SELinux, ACL
CONTENT_EX = sha256+ftype+p+u+g+n+acl+selinux+xattrs
DATAONLY   = p+u+g+sha256

Pro Tip: The most frequent mistake is monitoring the entire /var/log directory with content rules. Because logs are written continuously, every scan will trigger false positives. Use the ! operator to exclude volatile paths:

# 1. Core directories requiring strict monitoring
/etc          CONTENT_EX
/usr/bin      CONTENT_EX
/usr/sbin     CONTENT_EX
/boot         CONTENT_EX

# 2. Exclude logs, temporary files, and container data
!/var/log/.*
!/var/tmp/.*
!/tmp/.*
!/var/lib/docker/.*
!/var/lib/containers/.*

Step 3: Initialize the Baseline Database

AIDE works by capturing a snapshot of your filesystem’s current state into a database file. Generate the initial baseline snapshot:

sudo aide --init

On an NVMe SSD with roughly 50,000 standard files, this takes about 20–40 seconds. Once completed, the file /var/lib/aide/aide.db.new.gz will be created (around 3–8 MB in size).

Promote this file to become the active baseline database:

sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

Hardening step: If an attacker gains root privileges, they could overwrite this database to conceal their tracks. Prevent tampering by setting the immutable attribute on the database file:

sudo chattr +i /var/lib/aide/aide.db.gz

Step 4: Test Change Detection

Simulate an intrusion by modifying the system hosts file:

echo "192.168.1.50 rogue-c2.internal" | sudo tee -a /etc/hosts

Run a verification scan against the baseline:

sudo aide --check

AIDE will immediately catch the discrepancy and output a detailed report:

AIDE 0.16 found differences between database and filesystem!!
Start timestamp: 2026-10-25 10:30:00

Summary:
  Total number of entries:      54210
  Added entries:                0
  Removed entries:              0
  Changed entries:              1

---------------------------------------------------
Changed entries:
---------------------------------------------------
changed: /etc/hosts

---------------------------------------------------
Detailed information about changes:
---------------------------------------------------
File: /etc/hosts
  Size     : 158                              , 192
  Mtime    : 2026-10-25 09:12:00              , 2026-10-25 10:29:45
  SHA256   : e3b0c44298fc1c149afbf4c8996fb924 , b94d27b9934d3e08a52e52d7da7dabfa

Step 5: Update the Baseline After System Upgrades

Whenever you run dnf upgrade, dozens of binaries and libraries will have their checksums altered. Running an integrity check right after will trigger a flood of false alarms. Rebuild the baseline instead:

# Temporarily remove the immutable flag if set in Step 3
sudo chattr -i /var/lib/aide/aide.db.gz

# Update and replace the baseline database
sudo aide --update
sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz

# Re-lock the database file
sudo chattr +i /var/lib/aide/aide.db.gz

Step 6: Automate via Cron and Route Alerts to Telegram

Manually running scans every day is impractical. Automate the process by creating /usr/local/bin/aide-monitor.sh:

#!/usr/bin/env bash

BOT_TOKEN="123456789:ABCdefGHIjklMNOpqrSTUvwxYZ"
CHAT_ID="-987654321"

# Run the scan with the lowest I/O priority to avoid impacting server performance
OUTPUT=$(ionice -c 3 /usr/sbin/aide --check 2>&1)
EXIT_CODE=$?

# AIDE exit codes: 0 = clean; non-zero = changes detected or error occurred
if [ $EXIT_CODE -ne 0 ]; then
    REPORT_SNIP=$(echo "$OUTPUT" | head -n 25)
    TEXT="⚠️ <b>FIM ALERT ON $(hostname)</b>%0A%0A<code>${REPORT_SNIP}"
    curl -s -X POST "https://api.telegram.org/bot${BOT_TOKEN}/sendMessage" \
        -d "chat_id=${CHAT_ID}" \
        -d "parse_mode=HTML" \
        -d "text=${TEXT}" > /dev/null
fi

Apply strict permissions to the script:

sudo chmod 700 /usr/local/bin/aide-monitor.sh
sudo chown root:root /usr/local/bin/aide-monitor.sh

Schedule it to execute daily at 03:00 AM in root’s crontab:

echo "0 3 * * * /usr/local/bin/aide-monitor.sh" | sudo tee -a /var/spool/cron/root

3 Essential Best Practices for Running AIDE

  1. Throttle Disk I/O: Hashing 50,000 files in a single pass can saturate disk I/O, especially on production database hosts running MySQL or PostgreSQL. Always wrap scan commands with ionice -c 3 so AIDE only consumes idle I/O capacity.
  2. Store Database Copies Off-Host: If an intruder compromises root access, they can readily strip chattr +i. Regularly synchronize aide.db.gz to an external storage server (such as a read-only NFS mount or an S3 bucket with Object Lock enabled).
  3. Protect the AIDE Binary Itself: Record the SHA256 checksum of /usr/sbin/aide in external offline documentation so you can verify the integrity of the detection tool at any time.
Share: