Post

Hardening SSH: Modern Ciphers, MFA, and Audit Trails

Hardening SSH: Modern Ciphers, MFA, and Audit Trails

SSH is the most attacked service in most home labs. Hardening it is not just about disabling passwords. You want modern cryptography, strong authentication, and an audit trail that lets you investigate brute force attempts or misconfigurations quickly.

This guide walks through practical hardening steps for OpenSSH on Linux. The goal is to harden without breaking automation or legitimate admin workflows.

Start with key-based auth

Generate modern keys and disable legacy algorithms. Ed25519 keys are fast and secure, and they avoid the compatibility issues of older RSA defaults.

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

On the server, ensure only your keys are authorized and disable password authentication.

Harden sshd_config

This minimal sshd_config snippet favors modern ciphers, disables root login, and restricts forwarding. Adjust the user and group lists to match your environment.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
Port 22
Protocol 2
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
AllowUsers adminuser
AllowGroups sshusers

Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com

AllowTcpForwarding no
X11Forwarding no
PermitTunnel no
MaxAuthTries 3
LoginGraceTime 30

After editing, validate the effective config:

1
sshd -T | egrep "ciphers|kex|macs|passwordauthentication"

Add MFA with PAM

For interactive logins, PAM-based MFA provides an additional barrier. The most common approach is pam_google_authenticator for TOTP or pam_u2f for hardware keys.

Example for TOTP:

1
2
sudo apt install -y libpam-google-authenticator
sudo -u adminuser google-authenticator -t -d -f -r 3 -R 30 -W

Then add this line to /etc/pam.d/sshd:

1
auth required pam_google_authenticator.so

Update sshd_config to allow keyboard-interactive auth combined with public key:

1
AuthenticationMethods publickey,keyboard-interactive

This forces both a valid key and a TOTP token. For automation accounts, create a dedicated user without MFA and restrict it to specific IPs and commands using ForceCommand.

Restrict by source and command

Limit SSH to known IP ranges with a firewall. In a lab, this is often just your management subnet.

1
2
sudo ufw allow from 192.168.56.0/24 to any port 22
sudo ufw enable

For automation, use authorized_keys options:

1
command="/usr/local/bin/backup.sh",no-agent-forwarding,no-pty,no-user-rc ssh-ed25519 AAAA... backup@lab

Logging and audit trails

SSH logs go to journalctl or /var/log/auth.log depending on the distro. Make sure you log both failures and successes.

1
sudo journalctl -u ssh -S "-1h"

Add auditd rules if you want detailed command auditing. This is heavier, but it gives you a clear trail when investigating a compromise.

1
2
sudo auditctl -w /etc/ssh/sshd_config -p wa -k ssh_config
sudo auditctl -w /home/adminuser/.ssh/authorized_keys -p wa -k ssh_keys

Host key hygiene

Server host keys are part of your trust model. Use modern host keys (ed25519 and RSA 3072+ if you need RSA compatibility) and rotate them when you rebuild systems. Document host key fingerprints in a secure admin inventory so you can detect unexpected changes.

If you run multiple lab servers, do not reuse the same host key across hosts. It makes man-in-the-middle detection impossible because all hosts present the same identity. It is better to accept the management overhead than to train users to ignore warnings.

Rate limiting and brute force defense

Even with keys, brute force scans can fill logs and hide real activity. Use a firewall or a tool like fail2ban to block repeated failures.

1
2
3
4
5
6
# /etc/fail2ban/jail.d/sshd.conf
[sshd]
enabled = true
maxretry = 5
findtime = 10m
bantime = 1h

This keeps the noise down and provides a basic deterrent to automated scanners.

Session recording and command auditing

For high value hosts, consider recording SSH sessions. Tools like tlog or auditd can capture executed commands. In a lab, this helps you validate that your audit trail captures administrative actions. If you rely on sudo logs, make sure they include the full command line and the invoking user.

Keep these logs separate from the host where possible. If an attacker compromises the host, they can tamper with local logs. Shipping SSH logs to a central server or SIEM makes the trail more reliable.

Bastion host pattern

Instead of exposing every host to the network, place a single bastion host in front of them. This reduces the attack surface and gives you one place to enforce MFA, logging, and rate limiting. In a lab, you can configure the bastion to allow outbound SSH only to the management subnet and block direct access to internal hosts.

Use the bastion for interactive admin access and reserve direct SSH for automation accounts with strict command restrictions. This mirrors real enterprise patterns and makes it easier to review access logs during an incident.

SSH certificates

If you manage many hosts, consider SSH certificates instead of individual public keys. A small internal SSH CA can sign user keys with short lifetimes, which reduces key sprawl and makes revocation simple. OpenSSH supports this with TrustedUserCAKeys and AuthorizedPrincipalsFile.

In a lab, start with a short-lived user cert and test login to multiple hosts. You will see how quickly you can rotate access without editing authorized_keys on every host.

Client-side configuration

Harden the client side too. Use ~/.ssh/config to enforce known hosts, disable deprecated algorithms, and pin the host key type. This prevents accidental downgrades when connecting to older systems and reduces exposure to man-in-the-middle attacks.

You can also enable UpdateHostKeys to automatically learn new host keys from a trusted server, which helps during key rotation. In a lab, test this by rotating a server host key and observing how clients behave.

Validate with ssh-audit

Use ssh-audit to check for weak algorithms and misconfigurations.

1
ssh-audit 192.168.56.10

If it reports weak ciphers or MACs, remove them from sshd_config and reload the service.

Common pitfalls

  • Locking yourself out by disabling password auth before keys are in place.
  • Enabling MFA for automation accounts that cannot supply tokens.
  • Leaving legacy RSA keys around that clients still prefer.
  • Allowing agent forwarding by default, which can expose credentials.

Takeaways

SSH hardening is a layered practice. Modern keys, strict cipher selection, MFA for interactive access, and tight logging make a huge difference. Once you have these controls in place, your lab becomes a good template for production systems, and you gain a realistic environment for testing your monitoring and incident response workflows.

This post is licensed under CC BY 4.0 by the author.