A Three-Stage Security Audit Strategy
Production server security cannot be solved with a single tool. You need to combine three stages: measure (Lynis) → trace (auditd) → enforce (SELinux/AppArmor).
Stage 1 — Automated Security Auditing with Lynis
Lynis scans the entire system, produces a Hardening Index score, and reports weak findings.
Installation
# RHEL/CentOS
sudo yum install -y lynis
# Ubuntu/Debian
sudo apt install -y lynis
# ( save )
git clone https://github.com/CISOfy/lynis /usr/local/lynisRunning a Full System Audit
sudo lynis audit system
# (CI )
sudo lynis audit system --quiet
# Result file save
sudo lynis audit system --log-file /var/log/lynis.log --report-file /var/log/lynis-report.datInterpreting the Report
# check (100 )
grep "hardening_index" /var/log/lynis-report.dat
# WARNING
grep "^warning[]" /var/log/lynis-report.dat
# SUGGESTION
grep "^suggestion[]" /var/log/lynis-report.datTarget score: Keep production servers at 75 or higher. For new servers, aim for 90+ during initial setup.
Manually Remediating Critical Findings
# AIDE file
sudo apt install -y aide
sudo aideinit
sudo mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
#
echo "0 3 * * 0 root /usr/bin/aide --check" >> /etc/cron.d/aide-check
# file
sudo apt purge -y gcc make
# USB
echo "install usb-storage /bin/false" > /etc/modprobe.d/disable-usb-storage.confStage 2 — Event Tracing with auditd
auditd records file access, system calls, and privilege changes in real time at the kernel level.
Install and Enable
sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditdConfiguring Core Audit Rules
# /etc/audit/rules.d/hardening.rules
# (boot to )
-e 2
# when when when
-a always,exit -F arch=b64 -S adjtimex -S settimeofday -k time-change
-a always,exit -F arch=b64 -S clock_settime -k time-change
# User· when
-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/sudoers -p wa -k identity
-w /etc/sudoers.d/ -p wa -k identity
# settings when
-a always,exit -F arch=b64 -S sethostname -S setdomainname -k system-locale
-w /etc/hosts -p wa -k system-locale
-w /etc/network/ -p wa -k system-locale
# · when
-w /var/log/faillog -p wa -k logins
-w /var/log/lastlog -p wa -k logins
# when (sudo, su)
-w /bin/su -p x -k priv-esc
-w /usr/bin/sudo -p x -k priv-esc
-w /etc/sudoers -p wa -k priv-esc
# run when ( path)
-a always,exit -F arch=b64 -S execve -k exec#
sudo augenrules --load
sudo systemctl restart auditd
# check
sudo auditctl -lAnalyzing auditd Logs
#
sudo ausearch -k identity --interpret
# failed when
sudo ausearch -m USER_LOGIN --success no
# User
sudo ausearch -ua 1001 -m EXECVE --interpret | grep -A2 "type=EXECVE"
# 1when when
sudo ausearch -k priv-esc --start recent --interpret
#
sudo aureport --summary
sudo aureport --login --summary
sudo aureport --failed --summaryAlerting integration: Use the audisp-remote plugin to stream events in real time to a central SIEM (Splunk, Elastic).
Stage 3 — Applying SELinux Policy (RHEL/CentOS)
SELinux enforces which files and ports a process can access at the kernel level. Misconfiguration can take services down, so apply it in stages.
Understanding Modes
# check
getenforce # Enforcing / Permissive / Disabled
#
sestatus
# when Permissive (, boot when )
sudo setenforce 0
# settings (/etc/selinux/config)
SELINUX=enforcing #
SELINUX=permissive # ,
SELINUX=disabled #Analyzing Denial Logs and Generating Policy
# SELinux when check
sudo ausearch -m AVC --interpret | tail -30
sudo grep "denied" /var/log/audit/audit.log | tail -20
# audit2why
sudo ausearch -m AVC | audit2why
# audit2allow
sudo ausearch -m AVC | audit2allow -M my_custom_policy
sudo semodule -i my_custom_policy.ppIn Practice — SELinux Configuration for Nginx
# Nginx (8080) Listen
sudo semanage port -a -t http_port_t -p tcp 8080
# http list
sudo semanage port -l | grep http_port_t
# Nginx upstream
sudo setsebool -P httpd_can_network_connect 1
# Nginx NFS
sudo setsebool -P httpd_use_nfs 1
#
sudo semanage fcontext -a -t httpd_sys_content_t "/data/www(/.*)?"
sudo restorecon -Rv /data/wwwAppArmor (Ubuntu Alternative)
# file check
sudo aa-status
# file
sudo aa-enforce /etc/apparmor.d/usr.sbin.nginx
#
sudo journalctl -f | grep apparmor
# complain ( without )
sudo aa-complain /etc/apparmor.d/usr.sbin.nginxAutomation — Recurring Security Audit Script
#!/bin/bash
# /usr/local/bin/security-audit.sh
REPORT_DIR="/var/log/security-audit"
DATE=$(date +%Y%m%d)
mkdir -p "$REPORT_DIR"
echo "=== Security Audit: $DATE ===" > "$REPORT_DIR/$DATE.txt"
# Lynis
lynis audit system --quiet >> "$REPORT_DIR/$DATE.txt" 2>&1
# failed
echo "--- Failed Logins ---" >> "$REPORT_DIR/$DATE.txt"
aureport --failed --login >> "$REPORT_DIR/$DATE.txt"
# SUID file
find / -perm /4000 -type f 2>/dev/null | sort > /tmp/suid_current.txt
if [ -f /tmp/suid_baseline.txt ]; then
diff /tmp/suid_baseline.txt /tmp/suid_current.txt | grep "^>" >> "$REPORT_DIR/$DATE.txt"
fi
cp /tmp/suid_current.txt /tmp/suid_baseline.txt
# ( when)
# mail -s "Security Audit $DATE" admin@example.com < "$REPORT_DIR/$DATE.txt"# 2when run
echo "0 2 * * * root /usr/local/bin/security-audit.sh" > /etc/cron.d/security-audit
chmod 644 /etc/cron.d/security-auditAI tools may assist drafting. Check the evidence in each guide for whether commands were run and which environment was used. Confirm the current docs for your version before applying instructions, and email us about errors. email us
Questions & answers
Ask a question about this guide. We'll review and reply.