#!/usr/bin/env bash set -euo pipefail # Debian Hardening Script # Adapted from the Arch Linux hardening script (arch-hardening.sh) # Run as root or via sudo 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 upgrade -y # [STRG-1846] Disable drivers like firewire log "Disabling FireWire kernel modules..." sudo tee /etc/modprobe.d/firewire-disable.conf > /dev/null < /dev/null sudo systemctl restart systemd-resolved fi # [USB-3000] Ensure USBGUARD is installed and configured log "Installing usbguard..." sudo apt-get install -y usbguard if command -v usbguard >/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] Ensure arpwatch is installed and enabled log "Installing arpwatch..." sudo apt-get install -y arpwatch iface=$(ip -o link show | awk -F': ' '{print $2}' | sed 's/@.*$//' | grep -Ev '^(lo|virbr|vmbr)' | head -n1 || true) if [ -n "$iface" ]; then sudo systemctl enable --now "arpwatch@${iface}.service" || true else log_warn "No suitable network interface found for arpwatch; service not enabled." fi # [NETW-3200] Disable unused network protocols log "Disabling unused network protocol modules..." sudo tee /etc/modprobe.d/network-protocols-disable.conf > /dev/null </dev/null 2>&1; then sudo apt-get remove -y iptables || true fi sudo apt-get install -y nftables sudo tee /etc/modprobe.d/ip_tables-disable.conf > /dev/null < /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 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.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.ipv6.conf.all.accept_redirects = 0 net.ipv6.conf.default.accept_redirects = 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 AppArmor log "Installing and enabling AppArmor..." sudo apt-get install -y apparmor apparmor-utils 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=wheel 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=1,gid=wheel 0 0|' /etc/fstab fi sudo systemctl daemon-reload sudo mount -o remount /proc # [FILE-6374] Check /dev/shm and /tmp mount options log "Ensuring /dev/shm and /tmp have secure mount options..." 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/fs_blacklist.conf > /dev/null < /dev/null <chmod to restrict access log "Restricting compiler binaries..." for bin in /usr/bin/as /usr/bin/gcc /usr/bin/g++ /usr/bin/cc /usr/bin/c++ /usr/bin/ld /usr/bin/lld /usr/bin/clang; do if [ -f "$bin" ]; then sudo chmod 700 "$bin" || true fi done # [PKGS-7320] Install package auditing tools log "Installing arch-audit equivalent packages..." # Debian doesn't have arch-audit; install debsecan for security audits sudo apt-get install -y debsecan || true # [FILE-7524] Ensuring file permissions log "Enforcing file permissions for SSH & cron..." sudo chmod 600 /etc/ssh/sshd_config || true sudo chmod 700 /etc/cron.hourly || true # [CRYP-8004] Presence of hardware RNG and software PRNG log "Installing rng-tools and haveged..." sudo apt-get install -y rng-tools haveged || true sudo systemctl enable --now rng-tools haveged || true # [CRYP-8006] Ensure MemoryOverwriteRequest-bit set (UEFI) using system-shutdown script sudo tee /usr/lib/systemd/system-shutdown/mor-bit-wipe.sh > /dev/null <<'EOL' #!/bin/bash MOR_VAR_PATH="/sys/firmware/efi/efivars/MemoryOverwriteRequestControl-e20939be-32d4-41be-a150-897f85d49829" if [ -e "$MOR_VAR_PATH" ]; then printf "\x07\x00\x00\x00\x01" | dd of="$MOR_VAR_PATH" bs=5 count=1 conv=notrunc >/dev/null 2>&1 || true echo "$(date) - Successfully set MOR-bit for next boot memory wipe." >> /var/log/mor-wipe.log || true fi exit 0 EOL sudo chmod +x /usr/lib/systemd/system-shutdown/mor-bit-wipe.sh || true # [AUTH-*] Password and PAM related settings log "Configuring password hashing and pam pwquality..." sudo sed -i 's/^ENCRYPT_METHOD .*/ENCRYPT_METHOD YESCRYPT/' /etc/login.defs || true sudo sed -i 's/^#SHA_CRYPT_MIN_ROUNDS .*/SHA_CRYPT_MIN_ROUNDS 5000/' /etc/login.defs || true sudo sed -i 's/^#SHA_CRYPT_MAX_ROUNDS .*/SHA_CRYPT_MAX_ROUNDS 5000000/' /etc/login.defs || true sudo apt-get install -y libpam-pwquality || true sudo tee /etc/security/pwquality.conf > /dev/null </dev/null; then sudo sed -i "/pam_unix.so/ i password requisite pam_pwquality.so retry=3" /etc/pam.d/common-password || true fi # [AUTH-9286] Password change days 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 sudo sed -i 's/^UMASK.*/UMASK 027/' /etc/login.defs || true if grep -qE '^[[:space:]]*#?[[:space:]]*umask' /etc/bash.bashrc 2>/dev/null; then sudo sed -i 's/^[[:space:]]*#\?[[:space:]]*umask.*/umask 027/' /etc/bash.bashrc || true else echo 'umask 027' | 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 027/' /etc/profile || true else echo 'umask 027' | 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 # [ACCT-9630] Configure auditd rules sudo tee /etc/audit/rules.d/10-harden.rules > /dev/null <