Configure Google Authenticator on CentOS 7 – Part 2

Build and Install Google Authenticator

Download the codebase

As I stated in the intro, many of the guides used an outdated codebase from the now defunct Google Code Project Hosting service or they used an RPM repository that I didn’t find completely trustworthy.  To resolve those problems, I decided to just rely on the GitHub repository that is maintained by the Google developer team.

The first step is to download the code.  The GitHub repository for the PAM module is located at:

[root@server ~]# cd /opt[root@server opt]# wget -q

Compile and install

NOTE: as part of the build and install process, I have included a directive to change the base directory that is used for the installation.  The reason for this is due to the need to create two symbolic links.  This will be covered in the next section.

The following are the steps as laid out in the PAM Module Instructions from the wiki:

make install

To anyone that has compiled from source, these are likely to be sufficient, however I have included an abbreviated version of my code snippet for this since it may provide additional information for those that aren’t quite so familiar with the process.

[root@server ~]# cd /opt/google-authenticator-master/libpam/
[root@server libpam]# ./
libtoolize: putting auxiliary files in AC_CONFIG_AUX_DIR, `build'.
libtoolize: copying file `build/'
libtoolize: putting macros in AC_CONFIG_MACRO_DIR, `build'.
libtoolize: copying file `build/libtool.m4'
libtoolize: copying file `build/ltoptions.m4'
libtoolize: copying file `build/ltsugar.m4'
libtoolize: copying file `build/ltversion.m4'
libtoolize: copying file `build/lt~obsolete.m4' installing 'build/config.guess' installing 'build/config.sub' installing 'build/install-sh' installing 'build/missing' installing 'build/depcomp'
parallel-tests: installing 'build/test-driver'

[root@server libpam]# ./configure --prefix=/usr
checking for gcc... gcc
checking whether the C compiler works... yes
checking for C compiler default output file name... a.out
checking for suffix of executables...


google-authenticator version 1.01
Prefix.........: /usr
Debug Build....:
C Compiler.....: gcc -std=gnu99 -g -O2
Linker.........: /bin/ld -m elf_x86_64 -ldl

[root@server libpam]# makemake all-ammake[1]: Entering directory `/opt/google-authenticator-master/libpam'


[root@server libpam]# make installmake[1]: Entering directory `/opt/google-authenticator-master/libpam'
/bin/mkdir -p '/usr/bin'
/bin/sh ./libtool --mode=install /bin/install -c google-authenticator '/usr/bin'
libtool: install: /bin/install -c google-authenticator /usr/bin/google-authenticator
/bin/mkdir -p '/usr/share/doc/google-authenticator'


make[1]: Leaving directory `/opt/google-authenticator-master/libpam'

Configure PAM and SSH

The next two subsections cover the creation of two symbolic links (mentioned in the note in the previous section) and the change to the configuration file for the PAM system governing the SSH daemon.  Additionally, there are a couple of modifications that you might need to perform on the SSH daemon configuration as well, depending on your setup.

Add symlinks to 64bit libraries and module

During my installation, I ran into a situation that was caused by the location used for the installation of the PAM library and object files.  I solved this in two steps:

  1. Change the base location of the file installation
  2. Addition of two symbolic links

The first step was covered in the build process by the addition of a parameter to the call to the configure script:

[root@server libpam]# ./configure --prefix=/usr

The second step was accomplished using the following commands:

[root@server ~]# cd /usr/lib64/security/
[root@server security]# ln -s /usr/lib/security/
[root@server security]# ln -s /usr/lib/security/

As you can see from the following directory listing, this results in two symbolic links pointing back to the installed files in /usr/lib/security.

[root@server security]# pwd
[root@server security]# ls -l `find . -maxdepth 1 -type l -print`
lrwxrwxrwx 1 root root 15 May 11  2018 ./ ->
lrwxrwxrwx 1 root root 11 May 11  2018 ./ ->
lrwxrwxrwx 1 root root 11 May 11  2018 ./ ->
lrwxrwxrwx 1 root root 11 May 11  2018 ./ ->
lrwxrwxrwx 1 root root 11 May 11  2018 ./ ->

Update PAM config file for SSH

After you have the files installed in the correct locations, you need to update the PAM configuration for SSH.  Now, there are a number of ways that you can go about doing this.  I chose to use an inline edit with sed.

NOTE: editing PAM configurations can result in denying access to your system if performed incorrectly.  When editing the SSH PAM configuration file, always do the following:

  1. BACKUP the original file
  2. Make sure you have console access
  3. Open a secondary SSH terminal so that if you screw up you are still logged in
[root@server ~]# cd /etc/pam.d/
[root@server pam.d]# cp -p sshd sshd_backup
[root@server pam.d]# sed -i "2iauth required" sshd

If you would like to use HOTP (counter based) instead of TOTP add the following the end of the text to be inserted using the sed command in the above command example:


Update the SSH configuration

In order to make the SSH part work there are three configuration settings that have to be set in a particular way:

  • PasswordAuthentication
  • UsePAM
  • ChallengeResponseAuthentication

The configuration file is located here:


The desired settings for these are as follows:

PasswordAuthentication yes
UsePAM yes
ChallengeResponseAuthentication yes

The first two are likely already set to be to the desired value, but the third one will need to be changed from “no” to “yes” on a default CentOS 7 install.  To check your settings run the following command and the edit the configuration file if needed:

[root@server ~]# egrep "PasswordAuthentication|UsePAM|ChallengeResponseAuthentication" /etc/ssh/sshd_config | egrep -v "#"
PasswordAuthentication yes
ChallengeResponseAuthentication yes
UsePAM yes

Next you need to restart the SSH daemon so that the changes take effect.  Warning: until you have configured the userland piece (see the next section) your SSH users won’t be able to login. (This includes the root user, but you aren’t logging in remotely as root anyway right?)

Configure userland

This step involves configuring the users to use a TOTP token by running the google-authenticator binary and then answering some questions.  Here is the usage statement for the binary:

 [root@external ~]# google-authenticator -h
google-authenticator [<options>]
 -h, --help                     Print this message
 -c, --counter-based            Set up counter-based (HOTP) verification
 -t, --time-based               Set up time-based (TOTP) verification
 -d, --disallow-reuse           Disallow reuse of previously used TOTP tokens
 -D, --allow-reuse              Allow reuse of previously used TOTP tokens
 -f, --force                    Write file without first confirming with user
 -l, --label=<label>            Override the default label in "otpauth://" URL
 -i, --issuer=<issuer>          Override the default issuer in "otpauth://" URL
 -q, --quiet                    Quiet mode
 -Q, --qr-mode={NONE,ANSI,UTF8} QRCode output mode
 -r, --rate-limit=N             Limit logins to N per every M seconds
 -R, --rate-time=M              Limit logins to N per every M seconds
 -u, --no-rate-limit            Disable rate-limiting
 -s, --secret=<file>            Specify a non-standard file location
 -S, --step-size=S              Set interval between token refreshes
 -w, --window-size=W            Set window of concurrently valid codes
 -W, --minimal-window           Disable window of concurrently valid codes
 -e, --emergency-codes=N        Number of emergency codes to generate

The following snippet shows the command output and answers of run of the google-authenticator binary for a regular user (NOTE: I have removed the actual emergency codes and the secret key, also if your terminal will display it, you may be presented with a QR code to scan.):

[root@server ~]# su - johndoe
[johndoe@server ~]$ google-authenticator
Do you want authentication tokens to be time-based (y/n) y
Your new secret key is: SECRET_KEY_HERE
Your verification code is VERIFY_CODE_HERE
Your emergency scratch codes are:EMER_CODE_HERE
Do you want me to update your "/home/johndoe/.google_authenticator" file? (y/n) y
Do you want to disallow multiple uses of the same authenticationtoken? 
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. 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 +-1min (window size of 3) to about +-4min (window size of
17 acceptable tokens).
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

If you would like to just provide a single command for your users to run to avoid having to tell them the answers as laid out in the above example, use the following:

google-authenticator --time-based --disallow-reuse --window-size=17 --rate-limit=3 --rate-time=30 --force

Extra bits

The following sections detail two useful options.

Whitelist a network

It is possible that you may have a particular network segment, that by it’s very nature is secure enough to not require the additional steps of 2FA.  If this is the case for your installation, here is how you can whitelist a network segment.

  1. Create access control list
  2. Update /etc/pam.d/sshd to use to ACL

The following shows the contents of an ACL that would whitelist the network

[root@server ~]# vi /etc/security/2fa-acl.conf
[root@server ~]# cat /etc/security/2fa-acl.conf
# Allows certain network segments to skip 2FA
+ : ALL :
- : ALL : ALL

Once you have the ACL built add an exclusionary conditional to the SSH PAM configuration file BEFORE the line that was added to activate the module.  For example:

[root@server ~]# sed -i "2iauth [success=1 default=ignore] accessfile=/etc/security/2fa-acl.conf" /etc/pam.d/sshd

Allow unconfigured users

If you have a single user or two it will be easy enough to manage providing the string activate the google-authenticator system for a user, but if you are managing a server with a large number of users, you might want to establish a grace period during which users that have not yet configured their local account to continue to login.

This can be accomplished by adding this parameter to the end of the PAM configuration file line:


If you have already added the line and you just want to easily add the new parameter, then use the following sed command:

[root@server ~]# sed -i '2s/$/ nullok/' /etc/pam.d/sshd


If you encounter login failures during your testing, a good place to start is the content of the following log files:

  • /var/log/secure
  • /var/log/audit/audit.log

Configure Google Authenticator on CentOS 7 – Part 1


As part of the rebuild on my Plex Media Server using CentOS 7, I had intended to configure Google Authenticator but hadn’t gotten around to doing it yet.  As I got into the process recently I discovered that many of the steps that I had used when configuring my CentOS 6 Digital Ocean droplet were out of date to the point of uselessness.

I also discovered that most of the guides that I found either relied on the older 1.0 code release which was also outdated or used a unknown RPM repo.  As such I decided to write up the process that I followed to use the code downloaded from the official GitHub repository.

NOTE: If you are doing this in an enterprise setting, it is likely that your company has particular settings and restrictions that you may need to adhere to (e.g., not running things as the root user). Also, please note that all of my examples use the CentOS defaults unless specifically noted.

Continue reading

Checking your password expiration date (Linux Edition)

While logging into one of the Linux jump boxes at work today, it occurred to me that while I recently got notified about my password expiration from our Active Directory farm, I had no idea when my Linux password would expire or what the password life was.

To find out this information you can easily use the chage command.

Here is what the output looks like:

[user@myserver ~]$ chage -l user
Last password change : Apr 09, 2015
Password expires : Jul 08, 2015
Password inactive : never
Account expires : never
Minimum number of days between password change : 1
Maximum number of days between password change : 90
Number of days of warning before password expires : 7

It may seem like such a simple thing to do, but knowing when your password expires can be a lifesaver on occasion.