Two-factor on SSH
A stolen private key is the one failure that key-based SSH does not protect against. A second factor is what covers it.
Decide what you are protecting
If PasswordAuthentication no is already set, you are not defending
against guessing — there is nothing to guess. You are defending against a
laptop that is stolen with an unencrypted key on it, or a developer machine that gets
compromised.
That is a real risk and a narrow one. Apply the second factor where it matters: your bastion, your production hosts, anything with customer data.
A hardware key, if you can
The simplest and strongest option on a current OpenSSH is a FIDO2 key:
ssh-keygen -t ed25519-sk -O resident
The private key cannot leave the hardware, and logging in requires a physical touch.
No server-side configuration beyond putting the public key in
authorized_keys, and nothing to go wrong with clocks.
TOTP, the portable option
apt install libpam-google-authenticator, then as each user:
google-authenticator
In /etc/pam.d/sshd:
auth required pam_google_authenticator.so nullok
And in sshd_config:
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive
That comma is the whole point: it requires both a key and a code. A space instead of a comma would mean either one is enough.
Leave nullok while you are rolling it out, so users who have not
enrolled yet are not locked out, and remove it once everyone has.
Do not lock yourself out
The rule for every SSH change, and doubly here:
- Keep your current session open
- Open a second terminal and log in with the new configuration
- Only when that works, close the first
And confirm remote KVM works before you start. It is included on every machine and it is the way back in when SSH refuses you. Also check the clock — TOTP codes fail when it drifts, see keeping the clock right.
Keep automation working
Your deploy pipeline and your Ansible runs cannot type a code. Exempt them explicitly:
Match User deploy
AuthenticationMethods publickey
That account should already be restricted to the few commands it needs — see users and sudo. A second factor on humans and a narrow key for machines is the right shape.
Store the recovery codes somewhere else
google-authenticator prints scratch codes. Put them in your password
manager, not on the server they unlock. And see
keeping your account secure — two-factor on the
portal matters at least as much, because from there a machine can be
reinstalled.
Still stuck? Mail support@novogara.com — an engineer answers, at any hour. Back to the knowledge base