How I rolled two factor authentication for ssh access to the server that powers this site.

Update: some details in this post are out of date. I’m not running the same hardware I was when I wrote this now, and converted to systemd.

SSh and two factors (or more) of authentication.

Best practices in IT security dictate that to harden a computer against attacks, one should require a user to enable two-factor authentication. In a two factor authentication scheme, the user who is submitting credentials to a service must submit two different forms of proof they are who they claim to be. (Note that by service, it is most often thought of as a website, but in this case the credentials are to the ssh demon). In my first blog post, we are going to explore possible setups for deploying two factors (or more) of authentication to the ssh demon, such that a user must either provide ssh key, or password. Then they must provide two-factor auth from google authenticator. My current setup is running on a Digital Ocean droplet, and is the cheapest option available (512 mb ram and 1 cpu core and 20 gb ssd storage). I am running Ubuntu 14.04 lts, and have an nginx server setup behind what I am protecting with two-factor auth. It is being used to serve the website you are reading.

Background:

In IT security, two-factor authentication is commonly known as a scheme where you harden a system by ensuring two forms of authentication. Usually you want something you know (password, SSH Key Password) and something you have (SSH key in encrypted form, google authentication codes, biometric thing, Yubikey or smart card). This is what I call the “something you know and something you have” rule. If possible, you need to (either by policy or by technical measures) force the something you have rule. It is hard to do by policy because let’s face it, people are lazy and don’t want to get their phone out to prove the something you have part.

Pre recs

You will need a Linux distribution (any UNIX should work, but I have only tested this on Ubuntu Linux). To keep consistent with what I have, disable root login over ssh, and ensure you have a firewall enabled but allow port 22 (or if you changed the port ssh is served on use that port). I also am using public key auth with an ssh key and a strong ssh key password. I also have sudo privileges on my regular account so that I can upgrade myself to root for any commands or use super user. If you disable root login without enabling sudo privileges for your account you will not be able to use the root account again and you probably don’t want to do that.

Warning:

Keep an extra ssh session open right now before you start. Do not log out of this ssh session or if you break things you may end up trapping yourself out of the server and there will be no idiot switch to enable ssh again. (Have fun using the machines real console). I had two ssh shells running, and logged out of one when I was done, and didn’t log out of that one until I knew things were working properly. Also backup the files I ask you to edit, just in case.

Let’s get started

First things first, (obviously) ssh into your server.

Required packages:

Now, get the packages for google authenticator. I assume you are not running as root and thus use sudo.

$ sudo apt-get install libpam-google-authenticator

Setting it up:

Now, run the google-authenticator command in the context of every user you want to have access to the server. I didn’t use match in the ssh demon file, and therefore, two factor is enabled for all users. There are ways to selectively use two factor for only certain users that I didn’t show. If you need to run google-authenticator as bob and you are logged in as root I think you can use the su command. Up to you to figure out that one. Alternatively, before continuing, make all users of the system run google-authenticator and follow the prompts. Do not continue until all accounts are secured with two factor.

$ google-authenticator

It asks if you want time based codes. I recommend you answer yes.

It asks if you want the config written to your ~ directory. You must answer yes.

Now it will display a qr code (maybe) a secret key, and some rescue codes.

Copy all the rescue codes down somewhere safe. Copy the secret key somewhere safe as well. Note that the rescue codes are your get out of jail free cards. If you lose them and lose your phone with google authenticator on it, you are locked out for good. (In other words, if you lose them change your secret key by running this step again).

Enter the secret key into google authenticator.

IMPORTANT: In order to make the something you have part of two-factor auth work, I really don’t recommend using a two-factor authentication app on the pc you are SSH’ing into. This basically removes the point of two-factor authentication because the something you have is gone. Use a phone or separate PC. Phones are nice because they really are something you have.

Now enter what you wish for these prompts.

When all is done, you should have a  .google_authenticator file in your user directory.

$ ls -a ~ | grep google

If it prints .google_authenticator you should be good to go.

Edit the config files

Use your favorite text editor for this.

$nano /etc/pam.d/sshd

Add this line to the file: For future reference, anything in triple quotes should be added or edited.

“””

auth required pam_google_authenticator.so

“””

One tutorial I saw said to add this to the top, but I added it to the bottom after it failed to work properly. This is just including the shared object (library) for google auth.

Now edit

/etc/ssh/sshd_config

$ nano /etc/ssh/sshd_config

If the ChallengeResponseAuthentication exists, set it to yes. Otherwise, add the appropriate line. Note it may be commented.

“””

ChallengeResponseAuthentication yes

“””

I now added this line to that same file.

“””

Authentication Methods publickey,keyboard-interactive

“””

This sets up a chain of events. If you don’t want to use a public key (I recommend public key crypto over passwords always), then don’t do this, and be aware that if someone logs into the machine with a public key, two factor auth won’t work because it is going to assume that if the user has a public key, they don’t need to enter a password and two factor token.  Log out and try logging back in and see if it worked. If not, you should not log out of the other ssh shell.

Typical chain of events:

  • User Malinda gives her username.
  • SSH shell asks her for public key challenge. Her client provides the appropriate key.
  • Since she is a good and security conscious user of her computer, she is required to type in her ssh key password before the challenge is complete.
  • Now she is asked for her account password. She provides it.
  • The system now asks her for a two factor auth token. She complies.
  • If the two above pieces of information are correct, then she is in. Otherwise, access denied, it asks for password and two factor auth again with no indication of password or auth was wrong.

Other Notes:

If you have a Yubikey, there is a Yubikey module At the Yubikey page. I haven’t played with it because I don’t have a Yubikey.

It is possible to disable password auth altogether so it just requires username>ssh_key>auth_code but I didn’t do that. To do so, see

https://sysconfig.org.uk/two-factor-authentication-with-ssh.html

Also, if you are a company with needs for high security or have multiple (pesky) humans to enforce two factor auth with, you can better enforce the two factors of authentication if you use the Yubikey. This is because it is much harder to install an application to do the second factor of auth. A Yubikey is a physical device and thus is truly something you have.

Enjoy!