Table of Contents
- Prerequisites
- Core Hardening Scripts
- Testing & Validation
- Best Practices for Hardening Scripts
- References
Prerequisites
Before running these scripts:
- Run as Root: Most hardening tasks require root privileges (
sudo -iorsu -). - Test in Staging First: Always validate scripts in a non-production environment to avoid breaking critical services.
- Understand the Scripts: Review and modify scripts to match your infrastructure (e.g., allowed SSH ports, trusted IPs).
- Backup Configs: Save copies of critical files (e.g.,
/etc/ssh/sshd_config,/etc/ufw/ufw.conf) before overwriting them.
Core Hardening Scripts
1. User Account Security Hardening
Weak user accounts are a top attack vector. This script secures user credentials, enforces password policies, and locks unused accounts.
Script: harden_user_accounts.sh
#!/bin/bash
# User Account Security Hardening Script
# Purpose: Lock unused accounts, enforce password policies, and remove empty passwords.
# --------------------------
# Step 1: Lock empty password accounts
# --------------------------
echo "Locking accounts with empty passwords..."
awk -F: '($2 == "") {print $1}' /etc/shadow | while read -r user; do
if [ "$user" != "nobody" ]; then # Skip system accounts like 'nobody'
passwd -l "$user" # Lock the account
echo "Locked empty password account: $user"
fi
done
# --------------------------
# Step 2: Enforce password policies (age, complexity)
# --------------------------
echo "Enforcing password policies..."
# Set max password age to 90 days (prevents permanent passwords)
chage -M 90 root # Apply to root
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do # Apply to non-system users (UID ≥ 1000)
chage -M 90 "$user"
done
# Set min password age to 7 days (prevents frequent resets)
chage -m 7 root
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
chage -m 7 "$user"
done
# Set password warning period to 14 days
chage -W 14 root
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
chage -W 14 "$user"
done
# --------------------------
# Step 3: Lock accounts inactive for 90+ days
# --------------------------
echo "Locking accounts inactive for 90+ days..."
for user in $(awk -F: '$3 >= 1000 {print $1}' /etc/passwd); do
last_login=$(lastlog -u "$user" | awk 'NR==2 {print $4 $5 $6}')
if [ "$last_login" == "**Neverloggedin**" ] || [ $(($(date +%s) - $(date -d "$last_login" +%s)))/86400 -ge 90 ]; then
passwd -l "$user"
echo "Locked inactive account: $user"
fi
done
# --------------------------
# Step 4: Remove non-root accounts with UID 0 (privilege escalation risk)
# --------------------------
echo "Checking for non-root UID 0 accounts..."
non_root_uid0=$(grep -v '^root:' /etc/passwd | awk -F: '$3 == 0 {print $1}')
if [ -n "$non_root_uid0" ]; then
echo "Warning: Non-root accounts with UID 0 found: $non_root_uid0"
echo "Consider deleting or modifying these accounts!"
fi
echo "User account hardening complete."
Key Features:
- Locks accounts with empty passwords (common in misconfigured systems).
- Enforces password expiration (90 days max, 7 days min, 14-day warning).
- Locks inactive accounts (≥90 days of inactivity).
- Detects non-root accounts with UID 0 (a critical privilege escalation risk).
Usage:
chmod +x harden_user_accounts.sh
./harden_user_accounts.sh
2. SSH Configuration Hardening
SSH is a primary entry point for attackers. This script disables weak ciphers, enforces key-based auth, and limits access.
Script: harden_ssh.sh
#!/bin/bash
# SSH Hardening Script
# Purpose: Secure SSH daemon configuration (sshd_config).
# Backup original sshd_config
cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak-"$(date +%F)"
# --------------------------
# Step 1: Basic SSH hardening
# --------------------------
echo "Configuring /etc/ssh/sshd_config..."
sed -i.bak \
-e 's/^#PermitRootLogin.*/PermitRootLogin no/' \ # Disable root SSH login
-e 's/^PermitEmptyPasswords.*/PermitEmptyPasswords no/' \ # No empty passwords
-e 's/^#PasswordAuthentication.*/PasswordAuthentication no/' \ # Disable password auth (key-based only)
-e 's/^#PubkeyAuthentication.*/PubkeyAuthentication yes/' \ # Enable key-based auth
-e 's/^#AuthorizedKeysFile.*/AuthorizedKeysFile .ssh\/authorized_keys/' \ # Define key file path
-e 's/^#MaxAuthTries.*/MaxAuthTries 3/' \ # Limit failed login attempts (3 tries)
-e 's/^#ClientAliveInterval.*/ClientAliveInterval 300/' \ # Idle timeout (5 mins)
-e 's/^#ClientAliveCountMax.*/ClientAliveCountMax 0/' \ # Disconnect after 5 mins idle
/etc/ssh/sshd_config
# --------------------------
# Step 2: Restrict SSH ciphers, MACs, and KexAlgorithms
# --------------------------
echo "Hardening SSH ciphers and algorithms..."
cat << EOF >> /etc/ssh/sshd_config
# Hardened security settings
Ciphers aes256-ctr,aes192-ctr,aes128-ctr # Only use AES-CTR (no CBC)
MACs hmac-sha2-512,hmac-sha2-256 # SHA-2 only (no SHA-1)
KexAlgorithms [email protected],diffie-hellman-group-exchange-sha256 # Strong key exchange
EOF
# --------------------------
# Step 3: Restrict SSH access (optional: limit by IP/user)
# Uncomment and modify the lines below to allow only specific IPs/users.
# --------------------------
# echo "AllowUsers [email protected]/24" >> /etc/ssh/sshd_config # Allow only 'admin' from 192.168.1.0/24
# echo "AllowGroups ssh-users" >> /etc/ssh/sshd_config # Allow only members of 'ssh-users' group
# --------------------------
# Validate and restart SSH
# --------------------------
echo "Validating SSH configuration..."
if sshd -t; then
echo "SSH configuration is valid. Restarting sshd..."
systemctl restart sshd # Use 'service ssh restart' on older systems
echo "SSH hardening complete."
else
echo "Error: Invalid SSH configuration! Restoring backup..."
cp /etc/ssh/sshd_config.bak-"$(date +%F)" /etc/ssh/sshd_config
fi
Key Features:
- Disables root SSH login and password authentication (key-based only).
- Limits failed login attempts (3 tries) and enforces idle timeout (5 mins).
- Uses strong ciphers (AES-CTR), MACs (SHA-2), and key exchange algorithms.
- Includes optional rules to restrict access by user/IP (e.g.,
AllowUsers).
Usage:
chmod +x harden_ssh.sh
./harden_ssh.sh
Note: After running, test SSH access from a secondary terminal to avoid locking yourself out!
3. Firewall Setup with UFW/iptables
A firewall blocks unauthorized network traffic. This script uses UFW (Uncomplicated Firewall) for simplicity (replace with iptables for advanced setups).
Script: harden_firewall.sh
#!/bin/bash
# Firewall Hardening Script (UFW)
# Purpose: Block all inbound traffic except essential services (SSH, HTTP/HTTPS).
# --------------------------
# Step 1: Install UFW (if missing)
# --------------------------
if ! command -v ufw &> /dev/null; then
echo "Installing UFW..."
if [ -f /etc/debian_version ]; then
apt-get update && apt-get install -y ufw # Debian/Ubuntu
elif [ -f /etc/redhat-release ]; then
yum install -y ufw # RHEL/CentOS (may require EPEL repo)
fi
fi
# --------------------------
# Step 2: Set default policies (deny inbound, allow outbound)
# --------------------------
echo "Setting default firewall policies..."
ufw default deny incoming
ufw default allow outgoing
# --------------------------
# Step 3: Allow essential inbound services
# Modify these rules to match your needs (e.g., add 443 for HTTPS).
# --------------------------
echo "Allowing critical inbound ports..."
ufw allow 22/tcp # SSH (replace with your SSH port if non-default)
# ufw allow 80/tcp # HTTP (uncomment if needed)
# ufw allow 443/tcp # HTTPS (uncomment if needed)
# ufw allow 5901/tcp # VNC (only if absolutely necessary!)
# --------------------------
# Step 4: Enable UFW and verify status
# --------------------------
echo "Enabling UFW..."
ufw --force enable # --force bypasses confirmation prompt
echo "Firewall status:"
ufw status verbose
Key Features:
- Blocks all inbound traffic by default (deny incoming, allow outgoing).
- Allows only critical ports (SSH, optionally HTTP/HTTPS).
- Installs UFW automatically (Debian/Ubuntu/RHEL/CentOS).
Usage:
chmod +x harden_firewall.sh
./harden_firewall.sh
For iptables Users: Replace UFW with iptables rules (e.g., iptables -A INPUT -p tcp --dport 22 -j ACCEPT).
4. Automated Package Updates & Vulnerability Patching
Outdated packages are a leading cause of breaches. This script automates updates and removes unneeded software.
Script: harden_packages.sh
#!/bin/bash
# Package Hardening Script
# Purpose: Update packages, remove unneeded software, and enable auto-updates.
# --------------------------
# Step 1: Update package lists and upgrade
# --------------------------
echo "Updating packages..."
if [ -f /etc/debian_version ]; then
apt-get update && apt-get upgrade -y # Debian/Ubuntu
elif [ -f /etc/redhat-release ]; then
yum update -y # RHEL/CentOS (use 'dnf' for newer versions)
fi
# --------------------------
# Step 2: Remove unneeded packages (reduce attack surface)
# --------------------------
echo "Removing unneeded packages..."
if [ -f /etc/debian_version ]; then
apt-get autoremove -y # Remove unused dependencies
apt-get purge -y telnet rsh ftp # Remove insecure tools
elif [ -f /etc/redhat-release ]; then
yum autoremove -y
yum remove -y telnet rsh ftp
fi
# --------------------------
# Step 3: Enable automatic updates
# --------------------------
echo "Enabling automatic updates..."
if [ -f /etc/debian_version ]; then
apt-get install -y unattended-upgrades # Debian/Ubuntu
dpkg-reconfigure -plow unattended-upgrades # Auto-accept prompts
elif [ -f /etc/redhat-release ]; then
yum install -y dnf-automatic # RHEL/CentOS 8+
systemctl enable --now dnf-automatic.timer
fi
echo "Package hardening complete."
Key Features:
- Updates all packages to the latest security patches.
- Removes insecure tools (telnet, rsh, ftp) and unused dependencies.
- Enables automatic updates (unattended-upgrades for Debian, dnf-automatic for RHEL).
Usage:
chmod +x harden_packages.sh
./harden_packages.sh
5. File & Directory Permission Hardening
Misconfigured file permissions allow unauthorized access to sensitive data. This script secures critical system files and directories.
Script: harden_permissions.sh
#!/bin/bash
# File Permission Hardening Script
# Purpose: Secure critical system files and directories.
# --------------------------
# Step 1: Secure /etc/passwd, /etc/shadow, and /etc/sudoers
# --------------------------
echo "Securing user/group files..."
chmod 644 /etc/passwd # Readable by all, writable only by root
chmod 000 /etc/shadow # No access except root (shadow-utils manages permissions)
chmod 440 /etc/sudoers # Readable by root and sudo group, no write for others
# --------------------------
# Step 2: Set sticky bit on /tmp (prevent unauthorized file deletion)
# --------------------------
echo "Securing /tmp..."
chmod 1777 /tmp # Sticky bit: users can only delete their own files
# --------------------------
# Step 3: Find and fix world-writable files (excluding /tmp)
# --------------------------
echo "Checking for world-writable files (excluding /tmp)..."
world_writable=$(find / -path /tmp -prune -o -perm -0002 -type f -ls 2>/dev/null)
if [ -n "$world_writable" ]; then
echo "Warning: World-writable files found:"
echo "$world_writable"
echo "Consider fixing with: chmod o-w <file>"
fi
# --------------------------
# Step 4: Find SUID/SGID binaries (potential privilege escalation)
# --------------------------
echo "Checking for SUID/SGID binaries..."
suid_sgid=$(find / -perm -4000 -o -perm -2000 -type f -ls 2>/dev/null)
if [ -n "$suid_sgid" ]; then
echo "SUID/SGID binaries found (review for necessity):"
echo "$suid_sgid"
fi
echo "File permission hardening complete."
Key Features:
- Secures
/etc/passwd(user info),/etc/shadow(password hashes), and/etc/sudoers(sudo privileges). - Sets the sticky bit on
/tmp(prevents users from deleting others’ files). - Detects world-writable files (a common vulnerability) and SUID/SGID binaries (potential escalation vectors).
Usage:
chmod +x harden_permissions.sh
./harden_permissions.sh
6. Auditd Configuration for Security Monitoring
auditd logs system events (e.g., file modifications, privilege escalation) for post-incident analysis. This script sets up basic audit rules.
Script: harden_auditd.sh
#!/bin/bash
# Auditd Hardening Script
# Purpose: Configure auditd to log critical security events.
# --------------------------
# Step 1: Install auditd (if missing)
# --------------------------
if ! command -v auditd &> /dev/null; then
echo "Installing auditd..."
if [ -f /etc/debian_version ]; then
apt-get install -y auditd audispd-plugins
elif [ -f /etc/redhat-release ]; then
yum install -y audit
fi
systemctl enable --now auditd
fi
# --------------------------
# Step 2: Add critical audit rules
# --------------------------
AUDIT_RULES="/etc/audit/rules.d/sec_hardening.rules"
echo "Writing audit rules to $AUDIT_RULES..."
cat > "$AUDIT_RULES" << EOF
# Log modifications to user/group files
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
# Log sudo usage
-w /usr/bin/sudo -p x -k sudo
# Log SSH access
-w /var/log/auth.log -p wa -k sshd # Debian/Ubuntu
-w /var/log/secure -p wa -k sshd # RHEL/CentOS
# Log firewall changes
-w /etc/ufw/ -p wa -k firewall
-w /etc/iptables/ -p wa -k firewall
# Log kernel module loading/unloading
-w /sbin/insmod -p x -k modules
-w /sbin/rmmod -p x -k modules
-w /sbin/modprobe -p x -k modules
EOF
# --------------------------
# Reload audit rules
# --------------------------
echo "Reloading audit rules..."
augenrules --load # Load new rules
systemctl restart auditd
echo "Auditd hardening complete. Logs are in /var/log/audit/audit.log."
Key Features:
- Logs modifications to user/group files (
/etc/passwd,/etc/shadow). - Tracks sudo usage, SSH access, firewall changes, and kernel module modifications.
- Stores logs in
/var/log/audit/audit.log(useausearch -k identityto query).
Usage:
chmod +x harden_auditd.sh
./harden_auditd.sh
Bonus: Malware Scanning with ClamAV
ClamAV is an open-source antivirus engine. This script installs ClamAV and runs a weekly scan.
Script: harden_malware_scan.sh
#!/bin/bash
# Malware Scanning Script (ClamAV)
# Purpose: Install ClamAV and schedule weekly scans.
# --------------------------
# Step 1: Install ClamAV
# --------------------------
echo "Installing ClamAV..."
if [ -f /etc/debian_version ]; then
apt-get install -y clamav clamav-daemon
elif [ -f /etc/redhat-release ]; then
yum install -y clamav clamav-update epel-release
fi
# Update virus definitions
echo "Updating virus definitions..."
freshclam # May take a few minutes
# --------------------------
# Step 2: Schedule weekly scans with cron
# --------------------------
echo "Scheduling weekly scan (Sunday 2 AM)..."
(crontab -l 2>/dev/null; echo "0 2 * * 0 clamscan -r / --exclude-dir=/sys --exclude-dir=/proc --log=/var/log/clamav/weekly_scan.log") | crontab -
echo "Malware scanning setup complete. Weekly scans log to /var/log/clamav/weekly_scan.log."
Usage:
chmod +x harden_malware_scan.sh
./harden_malware_scan.sh
Testing & Validation
After running the scripts, validate their effectiveness with these checks:
| Hardening Area | Validation Command |
|---|---|
| User Accounts | awk -F: '($2 == "") {print $1}' /etc/shadow (no output = no empty passwords) |
| SSH | sshd -t (validates config); grep PermitRootLogin /etc/ssh/sshd_config (should be no) |
| Firewall | ufw status (verify allowed ports); netstat -tulpn (check for unexpected listeners) |
| Packages | apt list --upgradable (no output = fully updated); dpkg -l telnet (should be “not installed”) |
| File Permissions | ls -l /etc/shadow (permissions: -rw-------); find /tmp -perm -0002 -type f (no world-writable files) |
| Auditd | ausearch -k identity (logs user file modifications) |
Best Practices for Hardening Scripts
- Version Control: Store scripts in Git (e.g., GitHub, GitLab) to track changes and roll back if needed.
- Logging: Add logging to scripts (e.g.,
>> /var/log/security_hardening.log 2>&1) for auditing. - Regular Execution: Run scripts via cron (e.g., monthly) to catch new vulnerabilities.
- Least Privilege: Run scripts with minimal permissions (e.g., use
sudofor specific commands instead of full root).
References
- CIS Linux Benchmarks (industry-standard security guidelines).
- Ubuntu Server Security Guide
- Red Hat Enterprise Linux Security Guide
- OpenSSH Documentation
- auditd Man Page
- ClamAV Documentation
By integrating these scripts into your workflow, you’ll significantly reduce your Linux infrastructure’s attack surface. Remember: security is a journey, not a destination—regularly update scripts and stay informed about new threats!