Add Google Authenticator Style 2FA (Two Factor Auth) to FreeBSD SSH

In the current climate we are all concerned with security, so this article will show you how to enforce Google Authenticator style (there are many other apps other than Google’s!) two-factor authentication on FreeBSD servers SSH.

First, we need to install a package which includes the libraries and tools for the authentication:

pkg install oath-toolkit pam_per_user

You could also install this from ports if you prefer ports-based installations.

Next we will create a new token for a user (we’ll call the user twofa):

head -10 /dev/urandom | md5 | cut -b 1-30
oathtool –totp -v <hex code from above cmd>

in the example above, my random hex code was d1ac1a3d57deeefd6b83c3c340feea.

In the output from the oathtool command, the following line shows the code you need to add to your Google Authenticator style app… for me it was:

Base32 secret: 2GWBUPKX33XP224DYPBUB7XK

You can ignore the rest of the output.  If you wanted to use a QR code to scan in your app, this is the text you need to put in your QR generator:

otpauth://totp/<user>@<host>?secret=<base32 secret>

The “<user>@<host>” part of the text is the descriptive name shown in the app and doesn’t need to be in that format, it’s just a useful reminder!

Next we need to add the reference to map this user to this authenticator code.  Using your favourite editor, edit (or create if it’s the first user) the file: /usr/local/etc/users.oath and add:

HOTP/T30/6 <username> – <hex code>

Note: you use the hex code here, not the base32 secret.  For example:

HOTP/T30/6 twofa – d1ac1a3d57deeefd6b83c3c340feea

The “HOTP/T30/6” tells it that we’re using a TOTP code with 30 second rolling window that generates 6 digit codes (this is what Google Authenticator style apps will return to us)

This file needs to be secure, so make sure you set the permissions correctly:

chmod 0600 /usr/local/etc/users.oath

Next, we need to configure the “per-user” PAM module which allows us to selectively choose which users have to use TOTP auth.  Using your favourite editor, create the file: /usr/local/etc/pam_per_user.map and add:

twofa : sshd-oath
* : sshd-default

If you wanted to enforce 2FA for all users, change the last line from sshd-default to sshd-oath.  Again, we want this file to be secure, so set the permissions:

chmod 0600 /usr/local/etc/pam_per_user.map

So now we have the code added to our authenticator app, and the reference added to our config file… all we need to do is tell SSH to enforce it!

First, make a copy of your existing sshd file as the “default” (fallback, non-2FA) option, and also a template for our new “oath” copy:

cp /etc/pam.d/sshd /etc/pam.d/sshd-default
cp /etc/pam.d/sshd /etc/pam.d/sshd-oath

Using your favourite editor, edit the file: /etc/pam.d/sshd and comment out the following lines:

#auth sufficient pam_opie.so no_warn no_fake_prompts
#auth requisite pam_opieaccess.so no_warn allow_local
#auth sufficient pam_krb5.so no_warn try_first_pass
#auth sufficient pam_ssh.so no_warn try_first_pass
#auth required pam_unix.so no_warn try_first_pass

then add the following line after the last “auth” line:

auth required /usr/local/lib/security/pam_per_user.so.1 /usr/local/etc/pam_per_user.map

This tells PAM authentication for SSHD that we need to require a lookup via the per-user module.  Now edit the file: /etc/pam.d/sshd-oath and comment out the following lines:

#auth sufficient pam_opie.so no_warn no_fake_prompts
#auth requisite pam_opieaccess.so no_warn allow_local

then add the following line after the last “auth” line:

auth required /usr/local/lib/security/pam_oath.so usersfile=/usr/local/etc/users.oath

Finally, we have to set a few settings in SSHD so that it can prompt for the code (this isn’t strictly necessary as these are all the default options anyway, but sometimes it is best to enforce them in case they change in future versions)… edit the file /etc/ssh/sshd_config and add the following at the bottom of the file:

ChallengeResponseAuthentication yes
PasswordAuthentication no
UsePAM yes

This enforces the use of PAM which will enforce the use of the per-user and 2FA modules.  Finally we have to restart the SSH service:

service sshd restart

And if we now try to SSH to the server, we will see the following:

% ssh -l twofa 192.0.2.1
Password for twofa@totp-test.local:
One-time password (OATH) for `twofa’:
Password for twofa@totp-test.local:
One-time password (OATH) for `twofa’:
Last login: Mon Nov 6 19:57:56 2017 from test.local

I deliberately entered an invalid code the first time, so it re-prompted for a code.  The second time I entered a valid code from the authenticator and you can see that it allowed us access.

To add a new user token, simply repeat the instructions for generating a hex code, base32 secret and adding to the users.oath file (also add an entry to the pam_per_user.map file unless you set the default to be sshd-oath).  No reload of SSH is needed to add new users.

To change an existing user’s token, do the same as adding a new user except update the existing entry in the file.

There can only be a single entry for each user, so you can’t add multiple tokens for a user.  However, you could add the same token onto multiple authenticator devices.

Every attempt to authenticate a 2FA user will modify the users.oath file.  For example the above modifed the entry in the file to this:

HOTP/T30/6 twofa – d1ac1a3d57deeefd6b83c3c340feea 0 217227 2017-11-06T19:58:12L

The additional parameters are:

  • 0 – The sequence number (this is unused in TOTP, it’s only used for HOTP)
  • 217227 – The last valid 2FA code entered
  • 2017-11-06T19:58:12L – The datestamp of the last valid code entry

Be very careful setting this up for the first time.  I would advise having console access available in case you make a mistake and can’t authenticate!

This should help make your FreeBSD system a little more secure by adding two-factor authentication to SSH logins.  You can also apply this to any PAM-based authentication mechanism but that’s beyond the scope of this article.

For applications, I recommend the Authy app under Android (and perhaps other mobile devices) as it can be used on multiple devices, and migrated between devices easily too.  They also include a desktop version now.

One thought on “Add Google Authenticator Style 2FA (Two Factor Auth) to FreeBSD SSH

  1. dan Post author

    Instead of ‘twofa : sshd-oath’ in the pam_per_user.map file, you could have “GROUP=twofa : sshd-oath” which would cause all members of group “twofa” to need 2fa. This might be easier to manage on a multi-user system 🙂

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *