OmniOS: Two-Factor Authentication

Installation of Google Authenticator for more secure logins

This article is part of a series focused on the building and setup of a home-NAS based on ZFS and OmniOS. The index is located here: An OmniOS ZFS Fileserver.

This server has to be accessed via SSH also from the Internet, therefore I needed a safe and practical way to avoid using only a simple password, method vulnerable to key-logging and brute force attacks.

An option could have been the use of private/public keys with password, but this would require me to carry along a USB stick with the private key. I had until recently no USB stick anymore (what for? there is Internet everywhere!), so I checked other solutions.

An option could have been the use of Yubikey, but that is also something to carry along and at risk of loss.
At the end I decided to use two-factor authentication, either with one time passwords (OTP) or with time-dependent one time passwords (TOTP), as Google uses for its services (recently also Facebook, Twitter and Apple introduced similar techniques). I already carry a smartphone with me all the time and it is protected with a proper password, so I consider it secure enough and not an additional burden.

It is worth noting that Google Authenticator is not owned or dependent on Google, it is a software that uses a technique that never contacts Google servers (with one exception, see below).

First I cloned the repository and I compiled it using a recent gcc (version >= 4), ignoring the failed compilation of the test binary. After this I copied the binary PAM to the proper directory. I also made a soft link pointing to it, since the PAM system locks the file and would not give the option to replace it in a live system.

$ mkdir src
$ cd src
$ git clone https://code.google.com/p/google-authenticator/
$ cd src/google-authenticator/libpam/
$ pfexec pkg install developer/build/gnu-make
$ gmake
$ pfexec cp google-authenticator /usr/local/bin/
$ pfexec cp pam_google_authenticator.so /usr/lib/security/pam_google_authenticator.so.1
$ pfexec ln -s /usr/lib/security/pam_google_authenticator.so.1 /usr/lib/security/pam_google_authenticator.so

At this point only the /etc/pam.conf was left.
I checked the standard authentication chain used for SSH logins and I added the line for the new PAM. This way, the additional verification code is requested whenever I use SSH or "other" authentication methods, but not if I login from a real local terminal. This gives me the ability to get into my server to correct mistakes and it won't lower the security anyway: if someone got physical access, no protection is secure anymore.

#
# Default definitions for Authentication management
# Used when service name is not explicitly mentioned for authentication
#
other   auth requisite          pam_authtok_get.so.1
other   auth required           pam_dhkeys.so.1
other   auth required           pam_google_authenticator.so    nullok
other   auth required           pam_unix_cred.so.1
other   auth required           pam_unix_auth.so.1

Now I executed the binary "google-authenticator" that also got compiled and I answered some questions to generate a new initialization code. I am offered the option to use a URL to get a QR code in the browser, suitable for the mobile app. This QR code would be generated by a Google server and if you don't like the idea, simply enter the data manually in the app.

Easy.

Additional information can be found in the README file provided in the repository, or in the help page from the project wiki.

Be sure to check the issue tracker on the project page, to verify nothing serious has been discovered, and be sure to read the support documents to check that my instructions are actually correct.

Update (2014-01-30)

Google Authenticator offers the option to block accesses when it detects a brute-force attack (too many failed attemps in a short time). This protects the account, but also allows DoS (denial of service) to the machine: anyone would be able to lock out of the SSH account even the real owner, since no check of the originating IP is performed.

A better solution would include the addition of other protections, such as fail2ban.

Another element to remember is that by default in OmniOS SSH accepts both "password" authentication and "keyboard interactive" authentication. The first one may be scripted on the client side and may not allow multiple password/code requests, so I modified /etc/ssh/sshd_config by adding or modifying:

PasswordAuthentication no

PermitRootLogin no

KbdInteractiveAuthentication yes

In some guides online different options are suggested: "UsePAM yes" and "ChallengeResponseAuthentication yes", but they are either unsupported or unnecessary.

Since I disabled plaintext password authentication, I may need pubkey authentication in the future for scripting purposes for example, so I want to be sure that pubkey authentication won't expect the verification code (it's already safe enough).

I went to /etc/pam.conf and I commented out the line I introduced earlier, then I added a new block at the end.

Now my pam.conf contains:

#
# Default definitions for Authentication management
# Used when service name is not explicitly mentioned for authentication
#
other   auth requisite          pam_authtok_get.so.1
other   auth required           pam_dhkeys.so.1
# other   auth required           pam_google_authenticator.so    nullok
other   auth required           pam_unix_cred.so.1
other   auth required           pam_unix_auth.so.1

# SSH keyboard interactive, so that keys don't ask for verification code
sshd-kbdint   auth requisite          pam_authtok_get.so.1
sshd-kbdint   auth required           pam_dhkeys.so.1
sshd-kbdint   auth required           pam_google_authenticator.so    nullok
sshd-kbdint   auth required           pam_unix_cred.so.1
sshd-kbdint   auth required           pam_unix_auth.so.1

Be careful and always test every change using a second terminal without logging out of the main one, in case you make mistakes and you cannot get back anymore.

Update 2018-11-22

The PAM module is now available in the PKGSRC repository under the name "google-authenticator".

Author: Olaf Marzocchi

First revision: 2014-01-27.
Last revision: 2018-11-22.