#!/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 " 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"