HOWTO: Set Up Google Authenticator in Ubuntu

By Ted Felix Updated July 4, 2020

Two-factor authentication (2FA) is all the rage these days. Google Authenticator is the path of least resistance. Here's how to get it running with ssh and public key authentication. These steps were tested with Ubuntu Server 18.04.

Note that these instructions do not work if you are using passwords with ssh. I recommend that you don't use passwords to get into your system remotely. If you are using passwords, connect a keyboard and monitor to your server, set ssh up so that only public keys are allowed, then continue with these instructions.

Physical Keyboard and Monitor

Before we start, remember that we are changing the login behavior for the system and it is possible that we might end up locked out. Make sure you are working with a real monitor and keyboard connected to the server in case something goes wrong. At the very least be ready to connect them in case you get locked out.

Install Google Authenticator on the Server

$ sudo apt install libpam-google-authenticator

Allow Users to Run google-authenticator on the Server

Normally, users can simply ssh into the server and run google-authenticator to get set up. However, if you've limited their access using the git-shell, it's probably best to create a shell script for them to use to access google-authenticator and copy it into their ~/git-shell-commands directory. This will allow you to enforce policy. Here's a script that enforces a relatively secure Google Authenticator policy:

#!/bin/sh google-authenticator -t -d -w 3 -r 3 -R 30

I call it "ga" and copy it to each user's ~/git-shell-commands. Make sure it's owned by root and 755 permissions.

-rwxr-xr-x 1 root root 54 Apr 19 10:58 ga

Server Configuration

/etc/ssh/sshd_config

Edit /etc/ssh/sshd_config and make the following changes:

Change ChallengeResponseAuthentication to yes.

Check UsePAM and make sure it is "yes". (My git server setup steps turn this off out of an abundance of caution. "PasswordAuthentication no" works regardless of the presence of PAM.)

Check AuthenticationMethods which may not be there. Add it or make it look like this:

AuthenticationMethods publickey,keyboard-interactive

To reload the config:

$ sudo systemctl reload sshd.service

(As an aside, if we don't do the next step, both public key and PAM are in effect with that AuthenticationMethods line. This means a public key check will be done along with whatever PAM is configured for, and that's usually passwords. So, users without passwords cannot get in now. We'll fix that by reconfiguring PAM in the next step...)

/etc/pam.d/sshd

Next we have to configure PAM (pluggable authentication modules) to use Google Authenticator. Edit the pam config in:

/etc/pam.d/sshd

At the top, where the @include for common-auth appears, comment out that @include and add the Google Authenticator configuration lines. When done, it should look like this:

#@include common-auth # "nullok" says 2FA will be skipped it if isn't configured. Without # nullok, users can't get in to set 2FA up in the first place. auth required pam_google_authenticator.so nullok # Needed because "nullok" returns IGNORE and something has to succeed. auth required pam_permit.so

There is no need to restart anything as pam config is re-read at each login.

User Setup

The steps for user setup are as follows:

  1. Install Google Authenticator app on your phone.
  2. ssh into the server.
  3. Run google-authenticator
  4. Specify "y" for time-based tokens.
  5. When the QR code appears, scan it with the Google Authenticator app on the phone.
  6. Jot down the emergency scratch codes for future reference.
  7. Specify "y" for updating the .google_authenticator file.
  8. The rest are preferences. I usually go with: disallow multiple uses - no; 17 permitted codes - no; enable rate-limiting - yes.

After setup, login with ssh. You will see the following prompt:

Verification code:

At that point, bring up Google Authenticator on your phone and enter the six-digit code that is displayed for the server.

Testing

The wonderful thing about PAM is that it can leave you with a system that has no security at all. It's a really good idea to do some testing to make sure everything is working as expected.

Test some normal ssh connections, both success and failure.

$ ssh -p <portnum> <user>@<host or ip>

Test Cases

Next thing to test is forced passwords to make sure they are rejected.

$ ssh -p <portnum> -o PreferredAuthentications=password -o PubkeyAuthentication=no <user>@<host>

This case MUST always fail.

Next check to make sure attempts to connect without a public key always fail.

$ ssh -p <portnum> -o PubkeyAuthentication=no <user>@<host>

This case MUST always fail.

License

Copyright (C) 2020, Ted Felix

Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. See http://www.gnu.org/licenses/fdl.html for the full text of this license.

<- Back to my software page.