Skip to main content
RunBook Academy

LinuxXXVI · SSHMFA

SSH MFA and 2FA concepts

Intermediate⏱ ~10 minsshgoogle-authenticator

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

Not yet marked complete on this device.

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

MethodFactorUXOperational
TOTP (Google Authenticator)Phone appModerate (enter code)Simple, low cost
FIDO2 / U2F (YubiKey)Hardware tokenBest (touch)Low cost per key
SMS codesPhoneWorst (delivery issues)Discouraged for security
Push notification (Duo, etc.)PhoneBestVendor 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:

Read-only / Safesshd -t catches invented syntax
$ sshd -t -f /etc/ssh/sshd_config
Unknown 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:

Read-only / Safeprove MFA is enforced
$ ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no bastion.example.com
Permission 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

  1. Q1. Which MFA method is the gold standard for SSH?

  2. Q2. TOTP and FIDO2 both require something the user has.

  3. Q3. Which of the following are valid AuthenticationMethods values? Select all that apply.

  4. Q4. How do you express "either key + TOTP, or password + TOTP" in AuthenticationMethods?

  5. 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.