#!/usr/bin/env bash set -euo pipefail # Debian Hardening Script # Adapted from the Arch Linux hardening script (arch-hardening.sh) export DEBIAN_FRONTEND=noninteractive log() { echo "[$(date --rfc-3339=seconds)] $*" >&2 } log_warn() { echo "[$(date --rfc-3339=seconds)] WARNING: $*" >&2 } log_error() { echo "[$(date --rfc-3339=seconds)] ERROR: $*" >&2 } # Update system log "Updating packages..." sudo apt-get update sudo apt-get dist-upgrade -y # [DEB-0280] Ensure libpam-tmpdir is installed and enabled sudo apt-get install -y libpam-tmpdir if ! grep -q "pam_tmpdir.so" /etc/pam.d/common-session 2>/dev/null; then sudo sed -i "/pam_unix.so/ a session optional pam_tmpdir.so" /etc/pam.d/common-session || true fi # [DEB-0810] Ensure apt-listbugs is installed log "Installing apt-listbugs..." sudo apt-get install -y apt-listbugs # [DEB-0811] Ensure apt-listchanges is installed log "Installing apt-listchanges..." sudo apt-get install -y apt-listchanges # [DEB-0831] Ensure needrestart is installed log "Installing needrestart..." sudo apt-get install -y needrestart # [DEB-0880] Ensure fail2ban is installed log "Installing fail2ban..." sudo apt-get install -y fail2ban sudo cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local || true # [STRG-1846] Disable drivers like firewire log "Disabling FireWire kernel modules..." sudo tee /etc/modprobe.d/90-firewire-disable.conf >/dev/null </dev/null 2>&1; then sudo usbguard generate-policy | sudo tee /etc/usbguard/rules.conf >/dev/null sudo sed -i 's/^PresentControllerPolicy=.*/PresentControllerPolicy=apply-policy/' /etc/usbguard/usbguard-daemon.conf || true sudo systemctl enable --now usbguard fi # [NETW-3032] Checking for ARP monitoring software log "Installing Arpon..." sudo apt-get install -y arpon # [NETW-3200] Disable unused network protocols log "Disabling unused network protocol modules..." sudo tee /etc/modprobe.d/90-network-protocols-disable.conf >/dev/null </dev/null 2>&1; then # log "Installing clamd..." # sudo apt-get install -y clamav clamav-daemon clamav-freshclam clamdscan # sudo systemctl enable --now clamav-daemon clamav-freshclam || true # sudo freshclam # else # log "Clamd is already installed." # fi # [FINT-4350] Install a file integrity tool log "Installing AIDE..." sudo apt-get install -y aide sudo sed -i 's/^Checksums = .*/Checksums = sha512+sha256/' /etc/aide/aide.conf || true sudo sed -i 's|^database_in=file:.*|database_in=file:/var/lib/aide/aide.db.gz|' /etc/aide/aide.conf || true sudo sed -i 's|^database_out=file:.*|database_out=file:/var/lib/aide/aide.db.new.gz|' /etc/aide/aide.conf || true sudo sed -i 's|^database_new=file:.*|database_new=file:/var/lib/aide/aide.db.new.gz|' /etc/aide/aide.conf || true sudo aide --init --config /etc/aide/aide.conf || true sudo mv /var/lib/aide/aide.db.new.gz /var/lib/aide/aide.db.gz || true # [FIRE-45XX] Firewall configuration: ensure nftables is installed and iptables removed if present log "Disabling iptables to prevent conflicts with nftables (default on debian since Buster)..." sudo tee /etc/modprobe.d/90-ip_tables-disable.conf >/dev/null </dev/null 2>&1; then openssl rand -base64 $((len * 2)) | tr -dc 'A-Za-z0-9@%_+=!#-' | head -c "$len" else tr -dc 'A-Za-z0-9@%_+=!#-' /dev/null </dev/null; then log "Enabling audit=1 in GRUB_CMDLINE_LINUX..." sudo sed -i 's|^GRUB_CMDLINE_LINUX="\(.*\)"|GRUB_CMDLINE_LINUX="\1 audit=1"|' /etc/default/grub sudo update-grub || true else log "audit=1 already present in GRUB_CMDLINE_LINUX; skipping." fi # ^GRUB_CMDLINE_LINUX=.*audit_backlog_limit=8192 is not present in /etc/default/grub if ! grep -q 'audit_backlog_limit=8192' /etc/default/grub 2>/dev/null; then log "Enabling audit_backlog_limit=8192 in GRUB_CMDLINE_LINUX..." sudo sed -i 's|^GRUB_CMDLINE_LINUX="\(.*\)"|GRUB_CMDLINE_LINUX="\1 audit_backlog_limit=8192"|' /etc/default/grub sudo update-grub || true else log "audit_backlog_limit=8192 already present in GRUB_CMDLINE_LINUX; skipping." fi # ^GRUB_CMDLINE_LINUX=.*apparmor=1 security=apparmor is not present in /etc/default/grub if ! grep -q 'apparmor=1 security=apparmor' /etc/default/grub 2>/dev/null; then log "Enabling AppArmor in GRUB_CMDLINE_LINUX..." sudo sed -i 's|^GRUB_CMDLINE_LINUX="\(.*\)"|GRUB_CMDLINE_LINUX="\1 apparmor=1 security=apparmor"|' /etc/default/grub sudo update-grub || true else log "AppArmor already present in GRUB_CMDLINE_LINUX; skipping." fi # [TOOL-5190] Ensure IDS/IPS tools are installed (suricata) # log "Installing suricata..." # sudo apt-get install -y suricata # sudo systemctl enable --now suricata || true # [KRNL-5820] Disable core dumps log "Disabling core dumps via systemd and limits..." sudo mkdir -p /etc/systemd/coredump.conf.d sudo tee /etc/systemd/coredump.conf.d/99-disable-coredumps.conf >/dev/null <<'EOL' [Coredump] ProcessSizeMax=0 Storage=none EOL sudo systemctl daemon-reload || true sudo mkdir -p /etc/security/limits.d/ sudo tee /etc/security/limits.d/20-disable-core-dumps.conf >/dev/null </dev/null; then echo '# Disable core dumps system-wide' | sudo tee -a /etc/profile >/dev/null echo 'ulimit -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile >/dev/null echo 'ulimit -S -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile >/dev/null echo 'ulimit -H -c 0 > /dev/null 2>&1' | sudo tee -a /etc/profile >/dev/null fi # [KRNL-6000] Sysctl settings for kernel hardening log "Applying sysctl hardened settings..." sudo tee /etc/sysctl.d/99-hardened.conf >/dev/null <<'EOL' # Kernel and filesystem hardening settings kernel.randomize_va_space = 2 kernel.kptr_restrict = 2 kernel.unprivileged_bpf_disabled = 1 #kernel.modules_disabled = 1 # Uncomment to disable module loading entirely at your own risk kernel.sysrq = 0 kernel.core_uses_pid = 1 kernel.yama.ptrace_scope = 2 fs.suid_dumpable = 0 fs.protected_fifos = 2 fs.protected_hardlinks = 1 fs.protected_regular = 2 fs.protected_symlinks = 1 dev.tty.ldisc_autoload = 0 net.core.bpf_jit_harden = 2 net.ipv4.conf.all.forwarding = 0 net.ipv4.conf.all.accept_redirects = 0 net.ipv4.conf.all.send_redirects = 0 net.ipv4.conf.default.send_redirects = 0 net.ipv4.conf.all.log_martians = 1 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.accept_redirects = 0 net.ipv4.conf.default.log_martians = 1 net.ipv4.conf.all.secure_redirects = 0 net.ipv4.conf.default.secure_redirects = 0 net.ipv4.conf.all.rp_filter = 1 net.ipv4.conf.default.rp_filter = 1 net.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 0 net.ipv6.conf.all.accept_ra = 0 net.ipv6.conf.default.accept_ra = 0 EOL sudo sysctl --system # [SHLL-6220] Idle session handling if ! grep -q 'TMOUT' /etc/profile 2>/dev/null; then echo 'TMOUT=900' | sudo tee -a /etc/profile >/dev/null echo 'readonly TMOUT' | sudo tee -a /etc/profile >/dev/null echo 'export TMOUT' | sudo tee -a /etc/profile >/dev/null fi # [MACF-6290] Enable MAC framework (AppArmor) log "Enabling AppArmor..." sudo apt-get install -y apparmor apparmor-utils || true sudo systemctl enable --now apparmor || true # [FILE-6344] Restricting process details to users via /proc mount options log "Configuring /proc to hide process info..." if ! grep -q '^proc\s\+/proc\s\+proc\s\+' /etc/fstab; then echo '# /proc' | sudo tee -a /etc/fstab >/dev/null echo 'proc /proc proc defaults,hidepid=2,gid=sudo 0 0' | sudo tee -a /etc/fstab >/dev/null else sudo sed -i 's|^proc[[:space:]]\+/proc[[:space:]]\+proc[[:space:]]\+.*$|proc /proc proc defaults,hidepid=2,gid=sudo 0 0|' /etc/fstab fi sudo systemctl daemon-reload sudo mount -o remount /proc # [FILE-6374] Check /dev, /dev/shm and /tmp mount options log "Ensuring /dev, /dev/shm and /tmp have secure mount options..." if ! grep -q '^devtmpfs\s\+/dev\s\+devtmpfs\s\+' /etc/fstab; then echo '# /dev' | sudo tee -a /etc/fstab >/dev/null echo 'devtmpfs /dev devtmpfs rw,nosuid,noexec,relatime,size=10%,mode=755 0 0' | sudo tee -a /etc/fstab >/dev/null else sudo sed -i 's|^devtmpfs[[:space:]]\+/dev[[:space:]]\+devtmpfs[[:space:]]\+.*$|devtmpfs /dev devtmpfs rw,nosuid,noexec,relatime,size=10%,mode=755 0 0|' /etc/fstab fi sudo systemctl daemon-reload sudo mount -o remount /dev if ! grep -q '^tmpfs\s\+/dev/shm\s\+tmpfs\s\+' /etc/fstab; then echo '# /dev/shm' | sudo tee -a /etc/fstab >/dev/null echo 'tmpfs /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0' | sudo tee -a /etc/fstab >/dev/null else sudo sed -i 's|^tmpfs[[:space:]]\+/dev/shm[[:space:]]\+tmpfs[[:space:]]\+.*$|tmpfs /dev/shm tmpfs rw,nosuid,nodev,noexec 0 0|' /etc/fstab fi sudo systemctl daemon-reload sudo mount -o remount /dev/shm if ! grep -q '^tmpfs\s\+/tmp\s\+tmpfs\s\+' /etc/fstab; then echo '# /tmp' | sudo tee -a /etc/fstab >/dev/null echo 'tmpfs /tmp tmpfs rw,nosuid,nodev,noexec 0 0' | sudo tee -a /etc/fstab >/dev/null else sudo sed -i 's|^tmpfs[[:space:]]\+/tmp[[:space:]]\+tmpfs[[:space:]]\+.*$|tmpfs /tmp tmpfs rw,nosuid,nodev,noexec 0 0|' /etc/fstab fi sudo systemctl daemon-reload sudo mount -o remount /tmp # [FILE-6430] Disable mounting of some filesystems log "Disabling unnecessary filesystem modules..." sudo tee /etc/modprobe.d/90-fs_blacklist.conf >/dev/null </dev/null </dev/null 2>&1 || true sudo tee /etc/issue >/dev/null </dev/null </dev/null <<'EOL' # Exclude as from being installed path-exclude /usr/bin/as path-exclude /usr/bin/x86_64-linux-gnu-as EOL log "Done checking if as is present and excluding it from installation." # [HRDN-7222] Restricting compiler access to root user only # Correcting from chown->chmod to restrict access log "Restricting compiler binaries..." for bin in /usr/bin/as /usr/bin/x86_64-linux-gnu-as; do if [ -f "$bin" ]; then sudo chmod 700 "$bin" || true fi done log "Done restricting compiler binaries." # [PKGS-7320] Install package auditing tools log "Installing package auditing..." sudo apt-get install -y debsecan || true # [PKGS-7370] Checking for debsums utility if ! dpkg -l | grep -q debsums; then sudo apt-get install -y debsums || true fi # Ensure debsums is run weekly via CRON_CHECK=weekly in /etc/default/debsums if ! grep -q '^CRON_CHECK=weekly' /etc/default/debsums 2>/dev/null; then log "Configuring debsums to run weekly..." sudo sed -i 's|^#\?CRON_CHECK=.*|CRON_CHECK=weekly|' /etc/default/debsums || true fi # [SSH-7408] Check SSH specific defined options log "Checking SSH specific defined options..." set_sshd_option() { local opt="$1" local val="$2" # If the option exists (possibly commented), replace the whole line; otherwise append if sudo grep -Eq "^[[:space:]]*#?[[:space:]]*${opt}[[:space:]]+" /etc/ssh/sshd_config 2>/dev/null; then sudo sed -ri "s|^[[:space:]]*#?[[:space:]]*${opt}[[:space:]]+.*|${opt} ${val}|" /etc/ssh/sshd_config else echo "${opt} ${val}" | sudo tee -a /etc/ssh/sshd_config >/dev/null fi } set_sshd_option "Protocol" "2" set_sshd_option "LogLevel" "VERBOSE" set_sshd_option "X11Forwarding" "no" set_sshd_option "MaxAuthTries" "3" set_sshd_option "IgnoreRhosts" "yes" set_sshd_option "HostbasedAuthentication" "no" set_sshd_option "PermitRootLogin" "no" set_sshd_option "PermitEmptyPasswords" "no" set_sshd_option "PermitUserEnvironment" "no" set_sshd_option "Ciphers" "chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr" set_sshd_option "MACs" "hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,hmac-sha2-512,hmac-sha2-256" set_sshd_option "KexAlgorithms" "mlkem768x25519-sha256,sntrup761x25519-sha512,sntrup761x25519-sha512@openssh.com" set_sshd_option "ClientAliveInterval" "300" set_sshd_option "ClientAliveCountMax" "0" set_sshd_option "LoginGraceTime" "60" set_sshd_option "AllowUsers" "*" set_sshd_option "AllowGroups" "*" set_sshd_option "DenyUsers" "nobody" set_sshd_option "DenyGroups" "nobody" set_sshd_option "Banner" "/etc/issue.net" set_sshd_option "MaxStartups" "10:30:60" set_sshd_option "MaxSessions" "2" set_sshd_option "PubkeyAuthentication" "yes" set_sshd_option "PasswordAuthentication" "no" set_sshd_option "KerberosAuthentication" "no" set_sshd_option "ChallengeResponseAuthentication" "no" set_sshd_option "GSSAPIAuthentication" "no" set_sshd_option "GSSAPIKeyExchange" "no" set_sshd_option "RekeyLimit" "512M 6h" set_sshd_option "AllowAgentForwarding" "no" set_sshd_option "AllowTcpForwarding" "no" set_sshd_option "AllowStreamLocalForwarding" "no" set_sshd_option "PermitTunnel" "no" set_sshd_option "PermitUserRC" "no" set_sshd_option "GatewayPorts" "no" set_sshd_option "StrictModes" "yes" set_sshd_option "TCPKeepAlive" "no" set_sshd_option "Port" "2222" sudo systemctl restart ssh || true log "Done checking SSH specific defined options." # [PKGS-7420] Detect toolkit to automatically download and apply upgrades log "Installing unattended-upgrades..." sudo apt-get install -y unattended-upgrades || true sudo dpkg-reconfigure -f noninteractive unattended-upgrades || true if ! sudo grep -q 'Unattended-Upgrade::Automatic-Reboot "true"' /etc/apt/apt.conf.d/50unattended-upgrades 2>/dev/null; then log "Enabling automatic reboot for unattended-upgrades..." if sudo grep -q 'Unattended-Upgrade::Automatic-Reboot ' /etc/apt/apt.conf.d/50unattended-upgrades 2>/dev/null; then sudo sed -ri 's|^[[:space:]]*(//)?[[:space:]]*Unattended-Upgrade::Automatic-Reboot .*|Unattended-Upgrade::Automatic-Reboot "true";|' /etc/apt/apt.conf.d/50unattended-upgrades || true else echo 'Unattended-Upgrade::Automatic-Reboot "true";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades >/dev/null fi fi if ! sudo grep -q 'Unattended-Upgrade::SyslogEnable "true"' /etc/apt/apt.conf.d/50unattended-upgrades 2>/dev/null; then log "Enabling syslog logging for unattended-upgrades..." if sudo grep -q 'Unattended-Upgrade::SyslogEnable' /etc/apt/apt.conf.d/50unattended-upgrades 2>/dev/null; then sudo sed -ri 's|^[[:space:]]*(//)?[[:space:]]*Unattended-Upgrade::SyslogEnable.*|Unattended-Upgrade::SyslogEnable "true";|' /etc/apt/apt.conf.d/50unattended-upgrades || true else echo 'Unattended-Upgrade::SyslogEnable "true";' | sudo tee -a /etc/apt/apt.conf.d/50unattended-upgrades >/dev/null fi fi sudo systemctl enable --now unattended-upgrades || true # [FILE-7524] Ensuring file permissions log "Enforcing file permissions for SSH & cron..." sudo chmod -R 640 /var/log/ || true sudo chmod 600 /etc/crontab || true sudo chmod 700 /etc/cron.* || true sudo chmod 644 /etc/cron.allow || true sudo chmod -R 700 /etc/cron.d/ || true sudo chmod 600 /etc/ssh/sshd_config || true sudo sed -i 's/^UMASK=0022/UMASK=0027/' /etc/sysstat/sysstat || true if ! grep -q 'Dir::Log::Umask' /etc/apt/apt.conf.d/99Hardened 2>/dev/null; then log "Setting apt log umask to 027..." sudo tee -a /etc/apt/apt.conf.d/99Hardened >/dev/null </dev/null; then sudo sed -ri 's|^[[:space:]]*#?[[:space:]]*SHA_CRYPT_MIN_ROUNDS.*|SHA_CRYPT_MIN_ROUNDS 5000|' /etc/login.defs || true else echo 'SHA_CRYPT_MIN_ROUNDS 5000' | sudo tee -a /etc/login.defs >/dev/null || true fi if sudo grep -Eq '^[[:space:]]*#?[[:space:]]*SHA_CRYPT_MAX_ROUNDS\b' /etc/login.defs 2>/dev/null; then sudo sed -ri 's|^[[:space:]]*#?[[:space:]]*SHA_CRYPT_MAX_ROUNDS.*|SHA_CRYPT_MAX_ROUNDS 5000000|' /etc/login.defs || true else echo 'SHA_CRYPT_MAX_ROUNDS 5000000' | sudo tee -a /etc/login.defs >/dev/null || true fi sudo apt-get install -y libpam-pwquality || true set_pwq() { local key="$1" local val="$2" if sudo grep -Eq "^[[:space:]]*${key}[[:space:]]*=" /etc/security/pwquality.conf 2>/dev/null; then sudo sed -ri "s|^[[:space:]]*${key}[[:space:]]*=.*|${key} = ${val}|" /etc/security/pwquality.conf else sudo sh -c "printf '%s = %s\n' '${key}' '${val}' >> /etc/security/pwquality.conf" fi } set_pwq "retry" 3 set_pwq "difok" 6 set_pwq "minlen" 14 set_pwq "dcredit" -1 set_pwq "ucredit" -1 set_pwq "ocredit" -1 set_pwq "lcredit" -1 set_pwq "minclass" 4 set_pwq "usercheck" 1 set_pwq "enforcing" 1 # Add pam_pwquality to /etc/pam.d/common-password if not present if ! grep -q "pam_pwquality.so" /etc/pam.d/common-password 2>/dev/null; then sudo sed -i "/pam_unix.so/ i password requisite pam_pwquality.so" /etc/pam.d/common-password || true fi # [AUTH-9286] Password aging sudo sed -i 's/^PASS_MIN_DAYS.*/PASS_MIN_DAYS 7/' /etc/login.defs || true sudo sed -i 's/^PASS_MAX_DAYS.*/PASS_MAX_DAYS 90/' /etc/login.defs || true # [AUTH-9328] Default umask if sudo grep -Eq '^[[:space:]]*#?[[:space:]]*UMASK\b' /etc/login.defs 2>/dev/null; then sudo sed -ri "s|^[[:space:]]*#?[[:space:]]*UMASK[[:space:]]+.*|UMASK 077|" /etc/login.defs || true else echo 'UMASK 077' | sudo tee -a /etc/login.defs >/dev/null fi if grep -qE '^[[:space:]]*#?[[:space:]]*umask' /etc/bash.bashrc 2>/dev/null; then sudo sed -i 's/^[[:space:]]*#\?[[:space:]]*umask.*/umask 077/' /etc/bash.bashrc || true else echo 'umask 077' | sudo tee -a /etc/bash.bashrc >/dev/null fi if grep -qE '^[[:space:]]*#?[[:space:]]*umask' /etc/profile 2>/dev/null; then sudo sed -i 's/^[[:space:]]*#\?[[:space:]]*umask.*/umask 077/' /etc/profile || true else echo 'umask 077' | sudo tee -a /etc/profile >/dev/null fi # [AUTH-9408] Logging of failed login attempts is enabled if grep -q FAILLOG_ENAB /etc/login.defs 2>/dev/null; then sudo sed -i 's/^FAILLOG_ENAB .*/FAILLOG_ENAB yes/' /etc/login.defs || true else echo 'FAILLOG_ENAB yes' | sudo tee -a /etc/login.defs >/dev/null fi # [ACCT-9622] Enable process accounting sudo apt-get install -y acct || true sudo systemctl enable --now acct || true # [ACCT-9626] Enable sysstat sudo apt-get install -y sysstat || true sudo systemctl enable --now sysstat || true # [ACCT-9628] Enable auditd sudo apt-get install -y auditd || true sudo systemctl enable --now auditd || true # Fix ^space_left_action[[:space:]]*=[[:space:]]*email is not present in /etc/audit/auditd.conf if ! grep -q '^space_left_action[[:space:]]*=[[:space:]]*email' /etc/audit/auditd.conf 2>/dev/null; then log "Configuring auditd to email on low disk space..." sudo sed -i 's/^space_left_action[[:space:]]*=.*/space_left_action = email/' /etc/audit/auditd.conf || true fi # Fix ^admin_space_left_action[[:space:]]*=[[:space:]]*halt is not present in /etc/audit/auditd.conf if ! grep -q '^admin_space_left_action[[:space:]]*=[[:space:]]*halt' /etc/audit/auditd.conf 2>/dev/null; then log "Configuring auditd to halt on critical disk space..." sudo sed -i 's/^admin_space_left_action[[:space:]]*=.*/admin_space_left_action = halt/' /etc/audit/auditd.conf || true fi # Fix ^max_log_file_action[[:space:]]*=[[:space:]]*keep_logs is not present in /etc/audit/auditd.conf if ! grep -q '^max_log_file_action[[:space:]]*=[[:space:]]*keep_logs' /etc/audit/auditd.conf 2>/dev/null; then log "Configuring auditd to keep logs on max log file size..." sudo sed -i 's/^max_log_file_action[[:space:]]*=.*/max_log_file_action = keep_logs/' /etc/audit/auditd.conf || true fi # [ACCT-9630] Configure auditd rules sudo tee /etc/audit/rules.d/10-harden.rules >/dev/null <=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b32 -S chmod -S fchmod -S fchmodat -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b64 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b32 -S chown -S fchown -S fchownat -S lchown -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b64 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b32 -S setxattr -S lsetxattr -S fsetxattr -S removexattr -S lremovexattr -S fremovexattr -F auid>=1000 -F auid!=4294967295 -k perm_mod -a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access -a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EACCES -F auid>=1000 -F auid!=4294967295 -k access -a always,exit -F arch=b64 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access -a always,exit -F arch=b32 -S creat -S open -S openat -S truncate -S ftruncate -F exit=-EPERM -F auid>=1000 -F auid!=4294967295 -k access -a always,exit -F path=/usr/bin/chage -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/chfn -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/chsh -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/expiry -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/gpasswd -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/mount -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/newgrp -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/passwd -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/ssh-agent -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/su -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/umount -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/crontab -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/fusermount3 -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/dotlockfile -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/lockfile -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/procmail -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/newgidmap -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/newuidmap -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/bin/sudo -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/lib/openssh/ssh-keysign -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/lib/dbus-1.0/dbus-daemon-launch-helper -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/libexec/proxmox-mail-forward -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/libexec/pam-tmpdir/pam-tmpdir-helper -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/exim4 -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/unix_chkpwd -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/mount.cifs -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/mount.nfs -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/postdrop -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -a always,exit -F path=/usr/sbin/postqueue -F perm=x -F auid>=1000 -F auid!=4294967295 -k privileged -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 -a always,exit -F arch=b64 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete -a always,exit -F arch=b32 -S unlink -S unlinkat -S rename -S renameat -F auid>=1000 -F auid!=4294967295 -k delete -w /etc/sudoers -p wa -k sudoers -w /etc/sudoers.d/ -p wa -k sudoers -w /var/log/auth.log -p wa -k sudoaction -w /sbin/insmod -p x -k modules -w /sbin/rmmod -p x -k modules -w /sbin/modprobe -p x -k modules -a always,exit -F arch=b64 -S init_module -S delete_module -k modules # Make the configuration immutable (must be the last line) -e 2 EOL # Fix ^Storage=persistent is not present in /etc/systemd/journald.conf if ! grep -q '^Storage=persistent' /etc/systemd/journald.conf 2>/dev/null; then log "Configuring journald to use persistent storage..." sudo sed -i 's/^#Storage=.*/Storage=persistent/' /etc/systemd/journald.conf || true sudo systemctl restart systemd-journald || true fi # Fix tcpd is not installed sudo apt-get install -y tcpd || true # Fix Defaults log file not found in sudoers files log "Configuring sudo to log to /var/log/sudo.log..." if ! sudo grep -q '^Defaults[[:space:]]\+logfile=' /etc/sudoers; then sudo bash -c 'echo "Defaults logfile=\"/var/log/sudo.log\"" >> /etc/sudoers' log "Configured sudo to log to /var/log/sudo.log." else log "sudo logfile already configured in /etc/sudoers; skipping." fi # Fix logrotate permissions are not configured log "Configuring logrotate 'create 0640 root utmp' in /etc/logrotate.conf..." if ! grep -q '^create[[:space:]]\+0640[[:space:]]\+root[[:space:]]\+utmp' /etc/logrotate.conf; then sudo tee -a /etc/logrotate.conf >/dev/null <> /etc/pam.d/common-auth' sudo bash -c 'echo "auth [success=1 default=ignore] pam_faillock.so authfail" >> /etc/pam.d/common-auth' sudo bash -c 'echo "auth required pam_faillock.so postauth" >> /etc/pam.d/common-auth' log "Configured pam_faillock in /etc/pam.d/common-auth." else log "pam_faillock is already configured in /etc/pam.d/common-auth; skipping." fi # Fix pam_faillock not found in /etc/pam.d/common-account log "Ensuring pam_faillock is configured in /etc/pam.d/common-account..." if ! sudo grep -q '^account.*pam_faillock.so' /etc/pam.d/common-account; then sudo bash -c 'echo "account required pam_faillock.so" >> /etc/pam.d/common-account' log "Configured pam_faillock in /etc/pam.d/common-account." else log "pam_faillock is already configured in /etc/pam.d/common-account; skipping." fi # Fix ^password.*remember is not present in /etc/pam.d/common-password log "Ensuring password remember is configured in /etc/pam.d/common-password..." if ! sudo grep -q '^password.*remember' /etc/pam.d/common-password; then sudo bash -c 'echo "password required pam_unix.so remember=5" >> /etc/pam.d/common-password' log "Configured password remember in /etc/pam.d/common-password." else log "Password remember is already configured in /etc/pam.d/common-password; skipping." fi # Fix ^auth[[:space:]]*required[[:space:]]*pam_wheel.so is not present in /etc/pam.d/su log "Ensuring pam_wheel is configured in /etc/pam.d/su..." if ! sudo grep -q '^auth[[:space:]]*required[[:space:]]*pam_wheel.so' /etc/pam.d/su; then sudo bash -c 'echo "auth required pam_wheel.so" >> /etc/pam.d/su' log "Configured pam_wheel in /etc/pam.d/su." else log "pam_wheel is already configured in /etc/pam.d/su; skipping." fi # Fix ACTION=="add", SUBSYSTEMS=="usb", TEST=="authorized_default", ATTR{authorized_default}="0" is not present in /etc/udev/rules.d log "Ensuring USB storage devices are disabled via udev rules..." if [ ! -f /etc/udev/rules.d/85-usb-storage.rules ]; then sudo tee /etc/udev/rules.d/85-usb-storage.rules >/dev/null <