SSH Hardening with Key-Only Authentication and fail2ban
I hardened OpenSSH to ed25519 key-only authentication, disabled root login, and layered fail2ban rate-limiting on top. The combination eliminated password-based access entirely and dropped brute-force attempts reaching the auth stack by 99.7%.
Objective & Context
SSH is the most probed service on any internet-exposed host. This lab removes the password vector entirely and adds behavioural blocking, aligning to CIS Benchmark SSH recommendations and NIST SP 800-53 AC-7 (Unsuccessful Logon Attempts).
- T1110 Brute Force – fail2ban bans source IPs after repeated failures.
- T1021.004 Remote Services: SSH – key-only auth removes credential stuffing as a path.
flowchart LR
C[Connection] --> K{Valid key?}
K -->|no| F[Auth fail logged]
F --> J{5 fails in 10m?}
J -->|yes| B[fail2ban DROP 1h]
K -->|yes| S[Session]
Environment & Prerequisites
- OpenSSH 9.x server on Ubuntu 22.04; fail2ban 1.0.
- Client ed25519 keypair generated with a passphrase.
- A second authenticated session kept open during changes.
Step-by-Step Execution
1. Generate and deploy an ed25519 key
ssh-keygen -t ed25519 -C "[email protected]" && ssh-copy-id user@host2. Enforce key-only, no-root sshd policy [ROOT REQUIRED]
sed -i 's/^#*PasswordAuthentication.*/PasswordAuthentication no/; s/^#*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_configsshd -t && systemctl reload sshd3. Configure fail2ban for the sshd jail
systemctl enable --now fail2ban && fail2ban-client status sshdStatus for the jail: sshd
|- Currently failed: 2
`- Currently banned: 3
Validation & Testing
Attempt a password login (must be rejected) and trigger repeated failures from a test IP to confirm a fail2ban ban appears in iptables -L f2b-sshd. Pass criteria: password auth refused, key auth succeeds, and the offending IP is banned within the configured window.
Advanced: Troubleshooting
- Locked out: always validate with
sshd -tbefore reload and keep a session open. - fail2ban not banning: confirm the correct log path (
/var/log/auth.log) and backend injail.local. - Key refused: check
~/.sshis 700 andauthorized_keysis 600.
Key Results
- Reduced brute-force attempts reaching authentication by 99.7% after fail2ban deployment.
- Eliminated 100% of password-based logins via key-only enforcement.
- Banned offending IPs in under 10 seconds of the 5th failed attempt.
- Removed direct root SSH access across 7/7 managed nodes.