SSH is the gateway to your infrastructure. A compromised SSH key or misconfigured daemon can lead to complete server takeover. Hardening SSH is one of the highest-impact security improvements you can make.


Disable Password Authentication


Password authentication is susceptible to brute-force attacks. Disable it and use key-based authentication only:



# /etc/ssh/sshd_config

PasswordAuthentication no

ChallengeResponseAuthentication no

UsePAM no

PubkeyAuthentication yes


After making changes, restart the SSH daemon:



sudo systemctl restart sshd


Always keep an active SSH session open while testing changes. If something breaks, you can debug before the session closes.


Use Ed25519 Keys


Ed25519 keys offer better security and performance than RSA:



ssh-keygen -t ed25519 -a 100 -f ~/.ssh/id_ed25519


The `-a 100` option increases the KDF rounds for the private key file, making it harder to crack if the file is stolen. For legacy systems that require RSA, use at least 4096-bit keys:



ssh-keygen -t rsa -b 4096 -a 100 -f ~/.ssh/id_rsa


Restrict Key Usage


Limit what individual keys can do using the `authorized_keys` file:



# ~/.ssh/authorized_keys

restrict,command="/usr/bin/git-shell",from="192.168.1.0/24" ssh-ed25519 AAA...


The `restrict` keyword denies all forwarding and agent access. `command=` limits the key to a specific command. `from=` restricts which IP addresses can use this key.


Disable Root Login


Never allow direct root SSH access:



PermitRootLogin no


Use a regular user account with `sudo` access instead. This creates an audit trail -- every privileged command is logged with the user who ran it.


Change the Default Port


Changing the default port (22) reduces automated attack noise:



Port 2222


This is not real security (a determined attacker will find your SSH port), but it dramatically reduces log noise from automated scanners.


Use a Strong Cipher Configuration


Modern SSH supports strong ciphers. Enforce them:



Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com

MACs hmac-sha2-256-etm@openssh.com,hmac-sha2-512-etm@openssh.com

KexAlgorithms curve25519-sha256,diffie-hellman-group16-sha512

HostKeyAlgorithms ssh-ed25519,rsa-sha2-512


This configuration only allows algorithms with proven security. Remove legacy algorithms like `diffie-hellman-group14-sha1` and `hmac-sha1`.


SSH Timeout and Session Limits


Prevent idle sessions from accumulating:



ClientAliveInterval 300

ClientAliveCountMax 2

TCPKeepAlive no

MaxSessions 10

MaxStartups 10:30:60


`ClientAliveInterval=300` with `ClientAliveCountMax=2` means the server checks every 5 minutes and disconnects after 10 minutes of inactivity. `MaxStartups` limits concurrent unauthenticated connections to prevent DoS attacks.


Fail2Ban Integration


Install and configure Fail2Ban to block brute-force attempts:



sudo apt install fail2ban



# /etc/fail2ban/jail.local

[sshd]

enabled = true

port = ssh

filter = sshd

logpath = /var/log/auth.log

maxretry = 3

bantime = 3600

findtime = 600


This bans IPs for one hour after three failed attempts within ten minutes. For internet-facing SSH, consider longer ban times (24 hours) to be more aggressive.


Two-Factor Authentication


Add a second factor with `libpam-google-authenticator`:



sudo apt install libpam-google-authenticator

google-authenticator



# /etc/pam.d/sshd

auth required pam_google_authenticator.so



# /etc/ssh/sshd_config

ChallengeResponseAuthentication yes

AuthenticationMethods publickey,keyboard-interactive


This requires both an SSH key and a TOTP code to authenticate. Use this for high-value jump boxes and production servers.


SSH Agent Forwarding


Be careful with agent forwarding. Use `-J` (jump host) instead when possible:



# Instead of forwarding your agent through a chain:

ssh -J bastion.example.com target.internal



# Or use ProxyJump in ~/.ssh/config:

Host internal-*

  ProxyJump bastion.example.com


If you must use agent forwarding, use `ssh -A` with the `-t` flag for a single session rather than enabling forwarding globally in your config.


Key Rotation


Regularly rotate SSH keys and audit authorized keys:



#!/bin/bash

# audit-ssh-keys.sh

for user in $(getent passwd | cut -d: -f1); do

    home=$(getent passwd "$user" | cut -d: -f6)

    if [[ -f "$home/.ssh/authorized_keys" ]]; then

        echo "User: $user"

        cat "$home/.ssh/authorized_keys"

    fi

done


Remove keys belonging to departed team members and replace keys that are over a year old. Integrate key management with your identity provider (Okta, Azure AD) using tools like `ssh-ca` for certificate-based auth.


Monitor SSH Access


Monitor SSH access in real-time:



# Watch auth log for SSH activity

tail -f /var/log/auth.log | grep sshd



# Audit currently logged-in users

w



# Last login times for all users

lastlog


Set up alerts for SSH logins from unexpected IP ranges or at unusual hours using log ingestion tools.


Summary


SSH hardening follows defense in depth: disable passwords, use Ed25519 keys, lock down the daemon configuration, and add Fail2Ban. For production systems, add two-factor authentication and eliminate agent forwarding in favor of jump hosts. Regularly audit authorized keys and rotate them. Most SSH compromises come from weak configurations, not zero-days -- hardening your SSH setup prevents the majority of attack vectors.