How To Enable MFA For Sudo and SSH Access

Multi-Factor Authentication (MFA) adds a critical security layer to your Linux servers by requiring users to prove their identity through something they know (SSH key or password) and something they have (a time-based one-time password from their phone). This guide walks you through configuring MFA for both SSH login and sudo command execution using Google Authenticator.
Prerequisites
Before configuring MFA, install the required package:
Debian/Ubuntu:
sudo apt update
sudo apt install libpam-google-authenticator
RHEL/CentOS/Rocky:
sudo dnf install google-authenticator
Configuration Files Overview
Enabling MFA requires modifying these key areas:
| File | Purpose |
/etc/pam.d/sshd | Controls SSH authentication via PAM |
/etc/pam.d/sudo | Controls sudo authentication via PAM |
/etc/ssh/sshd_config | Enables challenge-response for SSH |
/etc/sudoers or /etc/sudoers.d/* | Controls whether sudo prompts for authentication |
~/.google_authenticator | Stores per-user TOTP secrets |
Step 1: Configure SSH Daemon
Edit /etc/ssh/sshd_config to enable keyboard-interactive authentication:
# Enable challenge-response authentication
ChallengeResponseAuthentication yes
# Required on Debian 12+ / Ubuntu 22.04+
KbdInteractiveAuthentication yes
# Disable password-only authentication
PasswordAuthentication no
# Require both SSH key and TOTP for users
AuthenticationMethods publickey,keyboard-interactive
Per-user configuration (optional):
If you have service accounts that should bypass MFA:
# Default: require MFA
AuthenticationMethods publickey,keyboard-interactive
# Exception for automation accounts
Match User ansible,deploy
AuthenticationMethods publickey
Restart SSH after changes:
sudo systemctl restart sshd
Step 2: Configure PAM for SSH
Edit /etc/pam.d/sshd to enforce Google Authenticator:
# /etc/pam.d/sshd
# MFA enforcement - add at the top of auth section
auth required pam_google_authenticator.so nullok
# Comment out or remove standard password auth if using keys + TOTP only
#@include common-auth
# Keep the rest of the file unchanged
account required pam_nologin.so
@include common-account
@include common-session
@include common-password
Key directives:
| Directive | Meaning |
auth required | Authentication fails if this module fails |
pam_google_authenticator.so | The TOTP verification module |
nullok | Allows users without MFA configured to still log in (remove once all users are enrolled) |
Step 3: Configure PAM for Sudo
Edit /etc/pam.d/sudo to require TOTP for privilege escalation:
# /etc/pam.d/sudo
# Session configuration
session required pam_limits.so
session required pam_env.so readenv=1 user_readenv=0
session required pam_env.so readenv=1 envfile=/etc/default/locale user_readenv=0
# MFA enforcement
auth required pam_google_authenticator.so
auth required pam_permit.so
# Disable password-based sudo
#@include common-auth
@include common-account
@include common-session-noninteractive
This configuration ensures every sudo command requires a fresh TOTP code.
Step 4: Configure Sudoers for MFA
For sudo MFA to work, users must not have NOPASSWD in their sudoers configuration. The NOPASSWD directive bypasses PAM authentication entirely, skipping the MFA prompt.
Check existing sudoers configurations:
sudo cat /etc/sudoers
sudo ls -la /etc/sudoers.d/
sudo cat /etc/sudoers.d/*
For users who need MFA, use visudo to ensure they have:
# Requires authentication (triggers PAM/MFA)
username ALL=(ALL) ALL
For automation accounts that should bypass MFA, use NOPASSWD:
# No authentication prompt (bypasses PAM/MFA)
ansible ALL=(ALL) NOPASSWD: ALL
Editing sudoers safely:
Always use visudo to edit sudoers files - it validates syntax before saving:
# Edit main sudoers file
sudo visudo
# Edit user-specific file in sudoers.d
sudo visudo -f /etc/sudoers.d/uche
Example configurations:
| User Type | Sudoers Entry | MFA Behavior |
| Regular user | uche ALL=(ALL) ALL | Prompted for TOTP |
| Admin user | admin ALL=(ALL) ALL | Prompted for TOTP |
| Automation | ansible ALL=(ALL) NOPASSWD: ALL | No prompt, bypasses MFA |
| Deploy service | deploy ALL=(ALL) NOPASSWD: /usr/bin/systemctl | No prompt for specific commands |
Common mistake:
If you see this in your sudoers and want MFA for that user:
# WRONG - bypasses MFA
uche ALL=(ALL) NOPASSWD: ALL
Change it to:
# CORRECT - triggers MFA
uche ALL=(ALL) ALL
Dev vs Production Considerations
Consider different MFA policies based on environment:
| Environment | Recommended Policy |
| Production | MFA strictly enforced for all users |
| Staging | MFA enforced, mirrors production |
| Development | MFA optional or relaxed for faster iteration |
Implementation approach:
For development servers, you might use conditional PAM configuration:
# /etc/pam.d/sshd (Development)
# Relaxed: standard authentication without MFA
@include common-auth
# Production would instead have:
# auth required pam_google_authenticator.so
Trade-offs:
| Strict MFA Everywhere | Relaxed MFA in Dev |
| Consistent security posture | Faster development workflow |
| No environment-specific configs | Risk of bad habits carrying to production |
| Simpler auditing | Developers may resist MFA adoption |
A common middle ground: enforce MFA for sudo everywhere, but relax SSH MFA in dev environments.
Why MFA for SSH and Sudo Matters
The Risk Landscape
Traditional single-factor authentication leaves gaps:
| Attack Vector | Single-Factor Risk | MFA Mitigation |
| Stolen SSH key | Full server access | Attacker lacks TOTP device |
| Compromised password | Full server access | Password alone insufficient |
| Insider threat | Difficult to prove unauthorized access | Physical device required |
| Lateral movement | Attacker escalates via sudo | Each sudo requires fresh TOTP |
Defense in Depth
MFA creates multiple barriers:
Attacker must compromise:
SSH Key ──────────┐
├──▶ SSH Access ──┐
TOTP Device ──────┘ │
│
┌─────────────────┘
│
▼
TOTP Device ──────────▶ Sudo Access ──▶ Privileged Commands
Even with a compromised SSH key, the attacker cannot:
Log in without the TOTP code
Execute privileged commands without continuous TOTP verification
Compliance Benefits
MFA for privileged access helps meet:
PCI-DSS: Requirement 8.3 — MFA for administrative access
SOC 2: Logical access controls
HIPAA: Access control safeguards
NIST 800-53: IA-2 Multi-factor authentication
Wrap up
Enabling MFA for SSH and sudo creates a robust security posture:
SSH access requires: valid SSH key + valid TOTP code
Privilege escalation requires: valid TOTP code per command
The implementation centers on:
Installing
libpam-google-authenticatorConfiguring
/etc/ssh/sshd_configfor challenge-responseModifying
/etc/pam.d/sshdfor SSH MFAModifying
/etc/pam.d/sudofor sudo MFARemoving
NOPASSWDfrom sudoers for users requiring MFA
This approach ensures that even sophisticated attacks face multiple barriers before achieving privileged access to your systems.



