Anasayfa / Cyber Security / Secure Your Linux SSH Logins: A Step‑by‑Step Guide to Implementing Multi‑Factor Authentication

Secure Your Linux SSH Logins: A Step‑by‑Step Guide to Implementing Multi‑Factor Authentication

Linux SSH security

In today’s threat landscape, a password alone is no longer enough to protect privileged access to your servers. Multi‑factor authentication (MFA) adds a second layer of verification, dramatically reducing the risk of credential‑stuffing attacks and unauthorized SSH sessions. This guide walks you through a complete, production‑ready MFA implementation for Linux SSH logins using the Pluggable Authentication Module (PAM) and Google Authenticator. By the end, you’ll have a hardened SSH service that asks for a time‑based one‑time password (TOTP) in addition to the usual key or password.

What You’ll Need

  • A Debian‑based or RHEL‑based Linux server with SSH already installed.
  • Root or sudo privileges on the target machine.
  • A smartphone with a TOTP app (Google Authenticator, Authy, or any compatible app).
  • Internet access to install packages from your distro’s repositories.
  • Basic familiarity with editing text files via vi, nano, or similar editors.

Step 1: Install the Google Authenticator PAM Module

The first component we need is the PAM module that can generate and verify TOTP codes. On Debian/Ubuntu, the package is called libpam-google-authenticator. On CentOS/RHEL 8+ it lives in the EPEL repository.

# Debian/Ubuntu
sudo apt update && sudo apt install -y libpam-google-authenticator

# RHEL/CentOS 8+ (enable EPEL first)
sudo dnf install -y epel-release
sudo dnf install -y google-authenticator

Installation is quick; the module places the binary /usr/bin/google-authenticator and the PAM library /lib/x86_64-linux-gnu/security/pam_google_authenticator.so (paths may vary slightly by distro).

Step 2: Generate a Secret for Each User

Each user that will log in via SSH needs a unique secret key. The easiest way is to run the google-authenticator command as that user. This command creates a .google_authenticator file in the user’s home directory, containing the secret, emergency scratch codes, and configuration flags.

# Switch to the target user (replace alice with the real username)
sudo -i -u alice
google-authenticator

The interactive script asks a series of questions. For a typical SSH‑only setup, answer as follows:

  1. Do you want authentication tokens to be time‑based (y/n)? – y
  2. Scan the QR code? – Use your phone’s TOTP app to scan the QR code displayed in the terminal (or copy the secret manually).
  3. Do you want to update the .google_authenticator file? – y
  4. Do you want to disallow multiple uses of the same token? – y (prevents replay attacks).
  5. Do you want to increase the time window? – n unless you have very high latency.
  6. Do you want rate‑limiting? – y (helps mitigate brute‑force attempts).

After completion you’ll see a list of eight emergency scratch codes. Store them securely; they can be used if the user loses their phone.

Step 3: Configure PAM to Use Google Authenticator

Now we tell PAM to invoke the Google Authenticator module during SSH authentication. Edit the file /etc/pam.d/sshd (or create a dedicated common-auth include, depending on your distro). Add the following line **above** any existing auth lines that use pam_unix.so:

auth required pam_google_authenticator.so nullok

The nullok flag allows users without a .google_authenticator file to log in using only their password or key. If you want to enforce MFA for every SSH user, omit nullok. Save the file and exit.

Step 4: Adjust the SSH Daemon Configuration

SSH must be aware that PAM will now request an additional authentication factor. Open /etc/ssh/sshd_config and ensure the following directives are set:

# Enable PAM integration
UsePAM yes

# Allow password authentication (required for the first factor)
PasswordAuthentication yes

# If you rely solely on public‑key authentication, keep this on but remember the first factor will be the key.
PubkeyAuthentication yes

# Optional: Increase the number of authentication attempts to give users time for the second factor.
MaxAuthTries 4

After editing, test the configuration syntax:

sudo sshd -t && echo "Syntax OK"

If you see Syntax OK, reload the daemon:

sudo systemctl reload sshd

Step 5: Verify the Setup with a Test User

