How-to: Harden SSH Authentication with Google Authenticator

A long, long time ago (in this very galaxy) I wrote a post on how to Harden SSH on a Linux instance with Multi-Factor Authentication which focused on using a Yubikey to add an extra layer of security to the traditional SSH login process. Today though, I’d like to follow up on that post and examine the use of OTP (One-Time Password) tokens generated via an app to secure SSH login in much the same way as the Yubikey. The primary benefit to using a software-based token as opposed to the physical Yubikey token is that you don’t have to incur the expense of purchasing a Yubikey. We’ll be using Google Authenticator and CentOS, but the same principles apply to virtually all Linux distribution that use PAM-based authentication. It’s also important to note that other apps such as Authy and 1Password can be used to generate the OTP tokens. We’re using Google Authenticator due to it’s ease of use and ubiquity. Let’s get started!

Step 1: Install the Google Authenticator package

We’ll start by installing the Google Authenticator package which provides the pam_google_authenticator module. To install the Google Authenticator package on RHEL-like distributions run the following command:

Once package installation is complete, you’ll see output similar to the following:

NOTE: If you receive an error “No package google-authenticator available” you don’t have a repository containing the package installed. To install the EPEL repository which contains the google authenticator package run:

Step 2: Configure Google Authenticator package

Next, we’ll use the Google Authenticator binary to configure our OTP tokens. Configuring OTP generation with the Google Authenticator binary is a simple process which involves answering a few questions during the setup “wizard”. Run the following command to launch the OTP generation “wizard”:

The output from the setup “wizard” should look similar to the following images:

There are a three important portions in the output in the above screenshot. The first is the URL that starts with Copy and paste this URL into your browser and scan the resulting QR code with your OTP generation app of choice (Google Authenticator, Authy, 1Password, etc). You can also scan the ASCII QR code directly from the terminal if you’re presented with one as in the above image. Once you’ve scanned the code, you should notice a new account has been added and random codes are being generated. The next section of node are your emergency scratch codes. Make sure you record these codes and store them somewhere safe!! These codes can be used to login to your server in the event you phone is lost or stolen. Lastly, we’re presented with the configuration questions the determine how the Google Authenticator PAM module functions. The questions ask by the OTP generation wizard are fairly straightforward, but I’ll explain why I chose the answers I did nonetheless.

  1. Do you want authentication tokens to be time-based (y/n) yThe OTP tokens generated by the Google Authenticator are intended to be random and basing them off the current time is a great way to achieve an acceptable level of randomness.
  2. Do you want me to update your “/home/test-1/.google_authenticator” file (y/n) y

    The .google_authenticator file is the configuration file for the Google Authenticator server-side components so it’s probably a good idea to update it with the settings you’ll be choosing below. Also, notice the configuration file is being placed in the home directory for user test-1 (the user I’m currently logged-in as). Therefore, these configuration settings are user specific and you should be logged-in as the user you want to enforce multi-factor authentication for when running the google-authenticator binary.
  3. 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 

    Yes, you want to disallow multiple uses of the same token. The whole point of these tokens is to be one-time password tokens.

  4. By default, tokens are good for 30 seconds and 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. If you experience problems with poor
    time synchronization, you can increase the window from its default
    size of 1:30min to about 4min. Do you want to do so (y/n) n 

    As a Linux System Administrator I know significant time skew can cause a myriad of issues on a Linux system so I actually leave the default window in place because, with a property configured NTP daemon, a system should never drift even a few seconds, let alone multiple minutes.

  5. 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 reality of today’s world is that any Linux system that’s exposed to the public Internet is going to be subject to brute-force attacks so enforcing rate limiting at the module level is a good idea.

Step 3: Configure PAM

Now we move on to configuring PAM to enforce the second factor of authentication we just configured. We just need to edit the /etc/pam.d/sshd configuration file and add the following line to the bottom of the file (PAM modules are read sequentially and we want the pam_google_authenticator module to be read last so the OTP token is requested after all other authentication mechanisms).

Step 4: Configure SSH

We’ve configured PAM to process OTP tokens, but we still need to configure the SSH service on the system to request the OTP during a login attempt. To configure the SSH service edit the /etc/ssh/sshd_config file and change the ChallengeResponseAuthentication parameter to yes. The edited line should look like the following:

Now restart the SSH service with the following command:

Note: For sysv (init) based distributions run:

Step 5: Test

With configuration complete, you should test the configuration to ensure the system prompts for the OTP during an SSH login attempt. Simply open another terminal and attempt to connect to the system. If you aren’t prompted for the OTP or it fails verification tail the output of /var/log/secure and look for errors during login. If all goes well a successful login should request the user’s password followed by a verification code (OTP) like the example below:

That all there is to it! You’ve now hardened your single Linux system against SSH-based attacks and since this process relies largely on editing plain-text files, it can be adapted fairly easily into a shell script or configuration management state that can be executed across a large number of servers with minimal effort.


Leave a Reply

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