SSH MFA and 2FA concepts
What you'll learn
- Describe what MFA adds to SSH authentication
- Configure TOTP-based 2FA via PAM
- Use FIDO2 hardware tokens (YubiKey)
- Recognise the operational trade-offs of each method
Prerequisites
Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09
Multi-factor authentication (MFA) adds something you have (a token or device) to something you know (a password or key). For SSH, MFA reduces the impact of a leaked credential.
MFA methods for SSH
| Method | Factor | UX | Operational |
|---|---|---|---|
| TOTP (Google Authenticator) | Phone app | Moderate (enter code) | Simple, low cost |
| FIDO2 / U2F (YubiKey) | Hardware token | Best (touch) | Low cost per key |
| SMS codes | Phone | Worst (delivery issues) | Discouraged for security |
| Push notification (Duo, etc.) | Phone | Best | Vendor cost |
For production, FIDO2 / U2F is the gold standard. TOTP is the standard fallback. SMS is not recommended.
TOTP with Google Authenticator
google-authenticator is the standard PAM module for TOTP.
Install:
sudo apt install libpam-google-authenticator
Configure for a user:
google-authenticator
Output includes:
- A QR code for the authenticator app.
- Secret key (manual entry).
- Emergency scratch codes (use once each).
The PAM module reads /home/user/.google_authenticator.
Configure SSH to require TOTP after publickey:
# /etc/ssh/sshd_config
KbdInteractiveAuthentication yes
AuthenticationMethods publickey,keyboard-interactive:pam
# /etc/pam.d/sshd
auth required pam_google_authenticator.so
KbdInteractiveAuthentication yes is a prerequisite, not a
detail. Hardening baselines commonly set it to no, and
keyboard-interactive:pam - the mechanism every SSH MFA
deployment uses - cannot run while it is disabled. Naming a
method in AuthenticationMethods does not enable it.
The user logs in with their key, then is prompted for the TOTP code. Two factors: the key (something you have) and the code (something you can compute from a secret).
FIDO2 with YubiKey
YubiKey (and other FIDO2 tokens) store a private key in hardware. The key signs challenges only when touched.
Generate an SSH key on the YubiKey:
ssh-keygen -t ed25519-sk -O resident -O verify-required
-O verify-required requires a touch for every auth.
Without it, the key can sign without confirmation.
The key is referenced as id_ed25519_sk in ~/.ssh/. ssh
uses it automatically when present.
Configure sshd for FIDO2
FIDO2 keys do not require special sshd configuration. They
work with the standard PubkeyAuthentication yes setup.
The advantage over TOTP:
- Hardware-protected key: cannot be extracted even from a compromised host.
- Touch required: physical presence prevents remote attacks.
- Single sign-on: many keys support multiple accounts.
AuthenticationMethods
AuthenticationMethods takes one or more lists. Within a
list, methods are joined by commas and every one of them must
complete, in order. Whole lists are separated by spaces,
and a login succeeds if it completes every method in at least
one list. That is how alternatives are expressed.
# Publickey only - one list, one method
AuthenticationMethods publickey
# Publickey then password - one list, both required
AuthenticationMethods publickey,password
# Publickey then TOTP via PAM - one list, both required
AuthenticationMethods publickey,keyboard-interactive:pam
# Either "key + TOTP" OR "password + TOTP" - two lists,
# separated by a space. Both alternatives are still two factors.
AuthenticationMethods publickey,keyboard-interactive:pam password,keyboard-interactive:pam
There is no or keyword. Writing
AuthenticationMethods publickey or password looks readable
and is rejected outright:
$ sshd -t -f /etc/ssh/sshd_configUnknown authentication method "or" in list
/etc/ssh/sshd_config line 42: invalid AuthenticationMethods method list.Illustrative output
Verify the policy from the client side rather than trusting the file. Ask the server what it wants:
$ ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no bastion.example.comPermission denied (publickey,keyboard-interactive).Illustrative output
Operational considerations
- Lost token: with TOTP, the user has emergency scratch codes. With FIDO2, they need a backup key registered.
- Recovery: production users should have at least two registered methods (key + TOTP, or two FIDO2 keys).
- Cost: FIDO2 keys cost $20-50 each. TOTP apps are free. Per-user cost matters at scale.
- Compliance: PCI-DSS, NIST 800-63, and many regulations require MFA for privileged access. SSH MFA meets this.
- Out-of-band recovery: if a user loses all factors, out-of-band recovery (cloud console, IPMI) is required.
When to enable SSH MFA
Enable SSH MFA when:
- The host handles privileged access (root, prod databases, critical services).
- Compliance requires it.
- The risk of a leaked credential is high.
Skip SSH MFA when:
- The host is for service-to-service automation (use certificates instead).
- The user base is large and cannot manage factors.
- The host is internal and protected by other means (bastion with MFA, VPN with MFA).
Knowledge check
Knowledge check · 5 questions
Q1. Which MFA method is the gold standard for SSH?
Q2. TOTP and FIDO2 both require something the user has.
Q3. Which of the following are valid AuthenticationMethods values? Select all that apply.
Q4. How do you express "either key + TOTP, or password + TOTP" in AuthenticationMethods?
Q5. You harden a bastion with `AuthenticationMethods any`, run `sshd -t` (exit 0), reload, and see no errors in the journal. What is the actual state of the host?
Passing score: 75%. Answers are checked in this browser.