Skip to content
Go back

2FA for SSH and sudo via PAM

By SumGuy 5 min read
2FA for SSH and sudo via PAM

Your SSH Key Just Leaked (Now What?)

Your private key is on GitHub. Not intentionally—you committed .env at 11 PM on a Friday and didn’t notice until Monday morning. Now someone has your SSH key. Without 2FA, they have full access to your server. Full stop.

Here’s the thing: SSH keys are amazing compared to passwords. But a leaked key is a stolen kingdom. Two-factor authentication (TOTP via your phone) won’t save you from every threat—nothing does—but it will stop that attacker cold. They have the key, sure, but they don’t have your phone. And they’re probably not patient enough to wait around.

This guide walks you through adding TOTP to both SSH and sudo using PAM (Pluggable Authentication Modules). It takes about 10 minutes, won’t break your server, and once you test it properly, you’ll sleep better.

Why 2FA for SSH Matters

People often think: “I have SSH keys. I don’t need 2FA.” But consider these scenarios:

TOTP doesn’t solve everything, but it converts a “full compromise” into a “maybe they get locked out when they try to sudo” situation. That’s worth 10 minutes.

Install libpam-google-authenticator

Start on your server. This works on Ubuntu, Debian, RHEL, Rocky—anywhere with PAM (which is basically everywhere).

Terminal window
sudo apt-get update
sudo apt-get install libpam-google-authenticator

On RHEL/Rocky:

Terminal window
sudo dnf install google-authenticator

Generate Your TOTP Secret

Run google-authenticator as your user:

Terminal window
google-authenticator

You’ll see prompts. Here’s what they mean:

Do you want authentication tokens to be time-based (y/n) y

Answer yes. This gives you TOTP (time-based, what Google Authenticator and Authy use).

Next, you’ll see a QR code. Scan it with your phone (Authy, Google Authenticator, Microsoft Authenticator—any TOTP app works).

Do you want me to update your "/home/kingpin/.google_authenticator" file? (y/n) y

Answer yes. This saves your secret locally.

Do you want to disallow multiple uses of the same authentication token? (y/n) y

Answer yes. Prevents replay attacks (someone using the same code twice).

Do you want to enable rate-limiting? (y/n) y

Answer yes. Stops brute-force attacks on the OTP codes.

After this, you’ll see backup codes. Screenshot or write these down and store them somewhere safe (encrypted password manager, not your Notes app). If you lose your phone, these get you back in.

Configure sshd for TOTP

Edit /etc/ssh/sshd_config:

Terminal window
sudo nano /etc/ssh/sshd_config

Make these changes:

/etc/ssh/sshd_config
#ChallengeResponseAuthentication no
ChallengeResponseAuthentication yes
#AuthenticationMethods publickey password
AuthenticationMethods publickey,keyboard-interactive

The first change enables interactive prompts. The second says: “require both a valid public key and keyboard-interactive auth (TOTP).” You must have the key and the code.

Check syntax:

Terminal window
sudo sshd -t

If you see no output, you’re good. If there’s an error, fix it before reloading.

Configure PAM for SSH

Edit /etc/pam.d/sshd:

Terminal window
sudo nano /etc/pam.d/sshd

Find the line that says @include common-auth and comment it out:

/etc/pam.d/sshd
@include common-auth
# @include common-auth

Then add these lines right after (before @include common-account):

/etc/pam.d/sshd
auth required pam_google_authenticator.so nullok sequential=deny

The nullok flag means: “if the user hasn’t set up TOTP yet, let them in anyway.” This prevents locking out other users. The sequential=deny flag prevents code reuse.

The Critical Test (Read This)

Do NOT close your current SSH session yet. Open a second terminal and SSH in as a test:

Terminal window
ssh user@your.server.com

You’ll be prompted for a password (which is your TOTP code—just the 6 digits, no special symbols). Enter the code from your phone. If you get in, great. If not, you have another terminal open to fix it.

This is the difference between a smooth deployment and being locked out of your own server at 2 AM.

Add TOTP to sudo

Now let’s require TOTP for sudo commands too. Edit /etc/pam.d/sudo:

Terminal window
sudo nano /etc/pam.d/sudo

Add this line right after the first @include common-auth line:

/etc/pam.d/sudo
auth required pam_google_authenticator.so nullok

Test it in your second terminal:

Terminal window
sudo -i

You’ll be prompted for a 6-digit code. Enter it. If it works, you’re good.

Fine-Tuning (Optional)

You might want TOTP for SSH login but not for key-only connections from trusted IPs (like your home network). This is possible but adds complexity—you’d modify sshd_config with Match blocks and conditional AuthenticationMethods. For now, require it everywhere. You can refine later.

Backup Codes: Don’t Lose Them

Those backup codes from google-authenticator? Print them. Store them in a safe place (encrypted password manager, physical safe). If your phone gets lost or stolen, those codes are your only way back in. Seriously.

You’re Done

You just added a second factor to SSH and sudo. An attacker with your private key now has to also have your phone. They probably don’t have your phone. That’s the whole idea.

Your future self (especially the 2 AM version) will thank you.


Share this post on:

Send a Webmention

Written about this post on your own site? Send a webmention and it'll show up above once verified.


Previous Post
CUDA vs ROCm vs CPU: Running AI on Whatever GPU You've Got
Next Post
LangGraph vs CrewAI vs AutoGen: AI Agent Frameworks for Mere Mortals

Discussion

Powered by Garrul . Sign in with GitHub or Google, or post anonymously.

Related Posts