Files
NIST-800.53-VM/scripts/nist-800-53-harden-v2.sh

1186 lines
48 KiB
Bash

#!/usr/bin/env bash
###############################################################################
# NIST 800-53 Hardening Script v2 - Ubuntu 24.04 LTS (Proxmox VM Template)
#
# CHANGES FROM v1:
# - iptables instead of UFW (Docker-compatible, CIS-clean)
# - Fixes: ssh service name (not sshd), TMOUT readonly guard,
# AIDE mkdir ordering, auditd.conf inline edits
# - Expanded audit rules (chcon, setfacl, chacl, usermod, mount, DAC, etc.)
# - CIS/Wazuh SCA alignment: kernel module blacklisting, cron/at allow
# files, journald rotation, sudo logging, nullok removal, GRUB audit
# flags, root umask, log permissions, opasswd, rsyslog file creation
# mode, apport disabled, telnet/ftp/rsync removed, AppArmor in GRUB,
# SSH AllowUsers, GSSAPIAuthentication, DisableForwarding,
# HostbasedAuthentication, IgnoreRhosts, PermitUserEnvironment
#
# Maps to control families: AC, AU, CM, IA, SC, SI, MP
# Run as root on a freshly installed Ubuntu 24.04 minimal server after
# running the partition-layout.sh script, then convert to Proxmox template.
#
# Usage: chmod +x nist-800-53-harden-v2.sh && sudo ./nist-800-53-harden-v2.sh
###############################################################################
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
LOG="/var/log/nist-hardening-$(date +%Y%m%d-%H%M%S).log"
exec > >(tee -a "$LOG") 2>&1
banner() { printf '\n\e[1;36m>>> %s\e[0m\n' "$1"; }
if [[ $EUID -ne 0 ]]; then
echo "ERROR: Run this script as root." >&2
exit 1
fi
###############################################################################
# CONFIGURATION — edit these before running
###############################################################################
# The primary non-root admin user (used for SSH AllowUsers, cron.allow, etc.)
ADMIN_USER="${ADMIN_USER:-chris}"
###############################################################################
# 0. PRE-FLIGHT - Update & install required packages
# CM-2 Baseline Configuration / SI-2 Flaw Remediation
###############################################################################
banner "CM-2 / SI-2: System update and baseline packages"
apt-get update -y
apt-get upgrade -y
apt-get dist-upgrade -y
apt-get install -y \
auditd audispd-plugins \
aide aide-common \
libpam-pwquality \
iptables iptables-persistent netfilter-persistent \
chrony \
rsyslog \
acl \
apparmor apparmor-utils \
unattended-upgrades apt-listchanges \
cloud-init \
qemu-guest-agent \
needrestart
# ---------------------------------------------------------------------------
# CM-7 Remove unnecessary packages (CIS 2.4.x, 2.1.x)
# ---------------------------------------------------------------------------
banner "CM-7: Remove unnecessary packages"
REMOVE_PKGS=(
telnet inetutils-telnet
ftp tnftp
rsync
ufw
nftables
apport
snapd
)
for pkg in "${REMOVE_PKGS[@]}"; do
if dpkg -s "$pkg" &>/dev/null; then
apt-get purge -y "$pkg" 2>/dev/null || true
fi
done
apt-get autoremove -y
# Disable apport if config file remains
if [[ -f /etc/default/apport ]]; then
sed -i 's/^enabled=.*/enabled=0/' /etc/default/apport
fi
# Disable motd-news network fetches
systemctl disable --now motd-news.timer 2>/dev/null || true
if [[ -f /etc/default/motd-news ]]; then
sed -i 's/^ENABLED=.*/ENABLED=0/' /etc/default/motd-news
fi
# Disable unnecessary motd scripts
for f in 10-help-text 50-motd-news 88-esm-announce 91-contract-ua-esm-status 91-release-upgrade 95-hwe-eol; do
chmod -x /etc/update-motd.d/$f 2>/dev/null || true
done
###############################################################################
# 1. ACCESS CONTROL (AC)
###############################################################################
# ---------------------------------------------------------------------------
# AC-2 Account Management
# ---------------------------------------------------------------------------
banner "AC-2: Account management"
passwd -l root
for usr in games lp news uucp proxy gnats; do
if id "$usr" &>/dev/null; then
userdel "$usr" 2>/dev/null || true
fi
done
# Default umask 027
sed -i 's/^UMASK.*/UMASK\t\t027/' /etc/login.defs
# Root umask (CIS 5.5.6 / Wazuh 35703)
for rcfile in /root/.bash_profile /root/.bashrc; do
if [[ -f "$rcfile" ]]; then
sed -i '/^umask/d' "$rcfile"
else
touch "$rcfile"
fi
echo "umask 0077" >> "$rcfile"
done
# ---------------------------------------------------------------------------
# AC-7 Unsuccessful Logon Attempts - pam_faillock
# ---------------------------------------------------------------------------
banner "AC-7: Account lockout (pam_faillock)"
cat > /etc/security/faillock.conf <<'EOF'
# AC-7: Lock account after 5 failed attempts for 900 s
deny = 5
fail_interval = 900
unlock_time = 900
even_deny_root
EOF
# Write pam_faillock into common-auth
# Remove any existing faillock lines first to avoid duplicates
sed -i '/pam_faillock/d' /etc/pam.d/common-auth
sed -i '/pam_faillock/d' /etc/pam.d/common-account
# Insert before pam_unix
sed -i '/^auth.*pam_unix.so/i auth required pam_faillock.so preauth' \
/etc/pam.d/common-auth
sed -i '/^auth.*pam_unix.so/a auth [default=die] pam_faillock.so authfail' \
/etc/pam.d/common-auth
echo "account required pam_faillock.so" >> /etc/pam.d/common-account
# ---------------------------------------------------------------------------
# AC-8 System Use Notification - login banners
# ---------------------------------------------------------------------------
banner "AC-8: Login banners"
BANNER_TEXT="========================================================================
WARNING: This system is for authorized use only.
All activity is monitored and recorded. Unauthorized access is prohibited
and subject to criminal and civil penalties.
========================================================================"
echo "$BANNER_TEXT" > /etc/issue
echo "$BANNER_TEXT" > /etc/issue.net
cat > /etc/motd <<'EOF'
**** NOTICE: Use of this system constitutes consent to monitoring. ****
EOF
# ---------------------------------------------------------------------------
# AC-11 / AC-12 Session Lock / Termination
# ---------------------------------------------------------------------------
banner "AC-11 / AC-12: Session timeout"
cat > /etc/profile.d/nist-timeout.sh <<'EOF'
# AC-11/12: Idle session timeout - 15 minutes
if [ -z "${TMOUT:-}" ]; then
readonly TMOUT=900
export TMOUT
fi
EOF
chmod 644 /etc/profile.d/nist-timeout.sh
###############################################################################
# 2. AUDIT AND ACCOUNTABILITY (AU)
###############################################################################
banner "AU-2 / AU-3 / AU-12: Audit configuration"
# ---------------------------------------------------------------------------
# AU-2/3/12 Audit Events - comprehensive rules for CIS/Wazuh
# ---------------------------------------------------------------------------
cat > /etc/audit/rules.d/nist-800-53.rules <<'AUDITRULES'
## ---- Remove any existing rules ----
-D
## ---- Buffer size ----
-b 8192
## ---- Failure mode: 1 = printk, 2 = panic ----
-f 1
## ---- Time changes (AU-8 / CIS 4.1.3.4 / Wazuh 35734) ----
-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
## ---- User/group changes (AC-2 / CIS 4.1.3.7 / Wazuh 35737) ----
-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
## ---- Network configuration (CIS 4.1.3.5 / Wazuh 35735) ----
-a always,exit -F arch=b64 -S sethostname,setdomainname -k network-config
-a always,exit -F arch=b32 -S sethostname,setdomainname -k network-config
-w /etc/hosts -p wa -k network-config
-w /etc/hostname -p wa -k network-config
-w /etc/netplan/ -p wa -k network-config
-w /etc/network/ -p wa -k network-config
-w /etc/networks -p wa -k network-config
## ---- Login/logout events (CIS 4.1.3.10 / Wazuh 35741) ----
-w /var/log/lastlog -p wa -k logins
-w /var/log/faillog -p wa -k logins
-w /var/log/wtmp -p wa -k logins
-w /var/log/btmp -p wa -k logins
## ---- Session initiation (CIS 4.1.3.11 / Wazuh 35740) ----
-w /var/run/utmp -p wa -k session
## ---- Sudo configuration changes (CIS 4.1.3.1 / Wazuh 35731) ----
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d -p wa -k scope
## ---- Sudo log file (CIS 4.1.3.3 / Wazuh 35733) ----
-w /var/log/sudo.log -p wa -k actions
## ---- Actions as another user (CIS 4.1.3.2 / Wazuh 35732) ----
-a always,exit -F arch=b64 -S execve -C euid!=uid -F auid!=unset -k user_emulation
-a always,exit -F arch=b32 -S execve -C euid!=uid -F auid!=unset -k user_emulation
## ---- Privileged commands ----
-a always,exit -F arch=b64 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k privileged
-a always,exit -F arch=b32 -S execve -F euid=0 -F auid>=1000 -F auid!=4294967295 -k privileged
## ---- Unsuccessful file access (CIS 4.1.3.6 / Wazuh 35736) ----
-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access
-a always,exit -F arch=b64 -S open,openat,creat,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access
-a always,exit -F arch=b32 -S open,openat,creat,truncate,ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access
-a always,exit -F arch=b32 -S open,openat,creat,truncate,ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access
## ---- DAC permission changes (CIS 4.1.3.8 / Wazuh 35738) ----
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b32 -S chown,fchown,lchown,fchownat -F auid>=1000 -F auid!=4294967295 -k perm_mod
-a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod
## ---- Successful file system mounts (CIS 4.1.3.9 / Wazuh 35739) ----
-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts
-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=4294967295 -k mounts
## ---- File deletion events (CIS 4.1.3.12 / Wazuh 35742) ----
-a always,exit -F arch=b64 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=4294967295 -k delete
-a always,exit -F arch=b32 -S unlink,unlinkat,rename,renameat -F auid>=1000 -F auid!=4294967295 -k delete
## ---- Mandatory access control changes (CIS 4.1.3.13 / Wazuh 35743) ----
-w /etc/apparmor/ -p wa -k MAC-policy
-w /etc/apparmor.d/ -p wa -k MAC-policy
## ---- chcon command (CIS 4.1.3.14 / Wazuh 35744) ----
-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=4294967295 -k perm_chng
## ---- setfacl command (CIS 4.1.3.15 / Wazuh 35745) ----
-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=4294967295 -k perm_chng
## ---- chacl command (CIS 4.1.3.16 / Wazuh 35746) ----
-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=4294967295 -k perm_chng
## ---- usermod command (CIS 4.1.3.17 / Wazuh 35747) ----
-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=4294967295 -k usermod
## ---- Kernel module loading (CIS 4.1.3.18 / Wazuh 35748) ----
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -k kernel_modules
-a always,exit -F arch=b32 -S init_module,finit_module,delete_module,create_module,query_module -k kernel_modules
-w /sbin/insmod -p x -k kernel_modules
-w /sbin/rmmod -p x -k kernel_modules
-w /sbin/modprobe -p x -k kernel_modules
-w /bin/kmod -p x -k kernel_modules
## ---- Make the audit configuration immutable (requires reboot to change) ----
-e 2
AUDITRULES
# ---------------------------------------------------------------------------
# AU-4 Audit Log Storage (CIS 4.1.2.x / Wazuh 35728-35730)
# ---------------------------------------------------------------------------
banner "AU-4: Audit log retention"
# Edit auditd.conf inline
AUDITD_CONF="/etc/audit/auditd.conf"
cp "$AUDITD_CONF" "${AUDITD_CONF}.bak"
sed -i 's/^max_log_file_action.*/max_log_file_action = keep_logs/' "$AUDITD_CONF"
sed -i 's/^space_left_action.*/space_left_action = email/' "$AUDITD_CONF"
sed -i 's/^admin_space_left_action.*/admin_space_left_action = halt/' "$AUDITD_CONF"
# Add space thresholds if not present
grep -q '^space_left ' "$AUDITD_CONF" || echo "space_left = 75" >> "$AUDITD_CONF"
grep -q '^admin_space_left ' "$AUDITD_CONF" || echo "admin_space_left = 50" >> "$AUDITD_CONF"
# Ensure max_log_file is set
grep -q '^max_log_file ' "$AUDITD_CONF" || sed -i '1i max_log_file = 50' "$AUDITD_CONF"
# Set permissions on audit config files (CIS 4.1.4.5 / Wazuh 35752)
find /etc/audit/ -type f \( -name '*.conf' -o -name '*.rules' \) -exec chmod 640 {} \;
chown -R root:root /etc/audit/
# Set permissions on audit tools (CIS 4.1.4.9 / Wazuh 35755)
chmod 755 /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/augenrules 2>/dev/null || true
systemctl enable auditd
systemctl restart auditd || augenrules --load
# ---------------------------------------------------------------------------
# AU-8 Timestamps / NTP (chrony)
# ---------------------------------------------------------------------------
banner "AU-8: NTP time synchronization (chrony)"
cat > /etc/chrony/chrony.conf <<'EOF'
# NIST 800-53 AU-8: Authoritative time source
pool ntp.ubuntu.com iburst maxsources 4
pool time.nist.gov iburst maxsources 2
keyfile /etc/chrony/chrony.keys
driftfile /var/lib/chrony/chrony.drift
logdir /var/log/chrony
maxupdateskew 100.0
rtcsync
makestep 1 3
EOF
systemctl enable chrony
systemctl restart chrony
# Disable systemd-timesyncd (Wazuh 35589 wants one or the other)
systemctl stop systemd-timesyncd 2>/dev/null || true
systemctl disable systemd-timesyncd 2>/dev/null || true
systemctl mask systemd-timesyncd 2>/dev/null || true
###############################################################################
# 3. IDENTIFICATION AND AUTHENTICATION (IA)
###############################################################################
# ---------------------------------------------------------------------------
# IA-5 Password Quality (CIS 5.4.x / Wazuh 35681, 35683)
# ---------------------------------------------------------------------------
banner "IA-5: Password quality (pam_pwquality)"
cat > /etc/security/pwquality.conf <<'EOF'
# IA-5(1): Password complexity (CIS 5.4.1)
minlen = 15
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
minclass = 4
difok = 8
maxrepeat = 3
maxsequence = 3
maxclassrepeat = 4
gecoscheck = 1
dictcheck = 1
enforcing = 1
EOF
# Password aging (IA-5 / CIS 5.5.1 / Wazuh 35694, 35695)
sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS\t60/' /etc/login.defs
sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS\t1/' /etc/login.defs
sed -i 's/^PASS_WARN_AGE.*/PASS_WARN_AGE\t14/' /etc/login.defs
# Set INACTIVE period for new accounts (CIS 5.5.3 / Wazuh 35698)
useradd -D -f 30
# Apply aging to existing admin user
if id "$ADMIN_USER" &>/dev/null; then
chage -M 60 -m 1 -W 14 -I 30 "$ADMIN_USER"
fi
# ---------------------------------------------------------------------------
# IA-5 PAM configuration (CIS 5.3.x / Wazuh 35672, 35673, 35675, 35687-35690)
# ---------------------------------------------------------------------------
banner "IA-5: PAM hardening"
# Remove nullok from all PAM files (Wazuh 35690)
sed -i 's/ nullok//g' /etc/pam.d/common-auth
sed -i 's/ nullok//g' /etc/pam.d/common-password
# pam_pwhistory: remember last 24 passwords (Wazuh 35675, 35687, 35688, 35689)
sed -i '/pam_pwhistory/d' /etc/pam.d/common-password
sed -i '/^password.*pam_unix.so/i password required pam_pwhistory.so remember=24 use_authtok enforce_for_root retry=3' \
/etc/pam.d/common-password
# Ensure pam_unix is configured properly (Wazuh 35672)
# pam_unix should be present in common-auth, common-account, common-password, common-session
# Verify — these should already exist from the default Ubuntu PAM config
# Create opasswd file with correct permissions (Wazuh 35770)
touch /etc/security/opasswd /etc/security/opasswd.old
chmod 600 /etc/security/opasswd /etc/security/opasswd.old
chown root:root /etc/security/opasswd /etc/security/opasswd.old
###############################################################################
# 4. SYSTEM AND COMMUNICATIONS PROTECTION (SC)
###############################################################################
# ---------------------------------------------------------------------------
# SC-5 / SC-7 Firewall - iptables with persistent rules
# ---------------------------------------------------------------------------
banner "SC-5 / SC-7: iptables firewall"
# Flush existing rules
iptables -F
iptables -X
iptables -Z
ip6tables -F
ip6tables -X
ip6tables -Z
# ---- DEFAULT POLICIES: deny all ----
iptables -P INPUT DROP
iptables -P FORWARD DROP
iptables -P OUTPUT DROP
ip6tables -P INPUT DROP
ip6tables -P FORWARD DROP
ip6tables -P OUTPUT DROP
# ---- LOOPBACK (CIS 3.5.3.3.1 / Wazuh 35623) ----
iptables -A INPUT -i lo -j ACCEPT
iptables -A OUTPUT -o lo -j ACCEPT
iptables -A INPUT ! -i lo -s 127.0.0.0/8 -j DROP
ip6tables -A INPUT -i lo -j ACCEPT
ip6tables -A OUTPUT -o lo -j ACCEPT
ip6tables -A INPUT ! -i lo -s ::1 -j DROP
# ---- CONNECTION TRACKING ----
iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -m conntrack --ctstate INVALID -j DROP
ip6tables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ip6tables -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
ip6tables -A INPUT -m conntrack --ctstate INVALID -j DROP
# ---- ICMP CONTROL ----
# Allow essential ICMP types, drop the rest
iptables -A INPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A INPUT -p icmp --icmp-type time-exceeded -j ACCEPT
iptables -A INPUT -p icmp --icmp-type echo-reply -j ACCEPT
# Rate-limit inbound pings
iptables -A INPUT -p icmp --icmp-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT
iptables -A INPUT -p icmp -j DROP
iptables -A OUTPUT -p icmp --icmp-type echo-request -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type destination-unreachable -j ACCEPT
iptables -A OUTPUT -p icmp --icmp-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type destination-unreachable -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type time-exceeded -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-reply -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type echo-request -m limit --limit 1/s --limit-burst 4 -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-solicitation -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type neighbor-advertisement -j ACCEPT
ip6tables -A INPUT -p icmpv6 --icmpv6-type router-advertisement -j ACCEPT
ip6tables -A INPUT -p icmpv6 -j DROP
ip6tables -A OUTPUT -p icmpv6 -j ACCEPT
# ---- INBOUND SERVICES ----
# SSH - rate limited: max 4 new connections per 60 seconds per source IP
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --set --name SSH --rsource
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j DROP
iptables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --set --name SSH --rsource
ip6tables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW \
-m recent --update --seconds 60 --hitcount 4 --name SSH --rsource -j DROP
ip6tables -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT
# ---- OUTBOUND SERVICES ----
# DNS
iptables -A OUTPUT -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 53 -m conntrack --ctstate NEW -j ACCEPT
# HTTP/HTTPS (apt updates, downloads)
iptables -A OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 80 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 443 -m conntrack --ctstate NEW -j ACCEPT
# NTP
iptables -A OUTPUT -p udp --dport 123 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p udp --dport 123 -m conntrack --ctstate NEW -j ACCEPT
# Wazuh agent (remove if not using Wazuh)
iptables -A OUTPUT -p tcp --dport 1514 -m conntrack --ctstate NEW -j ACCEPT
iptables -A OUTPUT -p tcp --dport 1515 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 1514 -m conntrack --ctstate NEW -j ACCEPT
ip6tables -A OUTPUT -p tcp --dport 1515 -m conntrack --ctstate NEW -j ACCEPT
# ---- LOGGING dropped packets ----
iptables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IPT_INPUT_DROP: " --log-level 4
iptables -A FORWARD -m limit --limit 5/min -j LOG --log-prefix "IPT_FORWARD_DROP: " --log-level 4
iptables -A OUTPUT -m limit --limit 5/min -j LOG --log-prefix "IPT_OUTPUT_DROP: " --log-level 4
ip6tables -A INPUT -m limit --limit 5/min -j LOG --log-prefix "IP6T_INPUT_DROP: " --log-level 4
ip6tables -A FORWARD -m limit --limit 5/min -j LOG --log-prefix "IP6T_FORWARD_DROP: " --log-level 4
ip6tables -A OUTPUT -m limit --limit 5/min -j LOG --log-prefix "IP6T_OUTPUT_DROP: " --log-level 4
# ---- DOCKER-USER chain (pre-create for Docker compatibility) ----
iptables -N DOCKER-USER 2>/dev/null || true
iptables -A DOCKER-USER -j RETURN 2>/dev/null || true
# ---- SAVE RULES ----
mkdir -p /etc/iptables
iptables-save > /etc/iptables/rules.v4
ip6tables-save > /etc/iptables/rules.v6
# Enable persistence
systemctl enable netfilter-persistent
echo "iptables rules saved and persistent."
echo "Current INPUT policy: $(iptables -L INPUT | head -1)"
echo "Current OUTPUT policy: $(iptables -L OUTPUT | head -1)"
# ---------------------------------------------------------------------------
# SC-8 / SC-13 SSH hardening
# ---------------------------------------------------------------------------
banner "SC-8 / SC-13: SSH hardening"
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
cat > /etc/ssh/sshd_config.d/nist-hardening.conf <<SSHEOF
# --------------- NIST 800-53 SSH Hardening ---------------
Protocol 2
# Authentication
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
MaxAuthTries 3
LoginGraceTime 60
# Access control (CIS 5.2.4 / Wazuh 35643)
AllowUsers ${ADMIN_USER}
# Session
ClientAliveInterval 300
ClientAliveCountMax 3
MaxSessions 3
MaxStartups 10:30:60
# Cryptography (SC-13)
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com
HostKeyAlgorithms ssh-ed25519,rsa-sha2-512,rsa-sha2-256
# Banner (AC-8)
Banner /etc/issue.net
# Disable forwarding (CIS 5.2.13 / Wazuh 35647)
DisableForwarding yes
# Disable unused auth methods (Wazuh 35648, 35649, 35650, 35660)
GSSAPIAuthentication no
HostbasedAuthentication no
IgnoreRhosts yes
PermitUserEnvironment no
# Disable X11 forwarding
X11Forwarding no
# Logging (AU-3 / CIS 5.2.5 / Wazuh 35653)
LogLevel VERBOSE
# Suppress login info (handled by MOTD)
PrintLastLog no
SSHEOF
# Remove small Diffie-Hellman moduli
awk '$5 >= 3071' /etc/ssh/moduli > /etc/ssh/moduli.safe && mv /etc/ssh/moduli.safe /etc/ssh/moduli
# Test and restart (Ubuntu 24.04 uses 'ssh' not 'sshd')
sshd -t && systemctl restart ssh
# Set permissions on SSH host key files (CIS 5.2.1-5.2.2 / Wazuh 35641, 35642)
find /etc/ssh -name 'ssh_host_*_key' -exec chmod 600 {} \;
find /etc/ssh -name 'ssh_host_*_key.pub' -exec chmod 644 {} \;
chown root:root /etc/ssh/ssh_host_*
chmod 600 /etc/ssh/sshd_config
# ---------------------------------------------------------------------------
# SC-28 Filesystem mount hardening
# ---------------------------------------------------------------------------
banner "SC-28 / MP-2: Filesystem mount hardening"
# Harden /dev/shm
if grep -q '/dev/shm' /etc/fstab; then
sed -i 's|^\(.*\s/dev/shm\s.*\)defaults\(.*\)|\1defaults,noexec,nosuid,nodev\2|' /etc/fstab
else
echo "tmpfs /dev/shm tmpfs defaults,noexec,nosuid,nodev 0 0" >> /etc/fstab
fi
###############################################################################
# 5. KERNEL HARDENING (SC / SI)
###############################################################################
banner "SC-3 / SC-39 / SI-16: Kernel parameter hardening"
cat > /etc/sysctl.d/99-nist-hardening.conf <<'SYSCTL'
# ----- Network (SC-5 / SC-7) -----
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0
net.ipv4.conf.all.secure_redirects = 0
net.ipv4.conf.default.secure_redirects = 0
net.ipv4.tcp_syncookies = 1
net.ipv4.conf.all.log_martians = 1
net.ipv4.conf.default.log_martians = 1
net.ipv4.icmp_echo_ignore_broadcasts = 1
net.ipv4.icmp_ignore_bogus_error_responses = 1
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1
net.ipv6.conf.all.accept_ra = 0
net.ipv6.conf.default.accept_ra = 0
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_max_syn_backlog = 4096
# ----- Kernel (SC-3 / SI-16) -----
kernel.kptr_restrict = 2
kernel.dmesg_restrict = 1
kernel.perf_event_paranoid = 3
kernel.randomize_va_space = 2
kernel.yama.ptrace_scope = 2
fs.suid_dumpable = 0
kernel.unprivileged_bpf_disabled = 1
net.core.bpf_jit_harden = 2
kernel.unprivileged_userns_clone = 0
# Additional CIS hardened parameters
fs.protected_fifos = 2
fs.protected_hardlinks = 1
fs.protected_regular = 2
fs.protected_symlinks = 1
SYSCTL
sysctl --system
# Disable core dumps via limits
cat > /etc/security/limits.d/nist-coredump.conf <<'EOF'
* hard core 0
EOF
# Systemd core dump disable
mkdir -p /etc/systemd/coredump.conf.d
cat > /etc/systemd/coredump.conf.d/disable.conf <<'EOF'
[Coredump]
Storage=none
ProcessSizeMax=0
EOF
###############################################################################
# 6. CONFIGURATION MANAGEMENT (CM)
###############################################################################
# ---------------------------------------------------------------------------
# CM-7 Disable unnecessary services and kernel modules
# ---------------------------------------------------------------------------
banner "CM-7: Disable unnecessary services and protocols"
DISABLE_SVCS=(
avahi-daemon cups bluetooth isc-dhcp-server rpcbind
nfs-server vsftpd apache2 nginx ModemManager rsync
)
for svc in "${DISABLE_SVCS[@]}"; do
if systemctl list-unit-files "${svc}.service" &>/dev/null; then
systemctl disable --now "$svc" 2>/dev/null || true
systemctl mask "$svc" 2>/dev/null || true
fi
done
# Disable uncommon filesystems (CIS 1.1.1.x / Wazuh 35509)
cat > /etc/modprobe.d/cis-filesystems.conf <<'EOF'
install cramfs /bin/false
install freevxfs /bin/false
install jffs2 /bin/false
install hfs /bin/false
install hfsplus /bin/false
install squashfs /bin/false
install udf /bin/false
install afs /bin/false
install ceph /bin/false
install cifs /bin/false
install exfat /bin/false
install fat /bin/false
install fscache /bin/false
install fuse /bin/false
install gfs2 /bin/false
install nfs_common /bin/false
install nfsd /bin/false
install smbfs_common /bin/false
blacklist cramfs
blacklist freevxfs
blacklist jffs2
blacklist hfs
blacklist hfsplus
blacklist squashfs
blacklist udf
blacklist afs
blacklist ceph
blacklist cifs
blacklist exfat
blacklist fat
blacklist fscache
blacklist fuse
blacklist gfs2
blacklist nfs_common
blacklist nfsd
blacklist smbfs_common
EOF
# Disable uncommon network protocols (CIS 3.1.x / Wazuh 35604-35607)
cat > /etc/modprobe.d/cis-network-protocols.conf <<'EOF'
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
blacklist dccp
blacklist sctp
blacklist rds
blacklist tipc
EOF
# Disable USB storage (MP-7)
cat > /etc/modprobe.d/cis-usb-storage.conf <<'EOF'
install usb-storage /bin/false
blacklist usb-storage
EOF
# ---------------------------------------------------------------------------
# CM-6 File permissions and access control
# ---------------------------------------------------------------------------
banner "CM-6: Critical file permissions"
chmod 600 /etc/shadow /etc/gshadow
chmod 644 /etc/passwd /etc/group
chmod 600 /boot/grub/grub.cfg 2>/dev/null || true
chmod 700 /root
chmod 600 /etc/crontab
chmod 700 /etc/cron.d /etc/cron.daily /etc/cron.hourly /etc/cron.monthly /etc/cron.weekly
chmod 600 /etc/ssh/sshd_config
# Restrict cron and at to authorized users (CIS 5.1.8-5.1.9 / Wazuh 35600, 35601)
touch /etc/cron.allow /etc/at.allow
chmod 640 /etc/cron.allow /etc/at.allow
chown root:root /etc/cron.allow /etc/at.allow
echo "root" > /etc/cron.allow
echo "$ADMIN_USER" >> /etc/cron.allow
echo "root" > /etc/at.allow
echo "$ADMIN_USER" >> /etc/at.allow
# Remove cron.deny and at.deny (CIS wants allow-files only)
rm -f /etc/cron.deny /etc/at.deny
# Fix log file permissions (CIS 4.2.3 / Wazuh 35722)
find /var/log -type f -exec chmod g-wx,o-rwx {} +
find /var/log -type d -exec chmod g-wx,o-rwx {} +
# Restrict su to sudo group (AC-6 / Wazuh 35668)
# Remove existing pam_wheel lines and add the correct one
sed -i '/pam_wheel.so/d' /etc/pam.d/su
echo "auth required pam_wheel.so use_uid group=sudo" >> /etc/pam.d/su
# ---------------------------------------------------------------------------
# Sudo logging (CIS 5.3.4 / Wazuh 35664)
# ---------------------------------------------------------------------------
banner "CM-6: Sudo logging"
cat > /etc/sudoers.d/nist-logging <<'EOF'
Defaults logfile="/var/log/sudo.log"
Defaults log_input,log_output
Defaults iolog_dir="/var/log/sudo-io"
EOF
chmod 440 /etc/sudoers.d/nist-logging
mkdir -p /var/log/sudo-io
###############################################################################
# 7. SYSTEM AND INFORMATION INTEGRITY (SI)
###############################################################################
# ---------------------------------------------------------------------------
# SI-2 Automatic security updates
# ---------------------------------------------------------------------------
banner "SI-2: Automatic security updates"
cat > /etc/apt/apt.conf.d/50unattended-upgrades <<'EOF'
Unattended-Upgrade::Allowed-Origins {
"${distro_id}:${distro_codename}-security";
"${distro_id}ESMApps:${distro_codename}-apps-security";
"${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Mail "root";
EOF
cat > /etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Unattended-Upgrade "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
EOF
# ---------------------------------------------------------------------------
# SI-7 AIDE file integrity monitoring
# ---------------------------------------------------------------------------
banner "SI-7: AIDE file integrity database"
# Configure AIDE to also cover audit tools (CIS 4.1.4.11 / Wazuh 35760)
cat > /etc/aide/aide.conf.d/99_nist_custom <<'EOF'
# NIST 800-53 SI-7: File integrity monitoring
/boot Full
/bin Full
/sbin Full
/lib Full
/lib64 Full
/usr/bin Full
/usr/sbin Full
/usr/lib Full
/etc Full
!/etc/mtab
!/etc/adjtime
!/var/log
!/var/spool
!/var/cache
# CIS 4.1.4.11 - Audit tool integrity
/sbin/auditctl p+i+n+u+g+s+b+acl+xattrs+sha512
/sbin/auditd p+i+n+u+g+s+b+acl+xattrs+sha512
/sbin/ausearch p+i+n+u+g+s+b+acl+xattrs+sha512
/sbin/aureport p+i+n+u+g+s+b+acl+xattrs+sha512
/sbin/autrace p+i+n+u+g+s+b+acl+xattrs+sha512
/sbin/augenrules p+i+n+u+g+s+b+acl+xattrs+sha512
EOF
aideinit -y -f 2>/dev/null || true
cat > /etc/cron.daily/aide-check <<'AIDECRON'
#!/bin/bash
/usr/bin/aide --check --config=/etc/aide/aide.conf | /usr/bin/mail -s "AIDE report: $(hostname)" root 2>/dev/null
AIDECRON
chmod 700 /etc/cron.daily/aide-check
###############################################################################
# 8. LOGGING (AU / Wazuh 35708, 35719, 35720)
###############################################################################
banner "AU: Logging configuration"
# Journald rotation (CIS 4.2.1.3 / Wazuh 35708)
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/nist.conf <<'EOF'
[Journal]
Compress=yes
Storage=persistent
ForwardToSyslog=yes
SystemMaxUse=500M
SystemKeepFree=1G
SystemMaxFileSize=50M
MaxRetentionSec=1month
EOF
systemctl restart systemd-journald
# Rsyslog file creation mode (CIS 4.2.2.4 / Wazuh 35719)
cat > /etc/rsyslog.d/50-nist.conf <<'EOF'
# CIS 4.2.2.4: Ensure rsyslog log file creation mode is configured
$FileCreateMode 0640
$DirCreateMode 0750
$Umask 0027
EOF
# Remote logging placeholder (CIS 4.2.2.6 / Wazuh 35720)
# Uncomment and edit if shipping to a remote syslog server
# If using Wazuh, this is handled by the Wazuh agent instead
cat > /etc/rsyslog.d/99-remote.conf <<'EOF'
# CIS 4.2.2.6: Forward logs to remote host
# Uncomment the line below and set your syslog/SIEM server
# *.* action(type="omfwd" target="your-siem.example.com" port="514" protocol="tcp")
EOF
systemctl restart rsyslog
###############################################################################
# 9. AppArmor ENFORCEMENT (AC-3 / AC-6)
###############################################################################
banner "AC-3 / AC-6: AppArmor enforcement"
systemctl enable apparmor
aa-enforce /etc/apparmor.d/* 2>/dev/null || true
# Ensure AppArmor is in bootloader config (CIS 1.3.1.2 / Wazuh 35537)
GRUB_DEFAULT="/etc/default/grub"
if ! grep -q 'apparmor=1' "$GRUB_DEFAULT"; then
sed -i 's/^GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 apparmor=1 security=apparmor"/' "$GRUB_DEFAULT"
fi
###############################################################################
# 10. GRUB / BOOT HARDENING (SI-7 / AC-3)
###############################################################################
banner "SI-7 / AC-3: GRUB boot hardening"
# Enable auditing for processes prior to auditd (CIS 4.1.1.3 / Wazuh 35725)
# Enable audit_backlog_limit (CIS 4.1.1.4 / Wazuh 35726)
if ! grep -q 'audit=1' "$GRUB_DEFAULT"; then
sed -i 's/^GRUB_CMDLINE_LINUX="\(.*\)"/GRUB_CMDLINE_LINUX="\1 audit=1 audit_backlog_limit=8192"/' "$GRUB_DEFAULT"
fi
# Disable recovery mode
sed -i 's/^#\?GRUB_DISABLE_RECOVERY=.*/GRUB_DISABLE_RECOVERY="true"/' "$GRUB_DEFAULT"
update-grub 2>/dev/null || true
# GRUB password (CIS 1.4.1 / Wazuh 35540)
# -----------------------------------------------------------------------
# IMPORTANT: Generate your own hash: grub-mkpasswd-pbkdf2
# Then replace <HASH> below and uncomment the block.
# -----------------------------------------------------------------------
# cat > /etc/grub.d/40_custom <<'GRUBPW'
# #!/bin/sh
# exec tail -n +3 $0
# set superusers="grubadmin"
# password_pbkdf2 grubadmin <HASH>
# GRUBPW
# chmod 755 /etc/grub.d/40_custom
# update-grub
###############################################################################
# 11. PROXMOX TEMPLATE PREPARATION
###############################################################################
banner "Proxmox template preparation"
# Enable QEMU guest agent
systemctl enable qemu-guest-agent
# Cloud-init config
cat > /etc/cloud/cloud.cfg.d/99_proxmox.cfg <<'EOF'
datasource_list: [NoCloud, ConfigDrive]
EOF
# Machine-id regenerated on clone
truncate -s 0 /etc/machine-id
rm -f /var/lib/dbus/machine-id
ln -s /etc/machine-id /var/lib/dbus/machine-id 2>/dev/null || true
# Clear SSH host keys (regenerated on first boot)
rm -f /etc/ssh/ssh_host_*
# Firstboot service to regenerate keys and AIDE DB
cat > /etc/systemd/system/firstboot-harden.service <<'SVC'
[Unit]
Description=First-boot tasks for hardened template
ConditionPathExists=!/var/lib/firstboot-done
After=network-online.target
[Service]
Type=oneshot
ExecStart=/bin/bash -c '\
dpkg-reconfigure openssh-server && \
systemctl restart ssh && \
find /etc/ssh -name "ssh_host_*_key" -exec chmod 600 {} \; && \
find /etc/ssh -name "ssh_host_*_key.pub" -exec chmod 644 {} \; && \
chown root:root /etc/ssh/ssh_host_* && \
aideinit -y -f && \
touch /var/lib/firstboot-done'
RemainAfterExit=yes
[Install]
WantedBy=multi-user.target
SVC
systemctl enable firstboot-harden.service
# Rebuild initramfs with module blacklists
update-initramfs -u
# Clean up
apt-get autoremove -y
apt-get clean
rm -rf /tmp/* /var/tmp/*
find /var/log -type f -exec truncate -s 0 {} \;
history -c
###############################################################################
# SUMMARY
###############################################################################
banner "NIST 800-53 Hardening v2 Complete"
cat <<SUMMARY
╔═══════════════════════════════════════════════════════════════════╗
║ NIST 800-53 + CIS/Wazuh Controls Applied ║
╠═══════════════════════════════════════════════════════════════════╣
║ ║
║ FIREWALL (iptables) ║
║ Default deny in/out/forward ║
║ SSH rate-limited (4/min per source) ║
║ ICMP type-filtered with rate limiting ║
║ Outbound: DNS, HTTP/S, NTP, Wazuh only ║
║ DOCKER-USER chain pre-created ║
║ Persistent via iptables-persistent ║
║ ║
║ ACCESS CONTROL ║
║ AC-2 Account management, root locked ║
║ AC-7 Faillock (5 attempts / 15 min) ║
║ AC-8 Login banners ║
║ AC-11 Session timeout (15 min, readonly) ║
║ AC-17 SSH hardened (key-only, AllowUsers) ║
║ ║
║ AUDIT ║
║ AU-2/3 Comprehensive rules (CIS 4.1.3.1-4.1.3.18) ║
║ AU-4 Log retention: keep_logs, space alerts ║
║ AU-8 Chrony NTP, systemd-timesyncd disabled ║
║ ║
║ AUTHENTICATION ║
║ IA-5 Password quality (minlen=15, minclass=4, maxseq=3) ║
║ IA-5 PAM: faillock, pwhistory, nullok removed ║
║ IA-5 Password aging on existing + future accounts ║
║ IA-5 opasswd permissions set ║
║ ║
║ SYSTEM PROTECTION ║
║ SC-8 SSH: modern crypto, DisableForwarding, GSSAPI off ║
║ SC-28 Mount hardening (/dev/shm) ║
║ SI-2 Unattended security upgrades ║
║ SI-7 AIDE with audit tool integrity ║
║ SI-16 ASLR, ptrace, BPF, core dumps disabled ║
║ ║
║ CONFIGURATION MANAGEMENT ║
║ CM-6 File permissions, sudo logging, su restricted ║
║ CM-7 Services disabled/masked, packages purged ║
║ CM-7 Filesystem + network modules blacklisted ║
║ CM-7 USB storage disabled ║
║ ║
║ LOGGING ║
║ Journald: persistent, rotated, size-limited ║
║ Rsyslog: file mode 0640, remote placeholder ready ║
║ Sudo: full I/O logging enabled ║
║ ║
║ BOOT ║
║ AppArmor enforced + in GRUB cmdline ║
║ audit=1 audit_backlog_limit=8192 in GRUB ║
║ Recovery mode disabled ║
║ GRUB password: MANUAL STEP (see Section 10) ║
║ ║
║ WAZUH SCA FIXES ║
║ 35509 Filesystem modules blacklisted ║
║ 35522 /var nodev (set in partition script) ║
║ 35537 AppArmor in bootloader ║
║ 35545 Apport removed ║
║ 35573 rsync removed ║
║ 35585 telnet removed ║
║ 35587 ftp removed ║
║ 35589 systemd-timesyncd masked (chrony used) ║
║ 35600 cron.allow created ║
║ 35601 at.allow created ║
║ 35604 dccp blacklisted ║
║ 35605 tipc blacklisted ║
║ 35606 rds blacklisted ║
║ 35607 sctp blacklisted ║
║ 35619 Single firewall (iptables only) ║
║ 35623 Loopback traffic configured ║
║ 35624 Default deny policy ║
║ 35641 SSH host key permissions (firstboot) ║
║ 35643 AllowUsers set ║
║ 35644 Banner configured ║
║ 35646 ClientAliveInterval configured ║
║ 35647 DisableForwarding yes ║
║ 35648 GSSAPIAuthentication no ║
║ 35649 HostbasedAuthentication no ║
║ 35650 IgnoreRhosts yes ║
║ 35652 LoginGraceTime configured ║
║ 35653 LogLevel VERBOSE ║
║ 35655 MaxAuthTries 3 ║
║ 35656 MaxSessions 3 ║
║ 35657 MaxStartups configured ║
║ 35658 PermitEmptyPasswords no ║
║ 35659 PermitRootLogin no ║
║ 35660 PermitUserEnvironment no ║
║ 35661 UsePAM yes ║
║ 35664 Sudo logfile configured ║
║ 35668 su restricted to sudo group ║
║ 35672 pam_unix enabled ║
║ 35673 pam_faillock enabled ║
║ 35675 pam_pwhistory enabled ║
║ 35681 Password complexity (minclass=4) ║
║ 35683 maxsequence=3 ║
║ 35687 Password history remember=24 ║
║ 35688 enforce_for_root on pwhistory ║
║ 35689 use_authtok on pwhistory ║
║ 35690 nullok removed ║
║ 35694 Password expiration (60 days) ║
║ 35695 Minimum password days (1) ║
║ 35698 Inactive lock (30 days) ║
║ 35703 Root umask 0077 ║
║ 35708 Journald rotation configured ║
║ 35719 Rsyslog file creation mode 0640 ║
║ 35722 Log file permissions restricted ║
║ 35725 audit=1 in GRUB ║
║ 35726 audit_backlog_limit in GRUB ║
║ 35728 max_log_file_action = keep_logs ║
║ 35729 admin_space_left_action = halt ║
║ 35730 space_left_action = email ║
║ 35731-35748 All audit rules present ║
║ 35752 Audit config file permissions ║
║ 35755 Audit tool permissions ║
║ 35760 AIDE covers audit tools ║
║ 35770 opasswd permissions ║
║ ║
║ STILL REQUIRES MANUAL ACTION: ║
║ 35540 Set GRUB password (see Section 10) ║
║ 35710 Journal-upload auth (only if using journal-upload) ║
║ 35720 Remote syslog (edit /etc/rsyslog.d/99-remote.conf ║
║ or use Wazuh agent as compensating control) ║
║ ║
╠═══════════════════════════════════════════════════════════════════╣
║ NEXT STEPS: ║
║ 1. Set GRUB password (Section 10) ║
║ 2. Verify: sudo sshd -T | grep -i allowusers ║
║ 3. Verify: sudo iptables -L -v -n ║
║ 4. Review $LOG ║
║ 5. Reboot and re-run Wazuh SCA scan ║
║ 6. Shut down → qm template <VMID> ║
╚═══════════════════════════════════════════════════════════════════╝
SUMMARY
echo ""
echo "Full log: $LOG"
echo "Reboot recommended: shutdown -r now"