sz

Sejan

Blog

Hardening SSH on Linux Servers: Key-Based Authentication, Ed25519, Fail2Ban, and MFA Setup

Home › Privacy & Security › Hardening SSH on Linux Servers: Key-Based Authentication, Ed25519, Fail2Ban, and MFA Setup
Share
Hardening SSH on Linux Servers: Key-Based Authentication, Ed25519, Fail2Ban, and MFA Setup

Every publicly accessible Linux server on the internet is subject to an unrelenting barrage of automated brute-force attacks. Within minutes of spinning up a fresh VPS, port 22 is probed by botnets attempting default credentials, dictionary wordlists, and known exploit payloads.

Leaving default SSH configurations in place is an invitation for server compromise. Securing your shell access is the single most critical defensive measure in server administration. In this guide, we walk through an enterprise-grade SSH hardening blueprint: adopting high-security Ed25519 cryptographic keys, locking down sshd_config, deploying Fail2ban for automated IP ban policies, and enforcing Two-Factor Authentication (2FA/MFA).


1. Transitioning to Modern Ed25519 Cryptographic Keys

For years, RSA 2048 or 4096-bit keys were standard. Today, Ed25519 (Edwards-curve Digital Signature Algorithm) is the gold standard for SSH authentication. Ed25519 keys are faster, mathematically superior, resistant to side-channel attacks, and produce much shorter signatures (68 characters vs. over 500 characters for RSA).

Generate a new Ed25519 keypair on your local machine with key derivation function (KDF) rounds for enhanced passphrase protection:

# Generate a hardened Ed25519 key with 100 KDF rounds
ssh-keygen -t ed25519 -a 100 -C "[email protected]" -f ~/.ssh/id_ed25519_production

Copy the public key to your target server:

ssh-copy-id -i ~/.ssh/id_ed25519_production.pub username@your-server-ip

Verify that you can authenticate using the new key before touching the server configuration:

ssh -i ~/.ssh/id_ed25519_production username@your-server-ip

2. Production-Grade sshd_config Hardening

Open the SSH daemon configuration file on your server (/etc/ssh/sshd_config or modular drop-in file under /etc/ssh/sshd_config.d/99-hardened.conf):

sudo nano /etc/ssh/sshd_config.d/99-hardened.conf

Add or verify the following critical security directives:

# Enforce modern protocol version
Protocol 2

# Disable root login over SSH
PermitRootLogin no

# Strictly require public key authentication
PubkeyAuthentication yes
PasswordAuthentication no
PermitEmptyPasswords no

# Disable challenge-response password authentication
KbdInteractiveAuthentication no

# Reduce maximum authentication attempts before disconnect
MaxAuthTries 3

# Terminate stale or idle connections quickly
ClientAliveInterval 300
ClientAliveCountMax 2

# Disable insecure X11 and Agent forwarding unless explicitly needed
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no

# Restrict allowed key exchange, cipher, and MAC algorithms
KexAlgorithms curve25519-sha256,[email protected],diffie-hellman-group16-sha512,diffie-hellman-group18-sha512
Ciphers [email protected],[email protected],[email protected]
MACs [email protected],[email protected]
Warning: Always test your SSH configuration syntax with sudo sshd -t before restarting the daemon. Keep your existing SSH terminal session open while testing a new connection in a separate window.

Validate the syntax and reload SSH daemon:

sudo sshd -t && sudo systemctl reload sshd

3. Automated IP Banning with Fail2Ban

Fail2Ban continuously inspects authentication logs (/var/log/auth.log) and automatically inserts temporary firewall rules (via nftables or iptables) to drop traffic from IPs that exhibit repeated failed login attempts.

Installing and Configuring Fail2Ban

sudo apt update && sudo apt install -y fail2ban

Create a localized jail override at /etc/fail2ban/jail.local:

[DEFAULT]
bantime = 1h
findtime = 10m
maxretry = 3
backend = systemd

[sshd]
enabled = true
port = ssh
filter = sshd
maxretry = 3
bantime = 24h
findtime = 15m

Start and enable Fail2Ban:

sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd

You can inspect active banned IPs at any time:

sudo fail2ban-client get sshd banned

4. Enforcing Two-Factor Authentication (MFA / 2FA)

For critical bastion hosts and production servers, combining public key authentication with Time-based One-Time Passwords (TOTP) ensures that even a stolen private key is insufficient without the physical authenticator token.

Step 1: Install the PAM Google Authenticator Module

sudo apt install -y libpam-google-authenticator

Step 2: Generate TOTP Secrets for your User

Run the initialization wizard under your standard user account:

google-authenticator -t -d -f -r 3 -R 30 -W

Scan the generated QR code into your authenticator app (e.g., Aegis, Bitwarden Authenticator, or Google Authenticator) and store the emergency scratch codes safely in an encrypted password vault.

Step 3: Configure PAM and SSHD

Edit /etc/pam.d/sshd and append:

auth required pam_google_authenticator.so nullok

In /etc/ssh/sshd_config.d/99-hardened.conf, enable interactive authentication specifically for PAM while keeping passwords disabled:

KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
UsePAM yes

Reload the service:

sudo sshd -t && sudo systemctl reload sshd

5. Firewall Rate Limiting & Monitoring Summary

Complement your SSH hardening with local firewall rate-limiting using UFW:

# Deny connections from IPs making more than 6 attempts in 30 seconds
sudo ufw limit ssh
sudo ufw enable

Security Checklist

  • Ed25519 Only: Deprecate short RSA or DSA keys.
  • No Passwords: PasswordAuthentication no prevents brute force.
  • No Direct Root: Always authenticate via an unprivileged sudo user.
  • Active Jail: Fail2ban automatically suppresses automated network scanners.
  • MFA Defense: Dual-layer authentication protects infrastructure even in worst-case workstation compromise.

Comments (0)

Leave a Reply ↓

No comments yet. Be the first to start the discussion!

Leave a Comment