Tyler's Site

Abstract

I wanted to research MFA methods for SSH connections that did not require a password. Passwords, as many people know, kind of suck. However, authentication is needed for SSH to work properly. How can you authenticate for SSH? Easy an RSA key; and RSA keys are pretty secure, especially if they are encrypted with a password. What if you are wanting more though? You could use a password for the user account as well, but again, passwords suck and we already have one for our RSA key. So what about One Time Passwords (OTPs)? Specifically TOTPs like you would get by using an app like Authy or Google Authenticator. That would be great! This is a guide on how to do just that with FreeBSD 13.2 and OpenSSH 9.3.

Use Case

The use case for this is probably pretty niche. For most people RSA keys (especially encrypted ones) will suffice for security with SSH sessions. People that are in need of more authentication than that likely have standards bodies to comply with; and I do not believe they would consult this blog for advise on how to configure authentication to their machines. However, if MFA with an RSA key and TOTP is interesting to you, here is how I went about doing it.

OpenSSH Server

I have OpenSSH 9.3 installed on the server that has this configuration.Other OpenSSH versions will likely work, however, be mindful in the differences between OpenSSH 9.3 and the version the reader may be using.

Generating Keys

Many people using SSH will already have keys for logging into their servers, however, for the sake of completeness the ssh-keygen command is how one would go about generating key pairs.

$ ssh-keygen -t rsa
> Enter passphrase (empty for no passphrase):
> Enter same passphrase again:

The ssh-keygen command will generate an asymetrical key pair. The default location for these files are ${HOME}/.ssh/ and they will be called id_rsa and id_rsa.pub. The contents of the .pub file will need to go on the remote server the file ${HOME}/.ssh/authorized_keys. This fill is the default file OpenSSH will be looking at to see if a key will authenticate a user to allow a successful login. The id_rsa file will need to be kept safe as it will authenticate to anything that corresponds to the .pub key that was generated with it. Alternatively the id_rsa.pub key can be shared with anyone and everyone; this file contains nothing sensitive.

Please note that while it is possible to not have a password for a key pair, it is a bad idea. The password (or passphrase as ssh-keygen calls it) will encrypt the key so that it cannot be used without knowing the password. It is also worth mentioning that there are other key pairs that ssh-keygen will generate. For more documentation on the utility please reference the ssh-keygen man page.

OpenSSH Server Config

Below is my OpenSSH server config with some comments removed. All of the comments in the config below were added during the time of writing to help explain some options better.

# Forces v2 protocol
Protocol 2
PermitRootLogin no
MaxAuthTries 5
PubkeyAuthentication yes

# Forces public key authentication, then allows for keyboard authentication
# the keyboard authentication needs to be enabled to allow entry of the TOTP
AuthenticationMethods publickey,keyboard-interactive
ChallengeResponseAuthentication yes
KbdInteractiveAuthentication yes
=======
X11Forwarding no
ClientAliveInterval 300
Subsystem       sftp    /usr/libexec/sftp-server

It is always a good idea to keep a backup terminal open to the remote server just in case. If something is configured incorrectly and a backup session is not open then you will have a difficult time getting back into the remote server. Restart the sshd service for the changes to take effect.

$ sudo service sshd restart

and attempt to login to the remote server. Rather than asking for a password from the SSH session, it should prompt for a password for the rsa key pair (you did set a password for that right?) and let you in once the key is unlocked.

Google Authenticator LibPam

The next part is the part that I found a bit more tricky as I am not as good with PAM configuration. However, there are a lot of resources online about it. I used this page from the FreeBSD handbook as a guide to navigate PAM. For a more in-depth guide to PAM Michael W Lucas sells a book about masting PAM. He also has a talk on PAM available here.

Download and install Google Authenticator LibPam

The Github page for Google Authenticator LibPAM is well documented and has a lot more than I am going to cover in this blog post; for further information about configuring this particular module, go there.

Download and install the PAM module.

$ git clone https://github.com/google/google-authenticator-libpam
$ ./bootstrap.sh
$ ./configure
$ make
$ sudo make install

Then configure PAM to use it for sshd. Below is the file located in /etc/pam.d/sshd which handles authentication for OpenSSH server.

auth            required        pam_google_authenticator.so nullok
auth            required        pam_opie.so             no_warn no_fake_prompts
auth            required        pam_opieaccess.so       no_warn allow_local

account         required        pam_nologin.so
account         required        pam_login_access.so

session         required        pam_permit.so

I do not have enough knowledge about PAM to go through this configuration and explain what each line does in depth. For that I am going to defer to the resources outlined at the top of this blog post.

TOTP App

Finally we are ready to set up our TOTP app. Run the command google-authenticator, if you have ‘libqrencode’ installed it will output a QR code that can be scanned on your app. If ‘libqrencoe’ is not installed, you can follow the link or manually enter the secret (scanning the QR code is by far the easiest). Once done you should have MFA setup for SSH sessions on remote machines.

Other Ideas

While logging into a remote machine is great, this blog post could also be modified to do other neat things to reduce or even eliminate passwords. For example, on the machine I set this up on, I also changed PAM’s entry for doas to allow using TOTP instead of typing the password for the user. Doing this could theoretically allow me to disable the user’s password entirely as they would not be using it for anything.