YubiKey 2FA on Ubuntu SSH

(Jump to the bottom to see the good stuff… Ubuntu Setup Instructions)

Over the last few years, there have been numerous stories in the news about companies and individuals getting hacked. From Sony to the Democratic National Committee, we’ve seen how devastating it can be for intruders to access your private data. To combat these attacks, it is essential to take security serious, both in our corporations as well as our personal lives.

Defense in Depth

In the security industry, there is a saying…

“There are two kinds of companies: The ones who have been hacked and the ones who don’t know it yet”.

There is no silver bullet to protect us, and no matter what, an attacker with unlimited resources and unlimited time will eventually succeed at breaking into our digital fortresses. The only approach to combat this is through defense in depth.

In the same way that we try to protect our homes in the physical world, we need to try and protect our digital assets. For a house, you would install deadbolt locks, get a big mean dog, install a security alarm, build a fence around the property, pay an off duty police officer to patrol the neighborhood, and join a neighborhood watch to work together with your neighbors to prevent crime. Individually, none of these would prevent a burgler from stealing your TV, but combined together, it would maybe make the burgler go to the house next door or the neighborhood down the street for easier targets.

In our digital infrastucture, we need to do the same thing. When setting up a new server or application, we should think of all the ways we can make it a harder target for would be attackers. This would include strong passwords, firewalls, logging, alerting, intrusion detection, role based access control, least privileged user accounts, removing unnecessary services, vulnerability scanning, and patch management (among many others). Additionally, a growing popular method for securing user accounts is to use Two Factor Authentication.

Two Factor Authentication (2FA) has been around for quite a while and boils down to requiring more than one piece of evidence that your are authorized to use a service before you are granted access. These pieces of evidence are routinely decribed as something you know (a password), what you have (a hardware device), and what you are (your fingerprint).

What is a YubiKey

A YubiKey is a popular tool for adding a second factor to authentication schemes. It is a physical USB drive that plugs into your computer and pretends to be a keyboard that types out a One Time Password (OTP) when you physically touch the device. This OTP can then be validated by a 3rd party service, in addition to your password, before authorizing you to log into the service. An attacker would have to hack into your computer to steal your password and also physically steal your YubiKey before they could log into an account as you. This is much safer than only using a password.

Also to note, many 2FA solutions have recently been using a phone number and text message as the second factor. When you log onto a service, it would send you a unique code in a text message for you to enter. By being able to produce this unique code, you can prove that you both have the password to the account and have the phone associated with the account. However, we have recently seen many phone porting attacks where someone uses social engineering to get the phone company to port a targets number to a different phone, thereby enabling them to bypass the 2FA (See here for an example). In fact, this is so easy to do that NIST (National Institute of Standards and Technology) no longer recommends using a phone number as part of a multi factor authentication scheme. Having a physical device that generates one time tokens is much safer than relying on text messaging.

Setting up Yubikey 2FA on AWS Ubuntu

In a recent project, I was charged with setting up some infrastructure on Amazon AWS and wanted to leverage 2FA with YubiKeys. By default, Amazon disables password based SSH access to the servers and instead requires public/private keypairs for authentication. This is more secure than using (often weak) passwords for login and would require an attacker to hack into your machine and get your private key. However, if you enable 2FA with a YubiKey, it would be much more secure and even if an attacker got hold of your private key, they still wouldn’t be able to log onto the server without your YubiKey token.

Our standard device templates are Ubuntu Server 16.04 LTS and requires some manual setup to allow 2FA with YubiKey. Fortunately, YubiKey provides a PAM (Pluggable Authentication Module) library to integrate with Linux. Below are the steps required for getting things up and running:

First, add the PPA and install the library:

$ sudo add-apt-repository ppa:yubico/stable
$ sudo apt-get update
$ sudo apt-get install libpam-yubico

Next, edit the pam settings for SSH.

$ vi /etc/pam.d/sshd

Add the following line at the top to enable the module:

auth sufficient pam_yubico.so id=[Your API Client ID] key=[Your API Client Key] debug authfile=/etc/yubikey_mappings mode=client

The Client ID and Client Key can be generated here for free:

Next, you need to create a mapping file to let the library know which YubiKey devices are associated with which user accounts on the system. The mapping file contains a user account, followed by a colon separated list of keys that are valid. To get the Token ID, you can just grab the first 12 characters of a generated token. The Yubico-Pam website has more details about this step.

For the mapping file, you can either create one mapping file for all users or have a separate mapping file for each user kept in their home directory. For our use case, we went with a combined mapping file (and instructions follow this setup).

Create the mapping file:

$ vi /etc/yubikey_mappings

Add the mappings for each user:

user1:cccccyubikey1:cccccyubikey2
user2:cccccyubikey3

Next, modify the SSH configuration to prompt for the YubiKey token and require both the public key authentication as well as the PAM authentication.

Edit the configuration file:

$ vi /etc/ssh/sshd_config

Enable challenge response authentication by changing this to “yes”.

ChallengeResponseAuthentication yes

Add a new line that sets the Authentication Methods to require first the public key to be valid and then the YubiKey token for each user.

AuthenticationMethods publickey,keyboard-interactive:pam

Finally restart the sshd service to pick up the new settings:

$ service sshd restart

Validating the Configuration

Before testing this out, make sure to keep your existing SSH session alive in case something went wrong. Otherwise you may get locked out of your server.

In another terminal session try to log in without using the key parameter (it should be rejected):

$ ssh user1@my.server.address
Permission denied (publickey).

Next, try again with the key parameter to satisfy the first part of the 2FA, and you should then be able to validate the YubiKey token (the token is not displayed on the terminal window):

$ ssh -i ~/.ssh/my_cert_rsa user1@my.server.address
YubiKey for `user1':
Welcome to Ubuntu 16.04.1 LTS (GNU/Linux 4.4.0-53-generic x86_64)

Above you will see that the certificate was validated and it prompted for the YubiKey. Once the YubiKey is touched, it will automatically type in the One Time Password and continue to the welcome screen. You have now been validated through 2FA.

Wrapping Up

As mentioned earlier, this is not the end-all-be-all of security, but is just another level of defense to protect your environments. Other research and implementation of security hardening and security methods should be investigated and included to make secure as possible while still being usable.

Supporting Links: