====== Multiple 2fac/MFA Login Options for SSH ======
===== Overview =====
While I generally use ssh keys for logging in to my servers, there is the occasion when I'm not at one of my primary machines and I need to log in to a server. This means I need to fall back to password based authentication and I since I hate having things exposed to the internet that **only** rely on username/password for auth, I long ago added TOTP as a 2nd factor with the Google Authenticator library.
A bit more recently, I setup my servers to accept either TOTP **or** a yubikey for the 2nd factor. In this, I'm going to walk through setting this up for yourself. With this config, when you try to log in via password authentication, you will be prompted for your password as normal, then you'll receive a prompt for a yubikey. You can tap your configured yubikey to then complete the login **or** you can just hit ENTER and you'll receive a prompt for a TOTP token that you can supply from your favorite app (Google Authenticator, Authy, etc.).
===== Some Things to Note =====
There are [[https://developers.yubico.com/yubico-pam/|many ways to configure the yubikey setup]], but I'm going to cover 1 specific way that, at worst, will at least give you ideas for more complex configurations.
You will need to get an API ID and key from [[https://upgrade.yubico.com/getapikey/|yubico]] before you get started. These will be used below.
I'm also assuming that your yubikey is configured such that the token ID is the first 12 characters of your generated token. This is pretty easy to test by just generating a couple of tokens and comparing them. If that's not the case, you will have to get your token ID a different way.
I'll also note that these instructions assume a Debian based system like Ubuntu, in terms of package names. Other distros should have the packages, but they're likely going to be slightly different names.
Without further ado, let's get started.
===== Setting up TOTP =====
We'll start here and add yubikey support after this.
First, you'll need to install the Google Authenticator library.
sudo apt install libpam-google-authenticator
Next, you'll want to create a key and add it to your favorite TOTP app. Using your standard user you want to protect, just run ''google-authenticator''. You'll get a question about "time based tokens" and you should just hit "y", which will then generate a new key and show a qr code in your terminal (make sure it's at least 82 columns wide to view the qr code). Just scan that in your app, give it a name, and then enter a code from the app to verify.
This will generate a file in your home dir at ''~/.google_authenticator'' with your key and some backup codes.
Next, you need to enable this in your pam sshd file:
echo 'auth required pam_google_authenticator.so' | sudo tee -a /etc/pam.d/sshd
You should now be able to test this by forcing password authentication (instead of key based):
ssh -o PubkeyAuthentication=no user@example.com
You should get your password prompt first, and enter your normal password there, then you'll get a prompt for your TOTP token. Enter that and you should be logged in.
===== Adding Yubikey Support =====
This is going to be a little bit more involved. As I noted above, you'll need the following items to get started:
* An API key
* The ID for your API key
* The token ID for your yubikey(s)
You can get your API key and ID [[https://upgrade.yubico.com/getapikey/|here]].
As noted above, most Yubikeys are configured these days such that the 1st 12 characters that are output are your token ID, which, again, is easy to check.
The first thing we're going to do is create the necessary config file in your user's home directory.
mkdir ~/.yubico
# Substitute your username and token id below
echo "$USER:$token_id" > ~/.yubico/authorized_yubikeys
A quick aside before moving on. You can have any number of Yubikeys configured for your user account. Just append the token IDs separated by colons. For example, you would do the following for multiple keys:
echo "$USER:$token_id1:$token_id2:$token_idN" > ~/.yubico/authorized_yubikeys
Next, let's install the pam module.
sudo apt install libpam-yubico
The last bit of config takes us back to our ''/etc/pam.d/sshd'' file. You'll need to open that with your favorite editor and add this line right **BEFORE** the google authenticator line we added above.
auth [success=done new_authtok_reqd=ok default=ignore] pam_yubico.so id=$YOUR_API_KEY_ID key=$YOUR_API_KEY nullok
You'll want to sub in your API key id (should be about 5 digits) and your API key for the variables above.
Again, you can test this with:
ssh -o PubkeyAuthentication=no user@example.com
This time, after your password entry, you should get prompted for a yubikey token. You can either press ENTER with no other input to fall back to TOTP or you can just tap your yubikey to complete your login.
This setup took me a while to perfect, but the end config is pretty simple. I hope this helps other save some time.