Skip to main content

Linux Hardening

A reference for securing Linux systems — covering user management, SSH, firewalls, file permissions, auditing, kernel tuning, and service hardening.


User and Account Security

Enforce Strong Password Policy

Configure password complexity and aging in /etc/login.defs:

PASS_MAX_DAYS   90
PASS_MIN_DAYS 7
PASS_MIN_LEN 12
PASS_WARN_AGE 14

Install and configure PAM password quality module:

sudo apt install libpam-pwquality

Edit /etc/security/pwquality.conf:

minlen = 12
dcredit = -1
ucredit = -1
ocredit = -1
lcredit = -1
maxrepeat = 3

Lock and Disable Unused Accounts

Lock an account (disables password login):

sudo usermod -L <username>

Set shell to nologin for service accounts:

sudo usermod -s /usr/sbin/nologin <username>

Find accounts with no password set:

sudo awk -F: '($2 == "" ) { print $1 }' /etc/shadow

Restrict Root Access

Disable direct root login. Require sudo for privilege escalation:

sudo passwd -l root

Limit sudo access to specific users/groups in /etc/sudoers (always edit with visudo):

%sudo   ALL=(ALL:ALL) ALL
tip

Review /etc/sudoers and /etc/sudoers.d/ regularly. Look for overly permissive entries like NOPASSWD:ALL or wildcard commands that could be abused.


SSH Hardening

Edit /etc/ssh/sshd_config:

# Disable root login
PermitRootLogin no

# Disable password authentication (use keys only)
PasswordAuthentication no
PubkeyAuthentication yes

# Disable empty passwords
PermitEmptyPasswords no

# Limit login attempts
MaxAuthTries 3

# Set idle timeout (seconds)
ClientAliveInterval 300
ClientAliveCountMax 2

# Restrict to specific users or groups
AllowUsers admin deployer
# AllowGroups sshusers

# Disable X11 forwarding and agent forwarding
X11Forwarding no
AllowAgentForwarding no

# Use only strong ciphers and MACs
Ciphers aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

# Disable legacy protocol
Protocol 2

# Change default port (optional, adds obscurity)
# Port 2222

Restart SSH after changes:

sudo systemctl restart sshd

SSH Key Management

Generate a strong key pair:

ssh-keygen -t ed25519 -C "admin@server"

Set proper permissions:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chmod 600 ~/.ssh/id_ed25519

Firewall Configuration

UFW (Uncomplicated Firewall)

Default deny incoming, allow outgoing:

sudo ufw default deny incoming
sudo ufw default allow outgoing

Allow specific services:

sudo ufw allow ssh
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

Limit SSH connections (rate limiting — blocks IPs with 6+ connection attempts in 30 seconds):

sudo ufw limit ssh

Enable the firewall:

sudo ufw enable
sudo ufw status verbose

iptables

Drop all incoming by default, allow established connections and specific services:

# Flush existing rules
sudo iptables -F

# Default policies
sudo iptables -P INPUT DROP
sudo iptables -P FORWARD DROP
sudo iptables -P OUTPUT ACCEPT

# Allow loopback
sudo iptables -A INPUT -i lo -j ACCEPT

# Allow established connections
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT

# Allow SSH
sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT

# Allow HTTP/HTTPS
sudo iptables -A INPUT -p tcp --dport 80 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 443 -j ACCEPT

# Log dropped packets
sudo iptables -A INPUT -j LOG --log-prefix "IPTables-Dropped: "

Save rules to persist across reboots:

sudo apt install iptables-persistent
sudo netfilter-persistent save

nftables (Modern Replacement)

nftables is the successor to iptables on newer Linux distributions:

sudo nft add table inet filter
sudo nft add chain inet filter input { type filter hook input priority 0 \; policy drop \; }
sudo nft add rule inet filter input ct state established,related accept
sudo nft add rule inet filter input iif lo accept
sudo nft add rule inet filter input tcp dport 22 accept
sudo nft add rule inet filter input tcp dport {80, 443} accept

File System Security

Set Proper Permissions on Sensitive Files

sudo chmod 600 /etc/shadow
sudo chmod 644 /etc/passwd
sudo chmod 600 /etc/gshadow
sudo chmod 644 /etc/group
sudo chmod 600 /boot/grub/grub.cfg

Find World-Writable Files and Directories

find / -type f -perm -o+w -not -path "/proc/*" -not -path "/sys/*" 2>/dev/null
find / -type d -perm -o+w -not -path "/proc/*" -not -path "/sys/*" -not -path "/tmp/*" 2>/dev/null

Find SUID/SGID Binaries

Review and remove unnecessary SUID/SGID bits:

find / -type f \( -perm -4000 -o -perm -2000 \) -exec ls -l {} \; 2>/dev/null

Remove SUID from binaries that don't need it:

sudo chmod u-s /path/to/unnecessary/suid/binary

Mount Options

Add restrictive mount options in /etc/fstab to limit what can be done on certain partitions:

/dev/sda2  /tmp   ext4  defaults,nosuid,noexec,nodev  0 0
/dev/sda3 /var ext4 defaults,nosuid 0 0
/dev/sda4 /home ext4 defaults,nosuid,nodev 0 0
  • nosuid — ignore SUID/SGID bits on this partition
  • noexec — prevent execution of binaries
  • nodev — ignore device files

Audit and Logging

auditd

auditd provides detailed system call auditing. Install and enable:

sudo apt install auditd
sudo systemctl enable auditd
sudo systemctl start auditd

Add rules to /etc/audit/rules.d/audit.rules:

# Monitor /etc/passwd and /etc/shadow changes
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity
-w /etc/sudoers -p wa -k sudoers

# Monitor SSH configuration
-w /etc/ssh/sshd_config -p wa -k sshd_config

# Monitor user authentication
-w /var/log/auth.log -p wa -k auth_log

# Monitor cron changes
-w /etc/crontab -p wa -k cron
-w /etc/cron.d/ -p wa -k cron

# Monitor binary execution in /tmp (common for attackers)
-w /tmp/ -p x -k tmp_exec

Search audit logs:

sudo ausearch -k identity
sudo ausearch -k sudoers --start today

Log Rotation and Centralization

Ensure logs rotate to prevent disk exhaustion. Check /etc/logrotate.conf and service-specific configs in /etc/logrotate.d/.

For centralized logging, forward logs to a SIEM using rsyslog or Filebeat (see Elastic Stack page).


Kernel Hardening (sysctl)

Apply kernel security parameters in /etc/sysctl.conf or /etc/sysctl.d/99-hardening.conf:

# Disable IP forwarding (unless this is a router)
net.ipv4.ip_forward = 0

# Disable ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv4.conf.default.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Enable SYN flood protection
net.ipv4.tcp_syncookies = 1

# Ignore ICMP broadcast requests
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Log martian packets (packets with impossible addresses)
net.ipv4.conf.all.log_martians = 1

# Disable source routing
net.ipv4.conf.all.accept_source_route = 0

# Enable address space layout randomization (ASLR)
kernel.randomize_va_space = 2

# Restrict access to kernel logs
kernel.dmesg_restrict = 1

# Restrict access to kernel pointers in /proc
kernel.kptr_restrict = 2

# Protect against hard/soft link attacks
fs.protected_hardlinks = 1
fs.protected_symlinks = 1

Apply changes:

sudo sysctl -p

AppArmor / SELinux

AppArmor (Ubuntu/Debian Default)

Check status:

sudo aa-status

Enforce a profile:

sudo aa-enforce /etc/apparmor.d/<profile>

Set a profile to complain mode (log violations but don't block):

sudo aa-complain /etc/apparmor.d/<profile>

SELinux (RHEL/CentOS Default)

Check status:

getenforce
sestatus

Set enforcing mode:

sudo setenforce 1

Make permanent in /etc/selinux/config:

SELINUX=enforcing

Service Hardening

Disable Unnecessary Services

List running services:

systemctl list-units --type=service --state=running

Disable services not needed:

sudo systemctl disable --now cups
sudo systemctl disable --now avahi-daemon
sudo systemctl disable --now bluetooth

Restrict Service Permissions with systemd

Add security directives to service unit files:

[Service]
ProtectSystem=strict
ProtectHome=yes
NoNewPrivileges=yes
PrivateTmp=yes
ReadOnlyDirectories=/etc

CIS Benchmark Reference

The Center for Internet Security (CIS) publishes detailed hardening benchmarks for every major Linux distribution. Use them as a comprehensive checklist:

tip

Automated CIS benchmark scanning tools like cis-cat or Lynis can audit a system against CIS recommendations and produce a report of gaps. Run sudo lynis audit system for a quick security audit.