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
Installation
We will begin by installing google-authenticator. Here are the commands for that
Centos
# Enable epel-release (skip next step if already enabled) yum install -y epel-release yum install –y google-authenticator
Ubuntu
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.
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: 16188387 53505968 60252315 44059915 63553846
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.
NOTE: DO NOT LOGOUT UNTIL YOU COMPLETE THE FOLLOWING SECTION
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@1.2.3.4 Password: Verification code: Last login: Fri Jun 29 15:21:39 2018 from 4.3.2.1
Caution
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.