2FA with SSH
Using ssh keys is certainly preferable over traditional passwords. You can use any number of Authenticator apps from Google, Microsoft et cetera to add a second factor. In this example we will use FreeOTP which is is maintained by Red Hat under the Apache 2.0 license, and supports Android and iOS.
The idea here is that if someone has compromised the physical device, such as your laptop, they may be able to ssh into your servers, unless there is a second factor. The second factor in this case, will be your phone. You must have an Android or iOS device with an internet connection to complete this activity. I will also assume that you are sitting on your local computer and will be sshing into a virtual machine for this activity. I will assume that you have already setup ssh keys. If you do not have these please see SSH Keys et al before continuing.
Getting FreeOTP on your phone
Start by installing FreeOTP Authenticator from the Android or iOS store.
- iOS: https://itunes.apple.com/us/app/freeotp-authenticator/id872559395?mt=8
- Android: https://play.google.com/store/apps/details?id=org.fedorahosted.freeotp
Installing the tools on your distro
Install the oath toolkit on your ssh client and server:
sudo apt install oathtool libpam-oath qrencode
pacman -S oath-toolkit qrencode
Configuration on the server
Create your seed with:
head -10 /dev/urandom | sha512sum | cut -b 1-30 >> seed
You should then copy the file seed to /etc/users.oath
cp seed /etc/users.oath
Then edit /etc/users.oath to contain
HOTP/T30/6 user - oethuoenthu----this-is-the-seed-otnehuoetnh
Please ensure that user is changed to your username and you have inserted your seed.
Edit the file /etc/pam.d/sshd on the server and insert the following line at the bottom:
auth sufficient pam_oath.so usersfile=/etc/users.oath window=30 digits=6
Then edit /etc/ssh/sshd_config and ensure that both ChallengeResponseAuthentication and UsePAM options are set:
ChallengeResponseAuthentication yes UsePAM yes AuthenticationMethods publickey,keyboard-interactive PasswordAuthentication no
Also, find the line PermitRootLogin and change to:
You can then generate a basic One time password with the following:
oathtool --totp --verbose $(cat seed)
The number at the end is the one that you can use to log in right now. If you are working with a local machine or a local VM, you can now test your configured functionality. The command to restart the SSH server is found at the bottom of the page. If you have ths capacity then you can test your configuration by sshing and entering that key.
Generating the OPT on your phone
Currently, your configuration is a little odd as you need local access to generate the key for remote access. This defeats the purpose. We want to generate the OTP, as the second factor, on your phone.
What we need is the Base32 value. We can get this value redirected into a file called base32 with the following:
oathtool --totp --verbose $(cat seed) | grep Base | cut -d ' ' -f3 > base32
You can check that it is present with
Using vim, edit base32 to prepend some text such that base32 looks like:
Ensure that Of course change user, machine and thesecretbase32val match your machine.
Run the following to generate a png qrcode for your phone to scan.
qrencode -o root.png $(cat base32)
You should then open the image that you create. I had to transfer my image to a computer with a screen with:
scp root.png user@ipaddress:/path
Obviously changing user, ipaddress and path as needed.
You can then open the image and scan it using the QRcode scanner on your Free OTP mobile app. You should now be able to generate these one time passes on your phone. Note that if FreeOTP crashes while scanning your QRcode, it is probably that your QRcode is wrong.
Be sure to destroy root.png, as leaving it on your laptop will essentially relegate you back to single factor authentication. If you have progressed this far, congratulations! Somebody needs to compromise your computer and your phone to gain access via SSH to your server.
Troubleshooting & Debugging
The most common problems you will experience are mistyping in this lab or not changing some of the values such as user, to values that match your own machine.
On the client side you can use
ssh user@destination -v
On the server side you can look at:
journalctl -u sshd | tail -100
If you use Ubuntu you can use
tail -f /var/log/auth.log
You can restart sshd but should not do so on a live production system unless you are confident that it will come back up.
systemctl restart sshd