SSH Hardening: Core Concepts
SSH Hardening: Core Concepts
Every SSH server exposed to a network is a target. Within minutes of going live, automated scanners find it and begin brute-forcing passwords. SSH hardening is the process of reducing that attack surface by eliminating weak authentication, restricting who can connect, and limiting what they can do once connected.
The Attack Surface
A default OpenSSH installation accepts password authentication for all users, allows root login, and listens on port 22. Each of these defaults is a liability:
- Password authentication is vulnerable to brute-force and credential-stuffing attacks. Even strong passwords can be guessed given enough attempts.
- Root login gives an attacker full system access the moment they guess one credential.
- Port 22 is the first port every scanner probes. While changing it is not real security (security through obscurity), it reduces log noise from automated scans.
Key-Based Authentication
The single most impactful hardening step is replacing password authentication with SSH keys. An ed25519 key pair consists of a private key that stays on your machine and a public key that lives in ~/.ssh/authorized_keys on the server. The server challenges the client to prove possession of the private key without ever transmitting it.
# Generate an ed25519 key pair
ssh-keygen -t ed25519 -C "your_email@example.com"
# Copy the public key to the server
ssh-copy-id -i ~/.ssh/id_ed25519.pub user@server
# Test the connection
ssh -i ~/.ssh/id_ed25519 user@server
Ed25519 keys are preferred over RSA for several reasons: they are shorter (256-bit security in a 64-byte public key), faster to generate and verify, and resistant to certain side-channel attacks that affect RSA implementations.
Disabling Root Login
When PermitRootLogin is set to no, an attacker who compromises a user's credentials still cannot directly become root. They must also exploit a local privilege escalation vulnerability. This two-step requirement dramatically increases the difficulty of a full compromise.
# /etc/ssh/sshd_config
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
After changing sshd_config, always validate the configuration before restarting:
sshd -t # Test configuration syntax
systemctl restart sshd
Rate Limiting and Brute-Force Protection
Even with key-only authentication, attackers will still attempt connections. Two mechanisms limit the damage:
MaxStartups in sshd_config limits concurrent unauthenticated connections:
MaxStartups 10:30:60
This allows 10 unauthenticated connections, with a 30% chance of rejection above that, scaling linearly to 100% rejection at 60.
Fail2ban watches authentication logs and bans IPs that exceed a threshold:
# /etc/fail2ban/jail.local
[sshd]
enabled = true
maxretry = 3
bantime = 3600
With maxretry = 3, an IP is banned for one hour after three failed authentication attempts. This turns a brute-force attack from millions of attempts per day into a handful before the attacker is locked out.
Where It Fits
SSH hardening is one component of a layered defense. It works alongside firewall rules (nftables) that restrict which IPs can reach port 22, and audit logging (auditd) that records who connected and what they did. Study CIS Benchmarks first for a systematic hardening checklist, then move to nftables to control network access at the packet level.
SSH Hardening: Practice
SSH Hardening: Practice
Reading about SSH hardening does not stick until you have locked yourself out of a server at least once. The exercises below are designed to build muscle memory for the configuration changes that matter.
Exercise 1: Generate and Deploy Keys
On your local machine, generate an ed25519 key pair and deploy it to a test server:
# Generate the key pair
ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C "admin@company"
# Set proper permissions (SSH will refuse keys with loose permissions)
chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_ed25519
chmod 644 ~/.ssh/id_ed25519.pub
# Deploy the public key
ssh-copy-id -i ~/.ssh/id_ed_ed25519.pub admin@192.168.1.100
# Verify key-based login works
ssh -i ~/.ssh/id_ed25519 admin@192.168.1.100
Once key-based login is confirmed, disable password authentication:
# On the server, edit /etc/ssh/sshd_config
PasswordAuthentication no
# Validate and restart
sshd -t && systemctl restart sshd
Try connecting with a password — it should be rejected. This is the moment you confirm your key works before the door closes.
Exercise 2: Restrict Root and Configure a Non-Standard Port
# /etc/ssh/sshd_config
PermitRootLogin no
Port 2222
AllowUsers admin deploy
Protocol 2
AllowUsers restricts SSH access to only the listed accounts. Combined with PermitRootLogin no, an attacker needs to compromise a specific named account rather than trying common usernames.
After changing the port, update your local SSH config to avoid retyping it:
# ~/.ssh/config
Host webserver
HostName 192.168.1.100
Port 2222
User admin
IdentityFile ~/.ssh/id_ed25519
Now ssh webserver connects with all the right parameters.
Exercise 3: Set Up Fail2ban
# Install fail2ban
apt install fail2ban # Debian/Ubuntu
yum install fail2ban # RHEL/CentOS
# Create a local configuration
cp /etc/fail2ban/jail.conf /etc/fail2ban/jail.local
# Edit jail.local
cat > /etc/fail2ban/jail.local << 'EOF'
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = 2222
EOF
# Start and enable
systemctl enable --now fail2ban
# Check status
fail2ban-client status sshd
Test it by attempting three wrong passwords from another machine. After the third failure, fail2ban-client status sshd should show your IP in the banned list.
Check Your Understanding
- Why is
sshd -tcritical before restarting sshd after a configuration change? - What happens if you disable password authentication before confirming your key works?
- How does
MaxStartupsdiffer from Fail2ban in the type of attack it mitigates?
SSH Hardening: Trade-offs and Interviews
SSH Hardening: Trade-offs and Interviews
SSH hardening involves real trade-offs. Understanding when to apply each control — and when a control creates more problems than it solves — is what separates a security engineer from someone who follows a checklist blindly.
The Lockout Problem
The most common operational risk of SSH hardening is locking yourself out. Disabling password authentication before confirming key-based login works, or setting AllowUsers without including your own account, can leave you with no remote access path.
Mitigation strategies:
- Keep a backup session open while testing configuration changes. Only close it after confirming the new configuration works.
- Use a console or out-of-band access path (IPMI, iLO, cloud instance console) as a fallback.
- Test with
sshd -tand usesshd -d(debug mode) on a secondary port to verify behavior before applying to the production port.
When Key Management Beats Hardening
In large environments, managing individual authorized_keys files across hundreds of servers does not scale. Centralized key management solutions (HashiCorp Vault, Teleport, or certificate-based SSH with short-lived certificates) replace static keys with dynamically issued credentials. This is a trade-off: more infrastructure to operate, but no key distribution problem and automatic revocation.
When SSH Hardening Is the Wrong Tool
SSH hardening controls access to the SSH protocol itself. It does not protect against:
- Application-layer attacks against services running on the server
- Lateral movement after an attacker compromises a different entry point
- Insider threats from authorized users with legitimate access
For these, you need network segmentation, intrusion detection, and audit logging — not just SSH configuration changes.
How This Comes Up in Interviews
Interviewers probe whether you understand the reasoning behind each control, not just the configuration lines. Strong answers include:
- "Walk me through hardening a new Linux server." Start with key deployment, then disable passwords, restrict root, configure Fail2ban, and finally restrict the firewall to known IPs. Explain why each step matters.
- "A developer says disabling password authentication slows them down. How do you respond?" Acknowledge the friction, then explain that the security gain (eliminating brute-force attacks) outweighs the convenience cost, especially when combined with SSH config files and agent forwarding to minimize the friction.
- "How do you handle SSH access in a 500-server environment?" Move beyond per-server configuration to centralized management: configuration management tools (Ansible, Puppet), certificate-based SSH, or bastion hosts that provide a single audited entry point.
Practice Problems
Solution
Edit /etc/ssh/sshd_config with the following lines:
```
Port 2222
PermitRootLogin no
PasswordAuthentication no
PubkeyAuthentication yes
AllowUsers admin deploy
```
Then validate and restart:
```bash
sshd -t && systemctl restart sshd
```
Finally, update your local ~/.ssh/config:
```
Host webserver
HostName <server-ip>
Port 2222
User admin
IdentityFile ~/.ssh/id_ed25519
``` Solution
After the 3rd failed attempt, Fail2ban bans 10.0.0.5 for 3600 seconds (1 hour). The 4th and 5th attempts are rejected by the firewall before reaching sshd. After 1 hour, the ban is automatically lifted and the IP can attempt authentication again. Quiz
1. Why is ed25519 preferred over RSA for SSH keys?
2. What is the primary security benefit of setting PermitRootLogin to 'no'?
3. What does 'MaxStartups 10:30:60' in sshd_config accomplish?
4. Before restarting sshd after a configuration change, what command should you run and why?
Flashcards
Question
What does PermitRootLogin no accomplish?
Click to reveal answer
Answer
Prevents direct root login over SSH, forcing attackers to compromise a normal account first before attempting privilege escalation.
Question
Why use ed25519 over RSA for SSH keys?
Click to reveal answer
Answer
Ed25519 provides equivalent security with shorter keys, faster generation and verification, and resistance to side-channel attacks.
Question
What does MaxStartups 10:30:60 mean?
Click to reveal answer
Answer
Allows 10 concurrent unauthenticated connections, with 30% rejection probability above that, scaling to 100% rejection at 60.
Question
What is the purpose of sshd -t?
Click to reveal answer
Answer
Validates sshd_config syntax without restarting the service, preventing lockout from configuration errors.
Question
What does Fail2ban do with maxretry=3?
Click to reveal answer
Answer
Bans an IP address for the configured bantime after 3 failed authentication attempts within the findtime window.
Revision Notes
Key Takeaways
- 1. Key-based authentication with ed25519 keys eliminates brute-force password attacks.
- 2. Disabling root login forces a two-step compromise: user account first, then privilege escalation.
- 3. sshd -t validates configuration before restart, preventing accidental lockout.
- 4. Fail2ban bans IPs after repeated failed attempts, turning brute-force into a non-viable attack.
- 5. MaxStartups limits concurrent unauthenticated connections to prevent connection exhaustion.
Interview Tips
- • Explain the reasoning behind each hardening control, not just the config lines.
- • Discuss the lockout risk and how to mitigate it (backup session, console access, sshd -t).
- • For large environments, discuss centralized key management or certificate-based SSH.
- • Connect SSH hardening to the broader defense-in-depth strategy: firewalls, audit logging, and network segmentation.
Cheat Sheet
SSH Hardening Cheat Sheet
Phase: Linux and Windows Security Administration | Level: intermediate
Key Configuration (/etc/ssh/sshd_config):
PermitRootLogin no— Block direct root SSH accessPasswordAuthentication no— Force key-based auth onlyPubkeyAuthentication yes— Enable public key authenticationAllowUsers admin deploy— Restrict which accounts can SSHPort 2222— Non-standard port (reduces scan noise)MaxStartups 10:30:60— Rate-limit unauthenticated connections
Key Management:
ssh-keygen -t ed25519— Generate ed25519 key pairssh-copy-id -i ~/.ssh/id_ed25519.pub user@server— Deploy public keychmod 600 ~/.ssh/id_ed25519— Private key must be owner-only
Fail2ban:
maxretry = 3— Ban after 3 failuresbantime = 3600— 1-hour ban durationfail2ban-client status sshd— Check banned IPs
Tags: linux, remote-access