Brain Phrye

code cooking diy fiction personal photos politics reviews tools 

The Less Scary Guide To Google Authenticator and PAM

[ Listen to article ]

Modifying low level authentication is a worrisome thing. If you do it wrong the fear is that you can’t log back in to fix it. So unlike some other guides out there I’ll point out the danger points here and some ideas on how to address them.

This is kind of long so a high level overview is this: install client software, install server software, activate server software, generate key, done! But first, let’s get some background here.

Also note that if you use home directory encryption this guide won’t work for you. Read this.


First let’s explain what this is and why you might want it. The general idea behind “second factor authentication“ (2FA) is that you should need something besides a password to authenticate yourself. The original idea was a hardware token. The token would have a special key that would be used to generate a sequence or time based code that would be matched on the server. This way if your password is compromised (keylogger, someone peeking over your shoulder, phishing), they’re still not going to get in because of that second factor. That second factor is also called a “one time password” (OTP) because it’s a password you can only use once.

Google Authenticator (GA) is actually a number of things that implement all parts of two open standards for a 2FA system. Those two standards are described in RFCs 6238 and 4226 and GA consists of some mobile apps that generate OTPs and a “pluggable authentication module” (PAM) that authenticates those OTPs on the server side.

Install Client Software

Note: Authentication doesn’t change here.

That’s what we’re going to install now. First you need the GA mobile app. You can use the Google Authenticator mobile app, but there are a number of other ones. Last I looked there were ones by Amazon, LastPass and a number of others. The GA app supports reading the key via a barcode which is nice for usability as you’ll see.

In addition to the mobile apps you can also install oathtool on a Linux box. Install it with apt-get install oathtool. Later on you could run this on your server to generate an OTP:

oathtool -b --totp `head -1 ~/.google_authenticator`

Install Server Software

Note: Authentication doesn’t change here.

On the Linux server side we’ll install the libpam-google-authenticator package (this will be on an Ubuntu 16.04 system, adjust for yours). It’s important to note that there are alternatives here too. On Ubuntu/Debian there’s libpam-oath. It makes some different design decisions, but implements the same 2FA system. For this though I’ll stick with libpam-google-authenticator.

Once installed nothing will change. You can run sudo apt-get install libpam-google-authenticator in complete safety. Nothing in the authentication system will change at this point. So run that and we’ll go about activating it.

A Little More Background

Now, before activating it, one last bit of theory about what we’re doing. GA will protect you from someone stealing your password. But remember, if they have physical access to your machine all bets are off. You can enable it for console and GUI logins if you wish, but for protecting a physical machine you should use full disk encryption (easiest to do at install).

What you really want GA for is for protecting ssh. And specifically you want it for ssh sessions that are authenticated by password. If you authenticate with your ssh key, you don’t need OTP.

Activate Server Software

Note: Authentication is changing. Be careful.

You will not require an OTP yet - you haven’t generated an OTP key yet! However keep a few terminals connected and sudo’d to root when you do this step and then check logins to confirm you can still connect. Also you should have ssh public key authentication already set up.

In one of those root sessions run the following. And note that restarting the ssh server will not disconnect any ssh sessions.

echo "auth required nullok" >> /etc/pam.d/sshd
sed -i "s/\(ChallengeResponseAuthentication \)no/\1yes/" /etc/ssh/sshd_config
systemctl restart sshd.service

Now try logging in via ssh via public key in another terminal. This should work just fine. Now try it without public key auth:

ssh -oPubkeyAuthentication=no YOUR-SERVER

Note that it’s not asking you for a one time password. This is because when we enabled pam_google_authenticator we set the nullok option. This enables you to bypass an OTP if you don’t have an OTP configured. Brilliant!

But let’s do the generate key thing:

Generate Key

Note: Authentication switches over to OTP here. Test!

In addition to installing that PAM GA module, that package also installed a tool called google-authenticator to generate your OTP key. So let’s run that - make sure your mobile GA client is installed and ready for a new key.

Do you want authentication tokens to be time-based (y/n) y|0&cht=qr&chl=otpauth://totp/kevin@bo%3Fsecret%3D2MVLIBJG4I6ZVCAN
[...deleted ascii barcode...]
Your new secret key is: 2MVLIBJG4I6ZVCAN
Your verification code is 526265
Your emergency scratch codes are:

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

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

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) y

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) n

Note that this is not my OTP. It’s just an example session to explain the questions you’ll get. To explain my answers:

First I picked a time based OTP (TOTP). Sequence based OTP (HOTP) are a bit more secure. You can detect if people have used your OTPs, but you’re really limited to a single device. Which is kind of a hassle.

Once picked you’ll get a barcode and the key - enter one or the other into your GA mobile app. Make sure to record the “emergency scratch codes” somewhere safe.

Once done, save the file. Next up disallow reuse (self-explanatory) and then let OTPs be valid for a wider window. This allows your server and phone to drift a bit time-wise. Not too much though so make sure your clocks are in sync with time servers.

Lastly turn off rate limiting. If you want to rate limit ssh connections, use fail2ban. And you should rate-limit failed ssh connections to stop brute-forcing attacks that just suck up bandwidth.

OTP is now active on your account. Attempt to ssh in without your public key (ssh -oPubkeyAuthentication=no YOUR-SERVER) and you should be prompted for a password and your OTP. If it fails, it’s likely the clock on your phone and on the server are not in sync. Make them sync with a time server.

Lastly those emergency scratch codes. I haven’t tried it, but I suspect you can generate more by appending them to your ~/.google_authenticator file. It follows this paragraph. As you log in using OTPs it will change - mainly adding times to the relevant lines. Or you can just rerun google-authenticator and create a new OTP key - don’t forget to update the mobile app.


Wrapping Up

Now would be a good time to review the README for the GA PAM project to learn more about the options you have in your /etc/pam.d/sshd entry for the auth required nullok line. From simple things like changing the token prompt (authtok_prompt) to requiring OTP (removing nullok) there are a number of things you can tweak. Just do so carefully.