Update scripts/remediate.sh

This commit is contained in:
2026-05-28 23:30:42 +00:00
parent 2c856e1fd5
commit b2c964b440
+724
View File
@@ -0,0 +1,724 @@
#!/usr/bin/env bash
###############################################################################
# NIST 800-53 / CIS Remediation Script - Fixes Wazuh SCA Failures
# Ubuntu 24.04 LTS (Proxmox VM Template)
#
# Run as root after the initial hardening script.
# Usage: chmod +x remediate.sh && sudo ./remediate.sh
###############################################################################
set -euo pipefail
export DEBIAN_FRONTEND=noninteractive
LOG="/var/log/nist-remediation-$(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 "Run as root." >&2; exit 1; fi
###############################################################################
# 35509 - Disable additional unused filesystem kernel modules
###############################################################################
banner "35509: Disable unused filesystem kernel modules"
cat > /etc/modprobe.d/cis-disable-fs.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 gfs2 /bin/false
install nfs /bin/false
install nfsd /bin/false
install smbfs /bin/false
EOF
# Blacklist them too
cat > /etc/modprobe.d/cis-blacklist-fs.conf <<'EOF'
blacklist cramfs
blacklist freevxfs
blacklist jffs2
blacklist hfs
blacklist hfsplus
blacklist squashfs
blacklist udf
blacklist afs
blacklist ceph
blacklist cifs
blacklist exfat
blacklist gfs2
blacklist nfs
blacklist nfsd
blacklist smbfs
EOF
###############################################################################
# 35522 - Add nodev to /var mount
###############################################################################
banner "35522: Add nodev to /var mount"
if grep -q 'vg_nist/lv_var ' /etc/fstab; then
sed -i 's|\(vg_nist/lv_var\s\+/var\s\+ext4\s\+\)defaults,nosuid|\1defaults,nosuid,nodev|' /etc/fstab
mount -o remount /var
fi
###############################################################################
# 35537 - Enable AppArmor in bootloader
###############################################################################
banner "35537: AppArmor in GRUB + audit at boot"
# Also covers 35725 (audit=1) and 35726 (audit_backlog_limit)
GRUB_PARAMS="apparmor=1 security=apparmor audit=1 audit_backlog_limit=8192"
if grep -q '^GRUB_CMDLINE_LINUX="' /etc/default/grub; then
# Get current value
CURRENT=$(grep '^GRUB_CMDLINE_LINUX=' /etc/default/grub | sed 's/GRUB_CMDLINE_LINUX="//;s/"$//')
# Add missing params
for param in $GRUB_PARAMS; do
if ! echo "$CURRENT" | grep -q "$param"; then
CURRENT="$CURRENT $param"
fi
done
sed -i "s|^GRUB_CMDLINE_LINUX=.*|GRUB_CMDLINE_LINUX=\"${CURRENT# }\"|" /etc/default/grub
else
echo "GRUB_CMDLINE_LINUX=\"${GRUB_PARAMS}\"" >> /etc/default/grub
fi
update-grub
###############################################################################
# 35540 - Bootloader password (informational — uncomment to enable)
###############################################################################
banner "35540: Bootloader password (MANUAL STEP)"
echo " To set a GRUB password:"
echo " 1. Run: grub-mkpasswd-pbkdf2"
echo " 2. Add to /etc/grub.d/40_custom:"
echo " set superusers=\"grubadmin\""
echo " password_pbkdf2 grubadmin <YOUR_HASH>"
echo " 3. Run: update-grub"
echo " Skipping — requires interactive input."
###############################################################################
# 35545 - Disable Apport (automatic error reporting)
###############################################################################
banner "35545: Disable Apport"
systemctl stop apport.service 2>/dev/null || true
systemctl disable apport.service 2>/dev/null || true
systemctl mask apport.service 2>/dev/null || true
apt-get purge -y apport 2>/dev/null || true
###############################################################################
# 35573, 35585, 35587 - Remove rsync, telnet, ftp
###############################################################################
banner "35573/35585/35587: Remove rsync, telnet, ftp"
apt-get purge -y rsync telnet inetutils-telnet ftp tnftp 2>/dev/null || true
###############################################################################
# 35589 - Time sync: Wazuh wants systemd-timesyncd but we use chrony
# Disable timesyncd cleanly since chrony is our NTP (AU-8)
###############################################################################
banner "35589: Time sync — chrony is authoritative"
# Some CIS scanners flag this; chrony is preferred and NIST-compliant
systemctl stop systemd-timesyncd 2>/dev/null || true
systemctl disable systemd-timesyncd 2>/dev/null || true
systemctl mask systemd-timesyncd 2>/dev/null || true
echo " chrony is running as the NTP source (AU-8). timesyncd masked."
echo " If Wazuh still flags this, add an exception — chrony satisfies the control."
###############################################################################
# 35600, 35601 - Restrict cron and at to authorized users
###############################################################################
banner "35600/35601: Restrict cron and at"
# Remove deny files, create allow files with only root
rm -f /etc/cron.deny /etc/at.deny
echo "root" > /etc/cron.allow
chmod 640 /etc/cron.allow
chown root:root /etc/cron.allow
echo "root" > /etc/at.allow
chmod 640 /etc/at.allow
chown root:root /etc/at.allow
###############################################################################
# 35604-35607 - Disable network protocol kernel modules properly
###############################################################################
banner "35604-35607: Disable unused network kernel modules"
cat > /etc/modprobe.d/cis-disable-net.conf <<'EOF'
install dccp /bin/false
install sctp /bin/false
install rds /bin/false
install tipc /bin/false
EOF
cat > /etc/modprobe.d/cis-blacklist-net.conf <<'EOF'
blacklist dccp
blacklist sctp
blacklist rds
blacklist tipc
EOF
###############################################################################
# 35619-35639 - Firewall: configure UFW properly
# CIS checks all three frameworks. We use UFW — nftables/iptables checks
# will show "failed" because those aren't our chosen tool. That's expected.
###############################################################################
banner "35619-35639: UFW firewall hardening"
# Ensure UFW is the only active firewall
systemctl stop nftables 2>/dev/null || true
systemctl disable nftables 2>/dev/null || true
systemctl mask nftables 2>/dev/null || true
# Loopback rules (35623)
ufw allow in on lo
ufw allow out on lo
ufw deny in from 127.0.0.0/8
ufw deny in from ::1
# Default policies (35624)
ufw default deny incoming
ufw default deny outgoing
ufw default deny routed
# Allow essential outbound
ufw allow out 53 comment 'DNS'
ufw allow out 80/tcp comment 'HTTP'
ufw allow out 443/tcp comment 'HTTPS'
ufw allow out 123/udp comment 'NTP'
# SSH inbound (already added but ensure)
ufw limit in 22/tcp comment 'SSH rate-limited'
# Wazuh agent outbound (if applicable)
ufw allow out 1514/tcp comment 'Wazuh agent'
ufw allow out 1515/tcp comment 'Wazuh enrollment'
ufw --force enable
ufw status verbose
###############################################################################
# 35641-35642 - SSH host key permissions
# Keys were removed for template prep. Regenerate them now for testing;
# the firstboot service will regenerate on each clone.
###############################################################################
banner "35641/35642: SSH host key permissions"
# Regenerate if missing (template prep removed them)
if [ ! -f /etc/ssh/ssh_host_ed25519_key ]; then
dpkg-reconfigure openssh-server
fi
# Set strict permissions
chmod 600 /etc/ssh/ssh_host_*_key
chmod 644 /etc/ssh/ssh_host_*_key.pub
chown root:root /etc/ssh/ssh_host_*
###############################################################################
# 35643-35661 - SSH configuration (complete rewrite)
###############################################################################
banner "35643-35661: Complete SSH hardening"
cat > /etc/ssh/sshd_config.d/nist-hardening.conf <<'SSHEOF'
# ============= NIST 800-53 + CIS SSH Hardening =============
Protocol 2
# Authentication
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no
ChallengeResponseAuthentication no
UsePAM yes
MaxAuthTries 3
LoginGraceTime 60
# Disable host-based auth (35649)
HostbasedAuthentication no
IgnoreRhosts yes
# Disable GSSAPI (35648)
GSSAPIAuthentication no
# Disable user environment (35660)
PermitUserEnvironment no
# Session limits (35646, 35656, 35657)
ClientAliveInterval 300
ClientAliveCountMax 3
MaxSessions 3
MaxStartups 10:30:60
# Forwarding — use DisableForwarding (35647)
DisableForwarding yes
# 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 (35644 / AC-8)
Banner /etc/issue.net
# Logging (35653 / AU-3)
LogLevel VERBOSE
# Access restriction (35643) — adjust username as needed
AllowGroups sudo
SSHEOF
# Remove stale/conflicting configs
rm -f /etc/ssh/sshd_config.d/50-cloud-init.conf 2>/dev/null || true
# Validate and restart
sshd -t && systemctl restart ssh
echo " SSH config validated and restarted."
###############################################################################
# 35664 - Sudo log file
###############################################################################
banner "35664: Sudo logging"
if ! grep -q 'Defaults.*logfile' /etc/sudoers; then
echo 'Defaults logfile="/var/log/sudo.log"' >> /etc/sudoers
fi
###############################################################################
# 35668 - Restrict su to sudo group
###############################################################################
banner "35668: Restrict su command"
# Ensure pam_wheel is properly configured
sed -i '/pam_wheel.so/d' /etc/pam.d/su
echo "auth required pam_wheel.so use_uid group=sudo" >> /etc/pam.d/su
###############################################################################
# 35672-35690 - PAM configuration (complete)
###############################################################################
banner "35672-35690: PAM configuration"
# --- common-auth ---
cat > /etc/pam.d/common-auth <<'EOF'
# NIST 800-53 / CIS compliant PAM auth stack
# pam_faillock: preauth (AC-7)
auth required pam_faillock.so preauth
# pam_unix: standard unix auth
auth [success=1 default=ignore] pam_unix.so
# pam_faillock: authfail
auth [default=die] pam_faillock.so authfail
auth sufficient pam_faillock.so authsucc
# Deny by default
auth requisite pam_deny.so
auth required pam_permit.so
EOF
# --- common-account ---
cat > /etc/pam.d/common-account <<'EOF'
# NIST 800-53 / CIS compliant PAM account stack
account required pam_faillock.so
account [success=1 new_authtok_reqd=done default=ignore] pam_unix.so
account requisite pam_deny.so
account required pam_permit.so
EOF
# --- common-password ---
cat > /etc/pam.d/common-password <<'EOF'
# NIST 800-53 / CIS compliant PAM password stack
# pam_pwquality: password complexity (IA-5)
password requisite pam_pwquality.so retry=3
# pam_pwhistory: remember 24 passwords (IA-5)
password required pam_pwhistory.so remember=24 use_authtok enforce_for_root
# pam_unix: store password
password [success=1 default=ignore] pam_unix.so obscure use_authtok try_first_pass yescrypt shadow
password requisite pam_deny.so
password required pam_permit.so
EOF
# --- common-session ---
cat > /etc/pam.d/common-session <<'EOF'
# NIST 800-53 / CIS compliant PAM session stack
session [default=1] pam_permit.so
session requisite pam_deny.so
session required pam_permit.so
session required pam_unix.so
session optional pam_systemd.so
EOF
###############################################################################
# 35681, 35683 - Password quality (maxsequence)
###############################################################################
banner "35681/35683: Password quality — maxsequence"
cat > /etc/security/pwquality.conf <<'EOF'
# IA-5(1): Password complexity — CIS compliant
minlen = 15
dcredit = -1
ucredit = -1
lcredit = -1
ocredit = -1
difok = 8
maxrepeat = 3
maxsequence = 3
maxclassrepeat = 4
gecoscheck = 1
dictcheck = 1
enforcing = 1
EOF
###############################################################################
# 35694, 35695, 35698 - Password expiration and inactive lock
###############################################################################
banner "35694/35695/35698: Password aging and inactive lock"
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 password lock to 30 days
useradd -D -f 30
# Apply to existing users (adjust username)
for user in $(awk -F: '($3 >= 1000) && ($7 != "/usr/sbin/nologin") {print $1}' /etc/passwd); do
chage --maxdays 60 --mindays 1 --warndays 14 "$user"
chage --inactive 30 "$user"
done
###############################################################################
# 35703 - Root umask
###############################################################################
banner "35703: Root user umask"
# Set in root's bashrc
if ! grep -q 'umask 027' /root/.bashrc 2>/dev/null; then
echo "umask 027" >> /root/.bashrc
fi
# Create bash_profile if missing
if [ ! -f /root/.bash_profile ]; then
cat > /root/.bash_profile <<'EOF'
umask 027
[ -f ~/.bashrc ] && . ~/.bashrc
EOF
fi
if ! grep -q 'umask 027' /root/.bash_profile; then
sed -i '1i umask 027' /root/.bash_profile
fi
###############################################################################
# 35708 - Journald log rotation
###############################################################################
banner "35708: Journald configuration"
mkdir -p /etc/systemd/journald.conf.d
cat > /etc/systemd/journald.conf.d/nist.conf <<'EOF'
[Journal]
Compress=yes
Storage=persistent
ForwardToSyslog=yes
SystemMaxUse=1G
SystemKeepFree=1G
SystemMaxFileSize=100M
MaxFileSec=1month
EOF
systemctl restart systemd-journald
###############################################################################
# 35719 - rsyslog file creation mode
###############################################################################
banner "35719: rsyslog file creation mode"
cat > /etc/rsyslog.d/99-nist-perms.conf <<'EOF'
$FileCreateMode 0640
$DirCreateMode 0750
$Umask 0027
EOF
systemctl restart rsyslog
###############################################################################
# 35720 - rsyslog remote logging (placeholder)
###############################################################################
banner "35720: rsyslog remote logging"
echo " Wazuh is handling remote log collection."
echo " If you also need syslog forwarding, add to /etc/rsyslog.d/:"
echo " *.* @@your-syslog-server:514"
echo " Skipping — environment-specific."
###############################################################################
# 35722 - Log file permissions
###############################################################################
banner "35722: Fix log file permissions"
find /var/log -type f -exec chmod g-wx,o-rwx {} +
find /var/log -type d -exec chmod g-w,o-rwx {} +
###############################################################################
# 35725, 35726 - Audit at boot (handled above in GRUB section)
###############################################################################
banner "35725/35726: Audit at boot — handled in GRUB section above"
###############################################################################
# 35728-35730 - Auditd configuration
###############################################################################
banner "35728-35730: Auditd log management"
# Write directly to auditd.conf since the .d directory may not be supported
cp /etc/audit/auditd.conf /etc/audit/auditd.conf.bak
sed -i 's/^max_log_file_action.*/max_log_file_action = keep_logs/' /etc/audit/auditd.conf
sed -i 's/^space_left_action.*/space_left_action = email/' /etc/audit/auditd.conf
sed -i 's/^admin_space_left_action.*/admin_space_left_action = halt/' /etc/audit/auditd.conf
# Ensure these exist
grep -q '^max_log_file_action' /etc/audit/auditd.conf || echo 'max_log_file_action = keep_logs' >> /etc/audit/auditd.conf
grep -q '^space_left_action' /etc/audit/auditd.conf || echo 'space_left_action = email' >> /etc/audit/auditd.conf
grep -q '^admin_space_left_action' /etc/audit/auditd.conf || echo 'admin_space_left_action = halt' >> /etc/audit/auditd.conf
###############################################################################
# 35731-35748 - Comprehensive audit rules (CIS complete)
###############################################################################
banner "35731-35748: CIS-compliant audit rules"
cat > /etc/audit/rules.d/cis-nist.rules <<'AUDITRULES'
## Remove existing rules
-D
## Buffer
-b 8192
## Failure mode
-f 1
## 35731 - Sudoers changes
-w /etc/sudoers -p wa -k scope
-w /etc/sudoers.d -p wa -k scope
## 35732 - Actions as another user
-a always,exit -F arch=b64 -C euid!=uid -F auid!=unset -S execve -k user_emulation
-a always,exit -F arch=b32 -C euid!=uid -F auid!=unset -S execve -k user_emulation
## 35733 - Sudo log file events
-w /var/log/sudo.log -p wa -k sudo_log
## 35734 - Date and time changes
-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
## 35735 - Network environment changes
-a always,exit -F arch=b64 -S sethostname,setdomainname -k system-locale
-a always,exit -F arch=b32 -S sethostname,setdomainname -k system-locale
-w /etc/issue -p wa -k system-locale
-w /etc/issue.net -p wa -k system-locale
-w /etc/hosts -p wa -k system-locale
-w /etc/hostname -p wa -k system-locale
-w /etc/netplan/ -p wa -k system-locale
## 35736 - Unsuccessful file access attempts
-a always,exit -F arch=b64 -S open,truncate,ftruncate,creat,openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access
-a always,exit -F arch=b64 -S open,truncate,ftruncate,creat,openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access
-a always,exit -F arch=b32 -S open,truncate,ftruncate,creat,openat -F exit=-EACCES -F auid>=1000 -F auid!=unset -k access
-a always,exit -F arch=b32 -S open,truncate,ftruncate,creat,openat -F exit=-EPERM -F auid>=1000 -F auid!=unset -k access
## 35737 - User/group information changes
-w /etc/group -p wa -k identity
-w /etc/passwd -p wa -k identity
-w /etc/gshadow -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/security/opasswd -p wa -k identity
## 35738 - DAC permission modification
-a always,exit -F arch=b64 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -k perm_mod
-a always,exit -F arch=b64 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -k perm_mod
-a always,exit -F arch=b64 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -k perm_mod
-a always,exit -F arch=b32 -S chmod,fchmod,fchmodat -F auid>=1000 -F auid!=unset -k perm_mod
-a always,exit -F arch=b32 -S chown,fchown,fchownat,lchown -F auid>=1000 -F auid!=unset -k perm_mod
-a always,exit -F arch=b32 -S setxattr,lsetxattr,fsetxattr,removexattr,lremovexattr,fremovexattr -F auid>=1000 -F auid!=unset -k perm_mod
## 35739 - Successful file system mounts
-a always,exit -F arch=b64 -S mount -F auid>=1000 -F auid!=unset -k mounts
-a always,exit -F arch=b32 -S mount -F auid>=1000 -F auid!=unset -k mounts
## 35740 - Session initiation
-w /var/run/utmp -p wa -k session
-w /var/log/wtmp -p wa -k session
-w /var/log/btmp -p wa -k session
## 35741 - Login and logout events
-w /var/log/lastlog -p wa -k logins
-w /var/run/faillock -p wa -k logins
## 35742 - File deletion events
-a always,exit -F arch=b64 -S rename,unlink,unlinkat,renameat -F auid>=1000 -F auid!=unset -k delete
-a always,exit -F arch=b32 -S rename,unlink,unlinkat,renameat -F auid>=1000 -F auid!=unset -k delete
## 35743 - Mandatory Access Controls
-w /etc/apparmor/ -p wa -k MAC-policy
-w /etc/apparmor.d/ -p wa -k MAC-policy
## 35744 - chcon command
-a always,exit -F path=/usr/bin/chcon -F perm=x -F auid>=1000 -F auid!=unset -k perm_chng
## 35745 - setfacl command
-a always,exit -F path=/usr/bin/setfacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_chng
## 35746 - chacl command
-a always,exit -F path=/usr/bin/chacl -F perm=x -F auid>=1000 -F auid!=unset -k perm_chng
## 35747 - usermod command
-a always,exit -F path=/usr/sbin/usermod -F perm=x -F auid>=1000 -F auid!=unset -k usermod
## 35748 - Kernel module loading/unloading
-a always,exit -F arch=b64 -S init_module,finit_module,delete_module,create_module,query_module -F auid>=1000 -F auid!=unset -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 /usr/bin/kmod -p x -k kernel_modules
## Make immutable (requires reboot to change)
-e 2
AUDITRULES
# Remove old rules file to avoid conflicts
rm -f /etc/audit/rules.d/nist-800-53.rules
# Load new rules
augenrules --load 2>/dev/null || true
# auditd often requires a service restart for rule reload
systemctl restart auditd 2>/dev/null || true
###############################################################################
# 35752 - Audit config file permissions
###############################################################################
banner "35752: Audit configuration file permissions"
find /etc/audit/ -type f \( -name '*.conf' -o -name '*.rules' \) -exec chmod 640 {} +
chown -R root:root /etc/audit/
###############################################################################
# 35755 - Audit tools permissions
###############################################################################
banner "35755: Audit tools permissions"
for tool in /sbin/auditctl /sbin/aureport /sbin/ausearch /sbin/autrace /sbin/auditd /sbin/augenrules; do
if [ -f "$tool" ]; then
chmod 755 "$tool"
chown root:root "$tool"
fi
done
###############################################################################
# 35760 - AIDE protects audit tools
###############################################################################
banner "35760: AIDE audit tool integrity"
cat > /etc/aide/aide.conf.d/99_audit_tools <<'EOF'
# CIS: Protect integrity of audit tools
/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
###############################################################################
# 35770 - opasswd permissions
###############################################################################
banner "35770: opasswd file permissions"
touch /etc/security/opasswd
chmod 600 /etc/security/opasswd
chown root:root /etc/security/opasswd
# Also create opasswd.old if it doesn't exist
touch /etc/security/opasswd.old
chmod 600 /etc/security/opasswd.old
chown root:root /etc/security/opasswd.old
###############################################################################
# FINAL CLEANUP
###############################################################################
banner "Final cleanup"
# Rebuild AIDE database with new audit tool entries
echo " Rebuilding AIDE database (this will take several minutes)..."
aideinit -y -f 2>/dev/null || true
apt-get autoremove -y
apt-get clean
###############################################################################
# SUMMARY
###############################################################################
banner "Remediation Complete"
cat <<'SUMMARY'
╔══════════════════════════════════════════════════════════════════╗
║ Remediation Summary ║
╠══════════════════════════════════════════════════════════════════╣
║ ║
║ FIXED: ║
║ 35509 Unused filesystem modules disabled ║
║ 35522 /var nodev added ║
║ 35537 AppArmor enabled in bootloader ║
║ 35545 Apport disabled and removed ║
║ 35573 rsync removed ║
║ 35585 telnet removed ║
║ 35587 ftp removed ║
║ 35589 timesyncd masked (chrony is NTP source) ║
║ 35600 cron.allow created ║
║ 35601 at.allow created ║
║ 35604-07 Network protocol modules disabled ║
║ 35619+ UFW firewall fully configured ║
║ 35641-42 SSH host key permissions set ║
║ 35643-61 SSH fully hardened ║
║ 35664 Sudo logging enabled ║
║ 35668 su restricted to sudo group ║
║ 35672-90 PAM stack fully configured ║
║ 35694-98 Password aging and inactive lock ║
║ 35703 Root umask set ║
║ 35708 Journald rotation configured ║
║ 35719 rsyslog file creation mode set ║
║ 35722 Log file permissions tightened ║
║ 35725-26 Audit at boot enabled ║
║ 35728-30 Auditd log management configured ║
║ 35731-48 Full CIS audit rules applied ║
║ 35752 Audit config permissions set ║
║ 35755 Audit tools permissions set ║
║ 35760 AIDE protects audit tools ║
║ 35770 opasswd permissions configured ║
║ ║
║ MANUAL STEPS REQUIRED: ║
║ 35540 Set GRUB bootloader password ║
║ 35720 Configure remote syslog if needed ║
║ 35710 Configure journal-upload if needed ║
║ ║
║ EXPECTED SCANNER NOISE (not actual failures): ║
║ 35626-35639 nftables/iptables checks — we use UFW ║
║ 35589 timesyncd — we use chrony instead ║
║ ║
║ Reboot required for GRUB and kernel module changes. ║
╚══════════════════════════════════════════════════════════════════╝
SUMMARY
echo ""
echo "Full log: $LOG"
echo "Reboot now: shutdown -r now"