Two-factor SSH using oathtool on Ubuntu 18.04

July 16, 2018

I've been using the Google Authenticator PAM Module for years. It works great, and is easy to set up. But, I generally try to stay away from all things Google, so I wanted to set up two-factor ssh using something else.

After a bit of googling (…), I found OATH Toolkit. Reading their documentation, it seems rather easy to set up. Also, this blog has a nice TL;DR of the setup. I've pretty much followed that, and added a few bits.

Setting up oathtool

# Install oathtool.
sudo apt install oathtool libpam-oath

export HEX_SECRET=$(head -15 /dev/urandom | sha1sum | cut -b 1-30)

oathtool --verbose --totp $HEX_SECRET --digits=8

# Type in the Base32-secret on your phone

sudo touch /etc/users.oath
sudo chmod 0600 /etc/users.oath

# Running subshell so we can send output to file with sudo-permissions
sudo /bin/bash -c "echo HOTP/T30 $USER - $HEX_SECRET \ >> /etc/users.oath"

# Unset your secret

Setting up an access-list for two-factor

Now, I want to be able to define who I require two-factor for, and from where I require it. I have a couple of hosts that I trust, where I can log in from in case I lose my two-factor.

Create /etc/security/login_token.conf. My file has the following contents:

# Do not require two-factor from here:
+ : dennis :

# lolnope don't need two-factor at all
+ : lolnope : ALL

# Demand two-factor from everywhere and everyone else
- : ALL : ALL

See man 5 access.conf for details on the format (link).

Setting up libpam-oath

Add the following to the top of /etc/pam.d/sshd:

# Exceptions from two-factor
auth    [success=1 default=ignore] accessfile=/etc/security/login_token.conf
# Two-factor
auth required usersfile=/etc/users.oath


Now all we need to do is to enable two-facor in sshd_config. Set ChallengeResponseAuthentication to yes in /etc/ssh/sshd_config. Now we can restart ssh, and test it!


This is what it should look like when logging in:

$ # I use ssh-keys, do I need to auth without them
$ ssh -o PubkeyAuthentication=no dennis@host
One-time password (OATH) for `dennis':

And, when logging in from one of the hosts I've defined in /etc/security/login_token.conf, I'm not asked about the OTP!