Two Factor Auth for SSH

Implementing Secure Two Factor Authentication for Linux SSH

Securing the Linux Secure Shell (SSH) interface represents the primary defensive perimeter for critical information infrastructure; whether managing distributed energy resources, municipal water control systems, or high-throughput cloud environments. Standard password or key-based authentication provides a single point of failure that is susceptible to exfiltration via side-channel attacks or sophisticated phishing. Implementing Two Factor Auth for SSH mitigates these risks by requiring a secondary, time-sensitive verification token. This protocol forces an “and” gate logic into the authentication flow: the knowledge component (private key or password) must coincide with the possession component (TOTP generator). By integrating the Pluggable Authentication Module (PAM) architecture, administrators establish a robust gatekeeper mechanism that significantly reduces the attack surface of the control plane. This manual details the hardening of the OpenSSH daemon through the integration of the Google Authenticator TOTP module, ensuring that unauthorized entry remains computationally and logistically improbable even in the event of primary credential compromise.

Technical Specifications

| Requirement | Default Port/Range | Protocol/Standard | Impact Level (1-10) | Recommended Resources |
| :— | :— | :— | :— | :— |
| OpenSSH Server | TCP 22 | SSHv2 | 10 | 1 vCPU / 512MB RAM |
| Google-Auth PAM | N/A | RFC 6238 (TOTP) | 9 | Low Overhead |
| NTP Sync | UDP 123 | NTP | 8 | Persistent Connection |
| Mobile Auth App | N/A | HMAC-SHA1 | 7 | iOS/Android Device |
| Root/Sudo Access | N/A | POSIX Permissions | 10 | Superuser Privileges |

The Configuration Protocol

Environment Prerequisites:

Ensure the target system is running a modern Linux distribution (Ubuntu 20.04+, RHEL 8+, or Debian 10+). The system clock must be synchronized via chronyd or ntpd to prevent rejection of valid tokens due to temporal drift. Minimum software requirements include libpam0g-dev and make if compiling from source; otherwise, standard repository packages suffice. Users must have sudo privileges to modify system-level configuration files and restart core services.

Section A: Implementation Logic:

The logic of Two Factor Auth for SSH relies on the Pluggable Authentication Module (PAM) architecture. PAM acts as an abstraction layer between Linux applications and various authentication backends. When a user attempts to connect via SSH, the daemon calls the PAM library, which executes a stack of modules defined in /etc/pam.d/sshd. By inserting the Google Authenticator module into this stack, we introduce a challenge-response requirement. The server generates a secret key (shared with the user’s mobile app) and uses the current unix time as a counter to produce a code. If the user’s provided code matches the server-generated code within a specific window of tolerance, access is granted. This mechanism ensures that even if a private key is leaked, the attacker cannot complete the handshake without the ephemeral payload generated by the user’s secondary device.

Step-By-Step Execution

1. Package Installation

Execute the following command to install the necessary PAM library:
sudo apt-get update && sudo apt-get install libpam-google-authenticator

System Note:

This command invokes the package manager to download the binary and link the shared objects into the system’s library path. It registers the module with the kernel’s dynamic linker, allowing the sshd process to call the PAM functions during the authentication phase without requiring a full system reboot.

2. Initialization of the TOTP Secret

Switch to the user account that requires 2FA and run the initialization tool:
google-authenticator

System Note:

This utility generates a unique HMAC-SHA1 secret key and stores it in ~/.google_authenticator. It also generates emergency “scratch codes” which are stored in cleartext: ensure these are moved to an offline vault. During this process, the tool modifies the user’s local filesystem; ensure proper umask settings are in place to prevent unauthorized read access to the secret key.

3. Modifying the PAM Stack

Edit the SSH PAM configuration file:
sudo vi /etc/pam.d/sshd
Add the following line to the top of the file:
auth required pam_google_authenticator.so

System Note:

This action modifies the stack of authentication instructions the kernel follows. By setting the control flag to “required,” the system mandates a success return code from the Google Authenticator module. Failure to provide a valid token will now result in a rejected session, regardless of the validity of the password or SSH key.

4. Adjusting the SSH Daemon Configuration

Modify the primary SSH configuration file to enable challenge-response:
sudo vi /etc/ssh/sshd_config
Locate and update the following directives:
KbdInteractiveAuthentication yes
UsePAM yes

System Note:

