CentOS/RHEL 6u5 with Two-Factor Authentication Google Authenticator and SELinux

As already announced on several Social Media Platforms, I got Google Authenticator PAM-module enabled on a Centos(/RHEL) 6u5 box.

This implementation includes:

  • SELinux can run in enforcing mode;

  • Certain IP-ranges or users in certain groups can be excluded from Two-Factor Authentication;

Please note that it does not require the Google Authentication Service, the Google Authenticator is just a PAM module that enables HMAC-Based One-time Password (HOTP) algorithm specified in RFC 4226 and the Time-based One-time Password (TOTP) algorithm specified in RFC 6238, which is license under the Apache License 2.0.

Installing Google Authenticator PAM Module

First step is to install the (additional) required packages; just to be sure they’re there…

# yum -y install git pam-devel

Download and compile the code:

# cd $HOME

# git clone https://code.google.com/p/google-authenticator/

# cd $HOME/google-authenticator/libpam

# make

# make install

Modify /etc/ssh/sshd_config so the following setting is active:

ChallengeResponseAuthentication yes

UsePAM yes

But also disable pubkey authentication, to avoid bypassing 2FA (one of the nice caveats I run into)

PubkeyAuthentication no

Restart the SSH Daemon

# service sshd restart

Change the /etc/pam.d/sshd so it has the following contents (please note that the secret is stored in the $HOME/.ssh folder, this has the correct SELinux Context):

auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/group-2fa.conf
auth required pam_google_authenticator.so secret=${HOME}/.ssh/google_authenticator
auth required pam_sepermit.so
auth include password-auth
account required pam_nologin.so
account include password-auth
password include password-auth
# pam_selinux.so close should be the first session rule
session required pam_selinux.so close
session required pam_loginuid.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session required pam_selinux.so open env_params
session optional pam_keyinit.so force revoke
session include password-auth

Now configure the /etc/security/group-2fa.conf, this file controls who/what are exempted from 2FA:

# This file controls which exemptions are made for
# disabling two factor authentication
# Users that are member of the usergroup no2fa are
# exempted of the requirement providing 2FA
+ : (no2fa) : ALL

# And we also trust the systems from the Subnet
# This subnet also contains hosts that are very secure
+ : ALL :
# Keep this line, to enforce non matching entries
# to enforce 2FA
- : ALL : ALL

Setting up the users

I created two users, one who is member of the no2fa group and one not.

# id pieter
uid=500(pieter) gid=500(pieter) groups=500(pieter)
# id testuser
uid=502(testuser) gid=502(testuser) groups=502(testuser),503(no2fa)

$ ssh [email protected]
Password: ********
Password: ********
Password: ********

As you can see, without luck... /var/log/secure gives you the following errors:

Jun 18 10:11:41 centos-testvm sshd[2896]: error: PAM: Cannot make/remove an entry for the specified session for pieter from workstation.example.com
Jun 18 10:11:41 centos-testvm sshd[2906]: pam_access(sshd:auth): access denied for user `pieter' from `workstation.example.com'
Jun 18 10:11:41 centos-testvm sshd(pam_google_authenticator)[2906]: Failed to read "/home/pieter/.ssh/google_authenticator"
Jun 18 10:11:41 centos-testvm sshd[2898]: Postponed keyboard-interactive for pieter from port 16055 ssh2
Jun 18 10:11:42 centos-testvm sshd[2898]: Connection closed by

This is caused because google-authenticator is not configured yet…

The user testuser can login (which is in the no2fa group): 

$ ssh [email protected]
Password: ******
Last login: Wed Jun 18 09:51:05 2014 from workstation.example.com
[[email protected] ~]$

So now we have to configure google-authenticator for the user pieter.

# sudo su - pieter
$ google-authenticator --label=${USER}@example.com --time-based --disallow-reuse --force
--window-size=6 --rate-limit=3 --rate-time=30 --secret=${HOME}/.ssh/google_authenticator
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/[email protected]%3Fsecret%3DABHNLFFWEOJPPL5QQ
Your new secret key is: DABHNLFFWEOJPPL5QQ
Your verification code is 408011
Your emergency scratch codes are:

Now the user pieter can log in using 2FA:

$ ssh [email protected]
Verification code: [Token]
Password: ********
Last login: Fri Jun 20 11:30:37 2014 from workstation.example.com
[[email protected] ~]$