In this article we are going to look at configuring two factor authentication via PAM using OATH. This is a simple and private way to increase the security of your systems. Even if you are not familiar with the term, it is likely that you have used OATH before. OATH (specifically TOTP) is the rotating 6 digit code that you get from scanning a QR code when setting up 2FA on an account.
This example will show how to configure 2FA for SSH logins to a server, but can easily be generalized to cover other programs or even all authentication on a system. The two factors here will be public key authentication and then the OATH/TOTP code. It is highly recommended that you remain SSHd into your server until after testing to avoid locking yourself out in the event of a configuration error.
Install Packages
You only need to install a single package on the server side.
apt install libpam-oath
On the client machine that will be SSHing to the server install these two packages.
apt install oathtool qrencode
Configure OATH
Create the OATH configuration file /etc/users.oath. This file will contain the OATH secret keys so permissions need to be set to only allow the root user to view it.
touch /etc/users.oath
chown root: /etc/users.oath
chmod 600 /etc/users.oath
Generate a secret key for the TOTP. Treat this secret key as you would your SSH or GPG private key. Anyone who has this key will be able to generate the code needed to authenticate.
openssl rand -hex 10
Now we define the TOTP configuration for our user. If you were setting this up for multiple users you would make one entry per line. Open /etc/users.oath and add this line. user is the username of the account you will SSH into. Replace the long string of numbers and letters with the secret key you just generated.
HOTP/T30/6 user - 00112233445566aabbcc
Configure PAM
Now we need to tell PAM to use OATH to authenticate sshd. Do that by opening /etc/pam.d/sshd and adding the following line to the top of the file.
auth sufficient pam_oath.so usersfile=/etc/users.oath window=30 digits=6
This tells PAM to consider a valid 6 digit code as fully authenticated and to skip any other processing that may normally occur, such as requesting a password.
Configure SSHD
We need to make a few changes to the sshd configuration to allow OATH to work properly. Open the sshd configuration file at /etc/ssh/sshd_config and make the following changes.
AuthenticationMethods publickey,keyboard-interactive
PubkeyAuthentication yes
PasswordAuthentication no
ChallengeResponseAuthentication yes
UsePAM yes
The AuthenticationMethods line specifically tells sshd that a user needs to both have an authorized SSH key and know the proper 6 digit code to login.
Restart sshd to apply the changes
systemctl restart sshd
Test the Changes
From your client ssh into your server as normal. Instead of connecting as you have been, you should now see a prompt for your one time password. You can use oathtool to get the code. Again, replace the long string of numbers and letters with the secret key you generated on the server.
oathtool --totp -d6 00112233445566aabbcc
Enter that 6 digit code into the prompt and you will be logged into your server.
Now, in the unlikely event that your SSH private key is stolen, an attacker still won't be able to access your server!
Managing your TOTP
You probably don't want to run the oathtool command everytime you need your code, and while you could make an alias, that would require storing your secret key in plaintext. Here are some better options.
- pass otp is an extension to the command-line password manager pass for handling TOTP. Use this if you are already using pass
- KeePassXC is a graphical password manager that can manage TOTP
- Gnome Authenticator is a graphical TOTP manager for the GNOME desktop environment
You may also want to generate a QR code for easy setup on another device. Rerun the same oathtool command as before with the -v flag to get the base32 version of your secret key.
oathtool --totp -v -d6 00112233445566aabbcc
--------------------------------
Hex secret: 00112233445566aabbcc
Base32 secret: AAISEM2EKVTKVO6M
Digits: 6
Window size: 0
TOTP mode: SHA1
Step size (seconds): 30
Then use qrencode to generate the QR code image.
qrencode -o totp.png 'otpauth://totp/user@server?secret=AAISEM2EKVTKVO6M'