The sshd service reads this file to determine its operational parameters. Enabling KbdInteractiveAuthentication instructs the daemon to support keyboard-driven input for the 2FA prompt. Changing UsePAM to “yes” ensures the daemon hands off the authentication process to the PAM modules configured in the previous step.

5. Finalizing Stack Integration

To ensure SSH keys and 2FA work in tandem, add this line to the end of /etc/ssh/sshd_config:
AuthenticationMethods publickey,keyboard-interactive

System Note:

This directive defines the specific requirements for successful authentication. It creates an idempotent requirement where both a valid cryptographic signature (public key) and a manual input (TOTP code) must be verified before the system spawns a shell for the user.

6. Service Reload and Validation

Restart the SSH service to apply the changes:
sudo systemctl restart ssh

System Note:

The systemctl tool sends a SIGHUP or SIGTERM signal to the sshd process, forcing it to drop its current configuration state and re-read the files from the disk. This does not drop existing connections, providing a safety net if the configuration contains syntax errors.

Section B: Dependency Fault-Lines:

The most common point of failure is clock desynchronization. If the server’s system time differs from the mobile device’s time by more than 30 seconds, the TOTP payload will fail validation. Another bottleneck involves the order of operations in the PAM stack; placing the pam_google_authenticator.so after common-auth may result in the user being prompted for a password before the token, or bypassing the token entirely if the password check succeeds first. Ensure that file permissions on ~/.google_authenticator are strictly set to chmod 400 to prevent the module from failing due to insecure permission flags.

THE TROUBLESHOOTING MATRIX

Section C: Logs & Debugging:

When a connection fails, the primary source of truth is the system authentication log. Use the following command to monitor failures in real-time:
sudo tail -f /var/log/auth.log (Debian/Ubuntu) or sudo tail -f /var/log/secure (RHEL/CentOS).
Look for specific error strings such as:
“Invalid verification code”: Indicates clock drift or incorrect manual entry. Check the server time with the date command and compare it with the mobile device.
“Failed to read secrets”: Indicates the PAM module cannot access the .google_authenticator file. Check chmod permissions and owner/group settings.
“Authentication methods did not match”: Indicates the user’s SSH client is not attempting keyboard-interactive authentication. Force the client to use it using ssh -o PreferredAuthentications=keyboard-interactive user@host.

OPTIMIZATION & HARDENING

Performance Tuning: In high-concurrency environments, numerous SSH handshakes can increase CPU overhead. To mitigate this, use the nullok parameter in the PAM file (pam_google_authenticator.so nullok) only during a transition period to allow users without secrets to log in; however, remove this once the rollout is complete to maintain a strict security posture.
Security Hardening: Implement Fail2Ban to monitor /var/log/auth.log. Configure a jail that triggers after three failed 2FA attempts to block the source IP via iptables. This prevents brute-force attempts against the 6-digit TOTP window. Furthermore, ensure that the SSH daemon is bound to a specific internal IP to reduce exposure to the public internet where signal-attenuation or packet-loss could disrupt the timing-sensitive TOTP exchange.
Scaling Logic: For large-scale infrastructure, utilize configuration management tools like Ansible to deploy the PAM module and sshd_config changes. Use an idempotent playbook to ensure that the auth required line is only added once and that permissions are consistently applied across thousands of nodes. For remote sites with high latency, consider increasing the TOTP window size using the -w flag during initialization to account for network-induced delay.

THE ADMIN DESK

How do I bypass 2FA if I lose my device?
Use the emergency scratch codes generated during the google-authenticator setup. If those are gone, you must log in via a physical console or an out-of-band management tool (like IPMI) to reset the ~/.google_authenticator file for that user.

Can I use 2FA with SFTP or SCP?
Yes, but many GUI clients struggle with interactive prompts. It is recommended to use a master SSH connection (ControlMaster) to authenticate once, then tunnel SFTP/SCP traffic through the established, authenticated socket to avoid repeated 2FA prompts and latency.

Will this interfere with automated rsync backups?
Yes, automated scripts cannot provide a TOTP code. To resolve this, exclude the backup user from the 2FA requirement by using a Match User block in sshd_config or by assigning the backup user to a specific group not subject to the 2FA PAM stack.

Why does the code change every thirty seconds?
This is the RFC 6238 standard for TOTP. It minimizes the window of opportunity for an attacker to reuse an intercepted code. This “thermal-inertia” approach to security ensures that any leaked credential has a very short shelf-life and high decay rate.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top