This page will walk you through setting up two-factor SSH authentication with a Yubico YubiKey on a per-user basis. Although most of the instructions are generally applicable on most systems, the install method and directory paths are FreeBSD specific. For more complex configurations and additional options, see the full documentation of the Yubico PAM module.
/usr/ports/security/openssl) then you MUST also use openssh-portable (/usr/ports/security/openssh-portable) for your SSH connections. The short explanation for this is that the base SSH is linked to the base OpenSSL, but the Yubico PAM module is linked to the ports OpenSSL. This ends up with a crash at runtime which manifests as the Yubikey prompt being presented to you repeatedly. There is currently no other viable solution for this. If you absolutely cannot run anything but the base SSH and ports OpenSSL, or are wondering why the port can't overcome this issue, send me an email and I'll give you the not-so-viable workaround and reasons why this can't easily be dealt with. Thanks to the people who reported and helped with troubleshooting this issue.
You should have an updated copy of the FreeBSD ports tree installed. This is in /usr/ports by default. The official method to download and keep up to date the ports tree as of the writing of this document is with subversion. If you're not sure if you have an updated ports tree, and don't know where to start, something like this will probably get you what you need (as root):
# Make sure we have subversion pkg_add -r subversion # Move the old (if any) ports tree out of the way mv /usr/ports /usr/ports.bak # And finally, check out the new copy svn checkout svn://svn.freebsd.org/ports/head /usr/ports
Now that we have an updated copy of the ports tree, the next step is to install the needed PAM modules (pam_yubico and pam_per_user).
# Install the pam_yubico port and its dependencies cd /usr/ports/security/pam_yubico && make install # and pam_per_user cd /usr/ports/security/pam_per_user && make install
Now on to configuring PAM, which is the system that handles authentication, among other things. I like to keep additions and edits to /usr/local as much as possible, so the first thing we'll do is move our stock sshd PAM file out of the way, and create a /usr/local area for our PAM configuration.
# Move the system version of the sshd PAM file out of the way cp -a /etc/pam.d/sshd /etc/pam.d/sshd.bak # Make our local pam.d directory if it doesn't already exist mkdir -p /usr/local/etc/pam.d # Now move the system version we already backed up to our new 'sshd-default' mv /etc/pam.d/sshd /usr/local/etc/pam.d/sshd-default
sshd-default is what users who are not going to use a YubiKey will default to, as it is exactly like the stock system version they've always used.
/usr/local/etc/pam.d/sshd to replace the /etc/pam.d/sshd that we moved out of the way. It should contain the following contents.
# Route all ssh users through the pam_per_user system auth required /usr/local/lib/security/pam_per_user.so.1Next up, we need to create
/usr/local/etc/pam.d/sshd-yubikey which is the PAM config file for the users we want to authenticate with a YubiKey. Before we do that though, you need to get an API key from Yubico that the pam_yubico module will use to communicate with the Yubico servers when authenticating the OTP. To get an API key, make sure you have your YubiKey handy and go to the Get API Key page. It should give you a Client ID and a Secret key.
/usr/local/etc/pam.d/sshd-yubikey. The file should look like what you see below, making sure you replace CLIENTID and SECRETKEY with your actual Client ID and Secret key that you got from Yubico.
# PAM configuration for the "sshd" service using a YubiKey # auth auth requisite /usr/local/lib/security/pam_yubico.so id=CLIENTID key=SECRETKEY auth required pam_unix.so no_warn try_first_pass # account account required pam_nologin.so account required pam_login_access.so account required pam_unix.so # session session required pam_permit.so # password password required pam_unix.so no_warn try_first_passAnd finally, we need to configure the pam_per_user PAM module, which allows us to specify which users will use the YubiKey auth method, and which will use the normal SSH auth method.
/etc/pam_per_user.map, and populate it with something like the following.
myuser : sshd-yubikey myuser2 : sshd-yubikey * : sshd-defaultThat example says that
myuser and myuser2 will authenticate with their YubiKey, and everyone else will default to the old method. If you want to do something a little more complex, or aren't sure what you need to do, consult the pam_per_user man page.
Now, on to making sure SSH works the way we want. This is pretty quick, all we need to do is edit our /etc/ssh/sshd_config file.
The three settings that we care about and their proper values are
ChallengeResponseAuthentication yesPasswordAuthentication noUsePAM yes# Back up our sshd_config cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.preyubikey # Run sshd_config through sed to change everything we need changed cat /etc/ssh/sshd_config | sed -e 's/^#*ChallengeResponseAuthentication .*/ChallengeResponseAuthentication yes/' -e 's/^#*PasswordAuthentication .*/PasswordAuthentication no/' -e 's/^#*UsePAM .*/UsePAM yes/' > /etc/ssh/sshd_configAnd finally, completely stop and restart the sshd service by running:
/etc/rc.d/sshd stop && /etc/rc.d/sshd start
Finally, we need to configure each user that will authenticate with a YubiKey (all of the users we listed in our /etc/pam_per_user.map). There are two options for this: a system-wide configuration (maintained by the sys admin), or a per-user configuration (done by/as the user).
myuser, not root).
.yubico directory created in the user's home.
mkdir ~myuser/.yubico && chmod 750 ~myuser/.yubicoNow make
~myuser/.yubico/authorized_yubikeys which has the format of user:token, like so:
# In the format of username:tokenID myuser:abcdefghijklAnd finally make sure the permissions are correct.
chmod 640 ~myuser/.yubico/authorized_yubikeys
/usr/local/etc/pam.d/sshd-yubikey and add in an argument that specifies the file we want to use to keep track of our users. We need to add the authfile option to the end of the first auth line, for example:
# PAM configuration for the "sshd" service using a YubiKey # auth auth requisite /usr/local/lib/security/pam_yubico.so id=CLIENTID key=SECRETKEY authfile=/usr/local/etc/yubikey_mappingsNow we will create the file we specified, in this case
/usr/local/etc/yubikey_mappings. It is of the exact same format as the ~myuser/.yubico/authorized_yubikeys file we talked about in the User section above.
# In the format of username:tokenID:tokenID2 myuser:abcdefghijkl joeblow:aaaaabbbbcgd:qwertyuioplk anotheruser:ccccccccjjjj
Now try to connect in and see if it works. You should see something like this.
myuser@remote% ssh [email protected] Yubikey for `myuser': <hit the button on your YubiKey> Password: <type in the password for myuser> [email protected]%
/etc/ssh/sshd_config. The setting is PubkeyAuthentication yes. However, this is usually not a good idea. If you use something that doesn't allow for use of a Yubikey OTP (e.g. an iPhone SSH client), then the user will not be able to connect without the use of their private key.