Never test MFA on your root account. Create a disposable user, set a password, and run through the flow.

sudo adduser testmfa
sudo passwd testmfa
sudo -i -u testmfa
google-authenticator   # follow the same steps as in Step 2
exit

Now open a new terminal (do **not** use the existing session) and attempt an SSH login:

ssh testmfa@your_server_ip

You should see the usual password prompt, followed by a second prompt asking for the verification code:

Verification code:

Enter the 6‑digit code from your authenticator app. If everything is correct, you’ll be logged in. If the code is wrong, SSH will reject the attempt and log a PAM failure.

Step 6: Harden the Configuration for Production

Now that the basics work, tighten a few settings to make the deployment more secure.

  • Disable password authentication for key‑only users: If you enforce key‑based SSH for privileged accounts, set PasswordAuthentication no and rely on the public key as the first factor.
  • Restrict PAM to MFA only: Remove nullok from the PAM line to force every SSH user to have a TOTP secret.
  • Limit authentication attempts: In /etc/ssh/sshd_config, set MaxAuthTries 3 to reduce brute‑force windows.
  • Log MFA events: Add authlog syslog to pam_google_authenticator.so if you need detailed audit trails.

After making changes, always run sshd -t and reload the daemon.

Common Mistakes to Avoid

Even seasoned admins can stumble when adding MFA to SSH. Here are the most frequent pitfalls and how to sidestep them:

  • Editing the wrong PAM file: Some distributions split SSH PAM rules across /etc/pam.d/sshd and /etc/pam.d/common-auth. Verify which file is included by checking the auth section of /etc/pam.d/sshd.
  • Placing the PAM line after pam_unix.so: The order matters. If pam_google_authenticator.so appears after pam_unix.so, a successful password login can bypass the second factor.
  • Leaving nullok in production: This flag is handy for testing but defeats the purpose of MFA if left enabled for all users.
  • Forgetting to restart/reload SSH: Changes to sshd_config or PAM files won’t take effect until you reload the daemon. A silent typo can lock you out.
  • Using the same secret on multiple accounts: Each user must run google-authenticator individually; copying .google_authenticator between accounts creates a single point of failure.

Tips and Tricks

These optional tweaks can improve usability and security:

  • Backup TOTP secrets: Export the QR code or the base‑32 secret string to a password‑protected file. In case a user loses their phone, an admin can quickly re‑enroll.
  • Use hardware tokens: The same PAM module works with YubiKey OTP or FIDO2 devices when configured with auth required pam_u2f.so. Combine with TOTP for a multi‑layered approach.
  • Grace period for new users: Add auth [success=1 default=ignore] pam_unix.so nullok_secure before the Google Authenticator line to allow a one‑time password‑only login for brand‑new accounts that haven’t set up TOTP yet.
  • Centralized management: For large fleets, consider deploying .google_authenticator via Ansible, Chef, or Puppet. Store the secrets in an encrypted vault.

Frequently Asked Questions

Can I use MFA with public‑key authentication only?

Yes. SSH will first verify the public key, then PAM will request the TOTP code. This gives you “something you have” (the private key) plus “something you know” (the time‑based code).

What happens if the user’s phone is dead or they lose it?

Provide the eight emergency scratch codes generated during enrollment. Each code can be used once. Alternatively, an admin can reset the user’s .google_authenticator file and re‑run the enrollment process.

Is there a performance impact?

The TOTP verification is CPU‑light (a few SHA‑1/HMAC operations). In practice you’ll notice no measurable latency, even on modest VPS instances.

Conclusion

Adding multi‑factor authentication to Linux SSH logins is a relatively small configuration change that yields a massive security payoff. By leveraging the PAM Google Authenticator module, you gain a standards‑based, time‑synchronized second factor that works on any modern smartphone. Follow the steps above, double‑check the PAM order, and harden the final configuration for production. Your servers will now require both something you know (password or key) and something you have (TOTP), dramatically reducing the attack surface and keeping your critical infrastructure safe from credential‑theft attacks.

Photo by FlyD on Unsplash

Etiketlendi: