Google Authenticator implements TOTP (timebased one-time-password) security tokens from RFC6238 via the Google mobile app Google Authenticator. The Authenticator provides a six digit one-time password users must provide in addition to their username and password to login, sometimes branded “two-step authentication”. Here, we install and configure a pluggable authentication module (PAM) which allows login using one-time passcodes.
Download and Install
At the time of this writing, only an old version of libpam-google-authenticator is available in the EPEL package repository. Hence, we are going to compile it from source. First, install prerequisites:
# yum install make gcc pam-devel |
# yum install make gcc pam-devel
TOTP (timebased one-time-password) security tokens are time sensitive. Hence, make sure that your system has ntpd running, and is configured to start the service at boot:
# service ntpd start
Starting ntpd: [ OK ]
# chkconfig ntpd on |
# service ntpd start
Starting ntpd: [ OK ]
# chkconfig ntpd on
Then download and install libpam-google-authenticator from source:
# cd /tmp
# wget http://google-authenticator.googlecode.com/files/libpam-google-authenticator-1.0-source.tar.bz2
# bunzip2 libpam-google-authenticator-1.0-source.tar.bz2
# tar xf libpam-google-authenticator-1.0-source.tar
# cd libpam-google-authenticator-1.0
# make
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o google-authenticator.o google-authenticator.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o base32.o base32.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o hmac.o hmac.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o sha1.o sha1.c
gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o -ldl
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator.o pam_google_authenticator.c
gcc -shared -g -o pam_google_authenticator.so pam_google_authenticator.o base32.o hmac.o sha1.o -lpam
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o demo.o demo.c
gcc -DDEMO --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator_demo.o pam_google_authenticator.c
gcc -g -rdynamic -o demo demo.o pam_google_authenticator_demo.o base32.o hmac.o sha1.o -ldl
gcc -DTESTING --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden \
-o pam_google_authenticator_testing.o pam_google_authenticator.c
gcc -shared -g -o pam_google_authenticator_testing.so pam_google_authenticator_testing.o base32.o hmac.o sha1.o -lpam
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator_unittest.o pam_google_authenticator_unittest.c
gcc -g -rdynamic -o pam_google_authenticator_unittest pam_google_authenticator_unittest.o base32.o hmac.o sha1.o -lc -ldl
# make install
cp pam_google_authenticator.so /lib64/security
cp google-authenticator /usr/local/bin |
# cd /tmp
# wget http://google-authenticator.googlecode.com/files/libpam-google-authenticator-1.0-source.tar.bz2
# bunzip2 libpam-google-authenticator-1.0-source.tar.bz2
# tar xf libpam-google-authenticator-1.0-source.tar
# cd libpam-google-authenticator-1.0
# make
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o google-authenticator.o google-authenticator.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o base32.o base32.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o hmac.o hmac.c
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o sha1.o sha1.c
gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o -ldl
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator.o pam_google_authenticator.c
gcc -shared -g -o pam_google_authenticator.so pam_google_authenticator.o base32.o hmac.o sha1.o -lpam
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o demo.o demo.c
gcc -DDEMO --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator_demo.o pam_google_authenticator.c
gcc -g -rdynamic -o demo demo.o pam_google_authenticator_demo.o base32.o hmac.o sha1.o -ldl
gcc -DTESTING --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden \
-o pam_google_authenticator_testing.o pam_google_authenticator.c
gcc -shared -g -o pam_google_authenticator_testing.so pam_google_authenticator_testing.o base32.o hmac.o sha1.o -lpam
gcc --std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator_unittest.o pam_google_authenticator_unittest.c
gcc -g -rdynamic -o pam_google_authenticator_unittest pam_google_authenticator_unittest.o base32.o hmac.o sha1.o -lc -ldl
# make install
cp pam_google_authenticator.so /lib64/security
cp google-authenticator /usr/local/bin
Set Up Google Authenticator
Before configuring SSH, first set up Google Authenticator. Run “google-authenticator” as the user you wish to log in with via SSH. You will be prompted with a few questions.
Do you want me to update your "~/.google_authenticator" file (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@server%3Fsecret%3DABCD12E3FGHIJKLMN
Your new secret key is: ABCD12E3FGHIJKLMN
Your verification code is 98765432
Your emergency scratch codes are:
01234567
89012345
67890123
45678901
23456789
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y |
Do you want me to update your "~/.google_authenticator" file (y/n) y
https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@server%3Fsecret%3DABCD12E3FGHIJKLMN
Your new secret key is: ABCD12E3FGHIJKLMN
Your verification code is 98765432
Your emergency scratch codes are:
01234567
89012345
67890123
45678901
23456789
Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y
By default, tokens are good for 30 seconds and in order to compensate for
possible time-skew between the client and the server, we allow an extra
token before and after the current time. If you experience problems with poor
time synchronization, you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so (y/n) y
If the computer that you are logging into isn't hardened against brute-force
login attempts, you can enable rate-limiting for the authentication module.
By default, this limits attackers to no more than 3 login attempts every 30s.
Do you want to enable rate-limiting (y/n) y
These settings are stored in the user’s ~/.google_authenticator
file.
Copy and paste the URL into your browser and scan the QR code that is displayed with the app Google Authenticator on your mobile device. If you can’t scan the QR code, then you can enter the information manually with the given secret key and verification code. A new verification code should be displayed every 30 seconds.
Emergency one-time use verification codes are also given for you to write down in a secure place in case you were to not have your mobile device with you.
Configure PAM
Have PAM require Google Authenticator for SSH authentication. Modify /etc/pam.d/sshd
and add the line “auth required pam_google_authenticator.so
” at the top.
#%PAM-1.0
auth required pam_google_authenticator.so
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 |
#%PAM-1.0
auth required pam_google_authenticator.so
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
This will require all users to use Google Authenticator for SSH authentication. To only require those users with Google Authenticator configured for their account (the ~/.google_authenticator
file exists), then instead enter “auth required pam_google_authenticator.so nullok
“.
The order in which you place items in this file matters. Given this configuration, you will first be prompted for your Google Authenticator verification code, then for your system account password when you SSH into the system.
Configure the SSH Service
Modify /etc/ssh/sshd_config
. Verify these settings:
PasswordAuthentication yes
ChallengeResponseAuthentication yes
UsePAM yes |
PasswordAuthentication yes
ChallengeResponseAuthentication yes
UsePAM yes
Restart the SSH service:
When you SSH into the system as a user configured for Google Authenticator, you will have to enter the verification code that is displayed in you Google Authenticator app, and then by your system password at the next prompt:
login as: root
Verification code: 01234567
Password: *******
# |
login as: root
Verification code: 01234567
Password: *******
#
If you have any problems, look in the /var/log/secure
system log file.
If you have SELinux enabled, you may not be able to login, and get this error in /var/log/secure
:
Jan 3 23:42:50 hostname sshd(pam_google_authenticator)[1654]: Failed to update secret file "/home/username/.google_authenticator"
Jan 3 23:42:50 hostname sshd[1652]: error: PAM: Cannot make/remove an entry for the specified session for username from 192.168.0.5 |
Jan 3 23:42:50 hostname sshd(pam_google_authenticator)[1654]: Failed to update secret file "/home/username/.google_authenticator"
Jan 3 23:42:50 hostname sshd[1652]: error: PAM: Cannot make/remove an entry for the specified session for username from 192.168.0.5
This is probably due /home/username/.google_authenticator not having an appropriate Type Enforcement (TE):
# ls -Z /home/username/.google_authenticator
-r--------. username username unconfined_u:object_r:user_home_t:s0 /home/username/.google_authenticator |
# ls -Z /home/username/.google_authenticator
-r--------. username username unconfined_u:object_r:user_home_t:s0 /home/username/.google_authenticator
See here for additional information on this issue.
Skip Google Authenticator Authentication if Logging in from the Local Network
You may trust systems on you local network enough not not require that SSH connections from them use Google Authenticator. If so, modify /etc/pam.d/sshd
so that it looks like this:
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/access-local.conf
auth required pam_google_authenticator.so |
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/access-local.conf
auth required pam_google_authenticator.so
Then add the file /etc/security/access-local.conf
with the contents:
# Google Authenticator can be skipped on local network
+ : ALL : 192.168.0.0/24
+ : ALL : LOCAL
- : ALL : ALL |
# Google Authenticator can be skipped on local network
+ : ALL : 192.168.0.0/24
+ : ALL : LOCAL
- : ALL : ALL
This assumes your local network is subnet 192.168.0.0/24.
My System Configuration
- CentOS 6.5 x86 64-bit
- Google Authenticator libpam 1.0
References