Two-Factor Authentication with OTP (Admin Guide)

From HPC Wiki
Admin Guide Two-Factor Authentication with OTP
Jump to navigation Jump to search

The problem

Login to the head nodes of HPC systems is often just secured by simple (user-generated) passwords, which are also often identical for services like e-mail. A second login factor (2FA) is a second authentication factor independent of the password and using a completely different secret. Also, OTP passwords are only used once at each login and created on demand, valid for only minutes or seconds. This makes hacking these accounts difficult for attackers.

About OTP

OTP (one-time-passwords) compute password based on an initial secret (like a private key) and an algorithm. Passwords are computed iteratively, either on demand (at each login) or at specific intervals. The OTP Key is (from a security standpoint) extremely sensitive and must be guarded against theft.

On the server side, oath is needed:

  • oathtool.x86_64 : A command line tool for generating and validating OTPs
  • liboath.x86_64 : Library for OATH handling
  • pam_oath.x86_64 : A PAM module for pluggable login authentication for OATH

On the client-side, software for desktop and mobile devices exist:

The Idea

Just as with passwords, the generation and distribution of the OTP Key need to be secured. We assume that the user has a password set for the system to log into and use the first login of the user to set up the OTP Key for this user and give him the necessary information to log in again later (with password and OTP). Therefore, on the first login, the user is presented some information and then logged out again.

The Setup

After installing oathtool, PAM must be adapted:


auth [success=2 default=ignore] uid = 0                        # skip 2 lines for root
auth [success=1 default=ignore] user notingroup otpusers       # ignore users not yet in otpusers
auth requisite usersfile=/var/security/auth/users.oath window=20     # accept one of 20 consecutive keys 
 (in case clocks of user and server are out of sync)

and /etc/ssh/sshd_config:

ChallengeResponseAuthentication yes
PasswordAuthentication no
UsePAM yes

On first login, a user is not yet a member of group otpusers and is thus not run. The login environment then, through scripts in /etc/profile.d/, generates the OTP Key for the user and puts him/her into the group otpusers and quits:


# RRZK, 2015-12-10 (CO)


/usr/bin/id -Gn ${ME}|/bin/grep ${OTPGROUP} >/dev/null 2>&1

if [ ! ${ME} = "root" ] && [ ${RET} -ne 0 ]; then

# Disable CTRL-C
trap '' 2

/bin/echo -e "

Hello ${ME}

I will generate a TOTP (time based) OATH Secret for you...

# generate secret
/bin/echo "... generating secret"
SECRET=$(/usr/bin/head -10 /dev/urandom | /usr/bin/sha512sum | /bin/cut -b 19-50)

# generate base32 secret 
/bin/echo "... generating base32 secret"
BASE32=$(/usr/bin/oathtool --totp -v ${SECRET}|/bin/grep 'Base32'|/bin/awk '{print $NF}')

# generate qrcode
/bin/echo "... generating qrcode"
/usr/bin/qrencode -l H -v 1 --background=FFFFFF -o ${ME}_oath.png "otpauth://totp/${ME}@${HOST}?secret=${BASE32}"

# insert secret in oath database
/bin/echo "... adding secret to oath database"
/bin/echo "... adding user to otpuser group"

TMPFILE=$(/bin/mktemp ) || exit 1
/bin/echo -e "HOTP/T30/6\t${ME}\t-\t${SECRET}" > $TMPFILE
/usr/bin/sudo -u root /usr/local/sbin/ ${TMPFILE} ${OTPGROUP} ${ME}
/bin/rm -f TMPFILE 

/bin/echo "... finished"
echo "Secret: ${SECRET}
BASE32 Secret:${BASE32}" > ${ME}_oath.dat

/bin/echo " 
Your Secret is: ${SECRET}
Your BASE32 Secret is ${BASE32}
Your QR-Code is: ${ME}_oath.png

Enter your secret in your OTP Token (enter BASE32 without the trailing '=')
Display this file and scan it with your OTP Token APP. (X11Forward only)
/bin/echo "To display your QR-Code, press <d><ENTER>"
read INPUT
if [ "$INPUT" = "d" ]; then
  /usr/bin/display ${ME}_oath.png


The script /usr/local/sbin/

# RRZK, 2015-12-10 (CO)


/bin/cat ${TMPFILE} >> ${OATH_FILE}
/usr/sbin/usermod -a -G ${OTPGROUP} ${USER}
exit 0

called per sudo(!), is then used to put the user in the group otpusers and save the OTP Key in the database file /var/security/auth/users.oath . Of course, an appropriate sudo rule has to be installed, too.

Finishing …

The script puts the OTP Keys (text and image) into the home directory of the user: - ${ME}_oath.dat - ${ME}_oath.png

These files are later removed using cfengine.


First Login

Hello test

I will generate a TOTP (time based) OATH Secret for you...

... generating secret
... generating base32 secret
... generating qrcode
... adding secret to oath database
... adding user to otpuser group
... finished
Your Secret is: c6cc87165150391e272194876ebd9ad4
Your BASE32 Secret is Y3GIOFSRKA4R4JZBSSDW5PM22Q======
Your QR-Code is: test_oath.png

Enter your secret in your OTP Token (enter BASE32 without the trailing '=')
Display this file and scan it with your OTP Token APP. (X11Forward only)

To display your QR-Code, press <d><ENTER>

QR Code

Second Login

The login process then looks like this:

rpabel@soliton:~> ssh
One-time password (OATH) for `rpa': 
Last login: Thu Jul  9 14:07:55 2020 from
[rpa@hermes ~]$


  • For HPC use, the oath.users should be identical for all login nodes. Put it on the /home parallel filesystem?
  • The group otpusers is there to save just one bit of data (user has OTP secret set up or not). With our current user management, local changes are not desirable. It seems the group was chosen because can only check a few details at runtime, like UID & groups of the user.
  • When logging in using SSH Keys, OTP could be skipped. This would encourage users to use SSH Keys…

External links