Securing SSH access is a top priority for any Linux server, and relying on passwords alone is no longer sufficient against modern attacks like credential stuffing and brute force attempts. Adding multi‑factor authentication (MFA) to SSH hardens access by requiring something known (key or password) plus something possessed (a one‑time code or hardware key).
Ubuntu supports common MFA methods through PAM (Pluggable Authentication Modules), including app‑based TOTP(Time-based One-time) codes (Google Authenticator/Authy/FreeOTP) and FIDO/U2F security keys (YubiKey, Nitrokey).
Why MFA for SSH is Needed?
- Reduces risk from password reuse and brute‑force attacks by requiring a second factor even if a credential is compromised.
- Integrates cleanly with existing SSH setups using PAM without replacing SSH keys or existing workflows.
- Ubuntu includes enhanced support for FIDO/U2F, enabling hardware‑backed second factors for stronger, phishing‑resistant authentication
Prerequisites:
- Ubuntu 20.04 server with SSH access and sudo privileges.
- An authenticator app (Google Authenticator) on a phone if using TOTP.
- A backup console or out‑of‑band access in case of misconfiguration to avoid lockout
Steps:
Step 1 — Install the Google Authenticator PAM module
- Update and install the PAM module:
sudo apt update && sudo apt install -y libpam-google-authenticator
Step 2 — Enroll each user with google-authenticator
- For every account that will use SSH with MFA, run:
google-authenticator
- Recommended prompts:
time‑based tokens -> (y)
update the ~/.google_authenticator file -> (y)
disallow reuse -> (y)
keep default window (-> n)
enable rate limiting -> (y)
- Scan the displayed QR code in the authenticator app and store the emergency scratch codes securely
Step 3 — Enable PAM integration for SSH
- Edit PAM config:
sudo vi /etc/pam.d/sshd
- Add the Google Authenticator line (place it near the top so it’s evaluated early): auth required pam_google_authenticator.so
- If using SSH keys with MFA and not passwords, comment out the Un*x password include to avoid password prompts:
#@include common-auth
Notes:Using “nullok” makes the factor optional for users without enrolment; remove it later to enforce MFA globally.
Step 4 — Configure sshd to prompt for the second factor
- Back up and edit SSH server config:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak && sudo vi /etc/ssh/sshd_config
- Ensure these are set:
UsePAM yes
ChallengeResponseAuthentication yes
- If using SSH keys + MFA, explicitly require both:
AuthenticationMethods publickey,keyboard-interactive
- Save and restart SSH:
sudo systemctl restart sshd.service
Step 5 — Test login in a second terminal
- Connect and verify that after key authentication (or in addition to password if configured), SSH prompts for a “Verification code”.
- Use -v for verbose SSH output to confirm publickey then keyboard‑interactive flow.
Best Practices and Recovery:
- Keep a break‑glass account or console access before enforcing MFA server‑wide to prevent lockouts during testing.
- Use “nullok” initially if migrating gradually, then remove it to mandate MFA for all users once enrolled.
- Store emergency scratch codes securely in a password manager or vault.
- For key+MFA deployments, use AuthenticationMethods publickey,keyboard-interactive to cryptographically require both factors.
Conclusion:
Adding MFA to SSH on Ubuntu significantly elevates security by combining something possessed (TOTP code) with something known or inherent (SSH key or password). The TOTP route via libpam‑google‑authenticator is quick and widely compatible. With PAM and a few sshd settings, Ubuntu delivers a robust MFA setup that meaningfully reduces the risk of unauthorized SSH access.
Top comments (0)