I recently got some access to some impressive hardware. I put in on the internet and no joke less then 24 hours someone had already gotten in. Honestly, I did set the ssh password to P@ssw0rd! but still, less then 24 hours? Come on script kiddies, give me at least 24 hours to set up. pppff whatever.

So I decided that I need to lock down my internet facing machines. First, I had to make some changes to the main /etc/ssh/sshd_config file to lock down the machine.

I changed the file to have:

PermitRootLogin no
PasswordAuthentication no

And copied my main id_rsa.pub to the authorized_keys of my user on the box. I enabled sudo for it and now I feel hella safer.

But that isn’t what this post is about, it’s about those times I need to knock on the front door and get access to this machine. So, lets get 2 factor authentication working.

There’s a handful of options and Open Source projects to do 2fa, but I’ve decided to try using the libpam-google-authenticator which you can find the code here.

Before I go any farther, this post is a voltron like walk through from this post, this post, and this post. With out their work I would have never gotten this to work. Thank you.

It seems that every user has to run the authentication software in order to get the keys created, there is a way to use something like Chef or Ansible for automation, but that’ll be at the end of this tutorial. For now lets just get it working with one user (admini).

I have a brand new machine up and running:


First thing first, gotta install the software. I’m on Debian, but you however you install your packages do something like:

admini@debian-template:~$ sudo apt-get update \
    && sudo apt-get install libpam-google-authenticator

Hopefully no errors, so we now have the application installed. Next lets run the application:

admini@debian-template:~$ google-authenticator

Do you want authentication tokens to be time-based (y/n) y
Warning: pasting the following URL into your browser exposes the OTP secret to Google:

[-- A QR CODE --]

Your new secret key is: KQ35JFEFTLDB3TA7QZILK4N7UE
Your verification code is 994945
Your emergency scratch codes are:

Do you want me to update your "/home/admini/.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, 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) 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) y

Now you want to say y to the first one, otherwise the application won’t work. Second question is just good practice you_want the passwords to expire every 30 seconds. Save the emergency scratch codes in a trusted location. If you can’t take a picture of the qr code, then use the secret key and verification code by hand. You should be able to take a picture I’d imagine though. Then the extra questions: you shouldn’t share your tokens so y is a good option. Same with the third and forth questions are just good practice, so answer y on each too.

Congrats! You’ve successfully configured the application. Now lets link it up to ssh.

Now we need to edit the /etc/pam.d/sshd file, you’ll need to be root so sudo su - up to it, or however you get there.

admini@debian-template:~$ sudo su -
root@debian-template:~# vi /etc/pam.d/sshd

Go ahead and add this to the top of the file:

auth required pam_google_authenticator.so

Also comment out, if you don’t want a password check:

#@include common-auth

Write and quit the file and open up:

root@debian-template:~# vi /etc/ssh/sshd_config

Change the following line to:

ChallengeResponseAuthentication yes

And add this to the file:

AuthenticationMethods publickey keyboard-interactive

If you want to be really secure you can add a , between it to make sure that you have BOTH your id_rsa.pub on the account and your 2fa enabled. I’d only do this after you’ve got your publickey on the box otherwise you’ll get errors attempting to reconnect.


AuthenticationMethods publickey,keyboard-interactive

Validate your /etc/ssh/sshd_config via:

root@debian-template:~# sshd -t

If any errors appeared go ahead and fix them NOW. If not, restart sshd!

root@debian-template:~# systemctl reload sshd.service

Go ahead and logout and log in, and you should see something like:

~ > ssh admini@
Verification code:
Linux debian-template 4.19.0-5-amd64 #1 SMP Debian 4.19.37-5 (2019-06-19) x86_64

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Wed Aug  7 19:39:27 2019 from

Congratulations! You now have 2fa working on your machine.


If you would like to automate this with a Chef Cookbook or Ansible playbook, you can!

You can run all the questions via command line, if you run google-authenticator --help you can see all your options:

admini@debian-template:~$ google-authenticator --help
google-authenticator [<options>]
 -h, --help                     Print this message
 -c, --counter-based            Set up counter-based (HOTP) verification
 -t, --time-based               Set up time-based (TOTP) verification
 -d, --disallow-reuse           Disallow reuse of previously used TOTP tokens
 -D, --allow-reuse              Allow reuse of previously used TOTP tokens
 -f, --force                    Write file without first confirming with user
 -l, --label=<label>            Override the default label in "otpauth://" URL
 -i, --issuer=<issuer>          Override the default issuer in "otpauth://" URL
 -q, --quiet                    Quiet mode
 -Q, --qr-mode={NONE,ANSI,UTF8} QRCode output mode
 -r, --rate-limit=N             Limit logins to N per every M seconds
 -R, --rate-time=M              Limit logins to N per every M seconds
 -u, --no-rate-limit            Disable rate-limiting
 -s, --secret=<file>            Specify a non-standard file location
 -S, --step-size=S              Set interval between token refreshes
 -w, --window-size=W            Set window of concurrently valid codes
 -W, --minimal-window           Disable window of concurrently valid codes
 -e, --emergency-codes=N        Number of emergency codes to generate

You’d have to add this for each of your users on the machine, it is possible to automate the setup :) .