2FA for SSH Logins 

June 29, 2018
SSH LOGINS , tutorials
Deluxe company -

Why 2-Factor Authentication

Almost all server setup guides carry an instruction to use SSH keys for authentication. While it is the best approach to authenticating SSH sessions, in some cases it may not be possible. I SSH into my servers sometimes via web sessions (?) to fix small issues such as having to restart a service. Setting up 2FA for my connections ensures that I have to worry less about security.

What You Need

There are a few 3rd party applications that provide 2Factor authentication such as Authy (Free ?), Duo (Freemium ?). We will use the ubiquitous Google Authenticator as it does a splendid job. Plus, I am pretty sure most of us have Google accounts and are not too keen to sign up for an extra service.

All Linux flavors are supported, we will show the two most often used installation methods (APT – Ubuntu/Debian and YUM – Centos/Fedora/RHEL)

Install Google Authenticator from the App Store or the Play Store before proceeding


We will begin by installing google-authenticator. Here are the commands for that


# Enable epel-release (skip next step if already enabled)

yum install -y epel-release

yum install –y google-authenticator


apt-get install libpam-google-authenticator

Now we will run google-authenticator, by typing google-authenticator on the command prompt. There will be a series of questions, the first being

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

We answered y, as the tokens will be time based and not counter based.

You will get a QR Code on your terminal followed by secret key, verification codes & Emergency scratch codes.

null | Deluxe company


Scan the QR Code on your phone using the Google Authenticator App. The account should be added successfully.

You can manually add the account via the secret key in the app. The emergency scratch codes are for cases when you lose your device and want to login. Each scratch code is valid only once.

Your new secret key is: TCO3JPPATK5YWMGXWSPHFVZCRI

Your verification code is 412598

Your emergency scratch codes are:






To the question

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

Answer y, as you want the above codes & details to be stored for the current user (e.g. thisuser)

To prevent the same authentication token from being used, answer y to the next question

Do you want to disallow multiple uses of the same authentication

token? This restricts you to one login about every 30s, but it increases

your chances to notice or even prevent man-in-the-middle attacks (y/n) y

Unless you have a really laggy connection and believe that your phone may not sync correctly, answer n to the next question. This gives you a 1 minute and 30 second window for your token to be considered valid by the authentication server.

By default, a new token is generated every 30 seconds by the mobile app.

In order to compensate for possible time-skew between the client and the server,

we allow an extra token before and after the current time. This allows for a

time skew of up to 30 seconds between authentication server and client. If you

experience problems with poor time synchronization, you can increase the window

from its default size of 3 permitted codes (one previous code, the current

code, the next code) to 17 permitted codes (the 8 previous codes, the current

code, and the 8 next codes). This will permit for a time skew of up to 4 minutes

between client and server.

Do you want to do so? (y/n) n

If you had answered y to the above question, every token is valid for 4 minutes, which we don’t really want.

To prevent attackers from “brute-force” guessing your token, (which is most likely impossible given the 1.5 minute window we set earlier), you can go ahead and answer y to the next question which limits users from only 3 login attempts in 30 seconds.

If the computer that you are logging into isn't hardened against brute-force

login attempts, you can enable rate-limiting for the authentication module.

By default, this limits attackers to no more than 3 login attempts every 30s.

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

The authenticator app is setup now.


Changes to SSH

The Time-based One-Time Passwords (TOTPs) generated by the authenticator integrates with PAM or Pluggable Authentication Modules used by Linux. We need PAM to know about the authenticator.

Edit the file /etc/pam.d/sshd as a sudo user. The file already contains the following lines

# Used with polkit to reauthorize users in remote sessions

-session   optional     pam_reauthorize.so prepare

Add the following lines after the above

auth    required      pam_unix.so     no_warn try_first_pass

auth    required      pam_google_authenticator.so

Save the file. What you have effectively done is to inform PAM to prompt for the password first and then Google Authenticator

Next edit the /etc/ssh/sshd_config file as sudo user. Find the below line

# Change to no to disable s/key passwords

ChallengeResponseAuthentication no

Change the above field ChallengeResponseAuthentication to yes

# The file will look like this

ChallengeResponseAuthentication yes

Add at end of file, add the following lines

Match User thisuser

AuthenticationMethods keyboard-interactive

Now thisuser requires 2FA, other users will still not be forced to use 2FA. After all users are enrolled, remove the Match User line

Save the file and restart the ssh daemon

systemctl restart ssh                     # New systems

service ssh restart                       # Older linux flavors

Logging in

When you need to login, you will be prompted first with your password and then with your Verification code

$ ssh thisuser@


Verification code:

Last login: Fri Jun 29 15:21:39 2018 from


You must be careful to not lock yourself out of your system. Make sure you follow all instructions correctly. The final check is once you restart the ssh daemon, do not disconnect the current session. Try to start a new session and login with the username you just enabled for 2FA. Once you are able to connect successfully, you can disconnect the first session.

If you are not able to login, delete the lines you just added in the ssh configuration, restart the ssh service. Now login again to ensure that things are working now and try again.



Ramesh Vishveshwar
Ramesh Vishveshwar

Ramesh Vishveshwar is a tech blogger who is always on the lookout for the next big thing. Having discovered his infatuation for various flavors of Linux, he spends his time tinkering with VPS nodes installing and trying out new applications. His interest in coding spans across multiple languages from PHP, shell scripting to remote old generation languages such as COBOL.