Kingsfordweg 151, 1043GR Amsterdam, The Netherlands ● 24/7 support — support@novogara.com
Knowledge base

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:

  1. Keep your current session open
  2. Open a second terminal and log in with the new configuration
  3. 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