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
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
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
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
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
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
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
when you do this step and then check logins to confirm you can still
connect. Also you should have ssh public key authentication already
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 pam_google_authenticator.so 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:
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
[...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
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”
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
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
create a new OTP key - don’t forget to update the mobile app.
" WINDOW_SIZE 17
Now would be a good time to review the README for the
project to learn more about the options you have in your
/etc/pam.d/sshd entry for the
auth required pam_google_authenticator.so nullok line.
From simple things like changing the token prompt (
to requiring OTP (removing
nullok) there are a number of things
you can tweak. Just do so carefully.