Two-Factor authentication

From SciNet Users Documentation
Jump to: navigation, search

Two-Factor authentication using Google-Authenticator is available at all Niagara and Mist login nodes as an option for the user; it is not mandatory.

Users can still login as usual using ssh with either PublicKey or Password authentication.

If a user has already done the Two-Factor setup, he/she will be prompted to enter a “One-Time Code” generated by the Google-Authenticator App installed in his/her phone. If the “One-Time Code” is not valid, access will be denied. This means that after a user does the Two-factor setup, its use becomes mandatory for that specific user.

Setup by the user

After the user has successfully logged in, just need to run this command from the command line:

$ authenticator_setup

The user will be prompted by the following dialog:


You have about to setup your Two-factor authentication.

Please download and install the 'Google Authenticator' app in your
smartphone or tablet (iOS, Android, Blackberry, Windows Phone),
then press 'Enter' to continue or Ctrl-C to exit without setup.


The user just has to follow the prompts. A QR bar code will be displayed. The user just need to scan this code using his/her Google Authenticator App.

Deployment of Two-Factor Authentication:

The rpm with the Google Authenticator PAM modules resides in:


There are two installers:

# ls -l /gpfs/fs1/scinet/authenticator/
total 106
-rw-r--r-- 1 root     root   49540 Aug 16  2017 google-authenticator-1.04-1.el7.ppc64le.rpm
-rw-r--r-- 1 root     root   48892 May 26 13:14 google-authenticator-1.04-1.el7.x86_64.rpm

One is the installer for x86_64 architecture (Niagara) and the other other one is for ppc64le architecture (Mist).

SSHD configuration

This is the content of the file /etc/ssh/sshd_config:

# ssh nia-login03 cat /etc/ssh/sshd_config
Port 22
# order is important 
HostKey /etc/ssh/ssh_host_ed25519_key
HostKey /etc/ssh/ssh_host_rsa_key
KexAlgorithms curve25519-sha256,,diffie-hellman-group18-sha512,diffie-hellman-group16-sha512,diffie-hellman-group-exchange-sha256,diffie-hellman-group14-sha256
SyslogFacility AUTHPRIV
LogLevel INFO
PermitRootLogin without-password
MaxSessions 10
PubkeyAuthentication yes
AuthorizedKeysFile  .ssh/authorized_keys
PasswordAuthentication no
HostbasedAuthentication yes
KbdInteractiveAuthentication yes
ChallengeResponseAuthentication yes
UsePAM yes
X11Forwarding yes
TCPKeepAlive yes
ClientAliveInterval 60
ClientAliveCountMax 60
Subsystem   sftp    /usr/libexec/openssh/sftp-server
MaxStartups 1024
HostbasedAuthentication yes
IgnoreUserKnownHosts yes
IgnoreRhosts yes
AuthenticationMethods publickey,keyboard-interactive keyboard-interactive hostbased
ExposeAuthenticationMethods pam-and-env
Match User root
  AuthenticationMethods publickey

The above configuration is pretty straightforward, except for two keywords, AuthenticationMethods and Match User root

This extract is from the sshd_config man page:

             Specifies the authentication methods that must be successfully completed for a user to be granted access.  This option must be followed by
             one or more comma-separated lists of authentication method names, or by the single string any to indicate the default behaviour of accepting
             any single authentication method.  If the default is overridden, then successful authentication requires completion of every method in at
             least one of these lists.

             For example, "publickey,password publickey,keyboard-interactive" would require the user to complete public key authentication, followed by
             either password or keyboard interactive authentication.  Only methods that are next in one or more lists are offered at each stage, so for
             this example it would not be possible to attempt password or keyboard-interactive authentication before public key.

In our configuration above, the line reads as follows:

AuthenticationMethods publickey,keyboard-interactive keyboard-interactive hostbased

This means that there are three authentication methods: publickey followed by keyboard-interactive, keyboard-interactive and hostbased. If any of these three is successfully completed then the user is granted access.

publickey,keyboard-interactive: publickey verification is performed internally by sshd, if successful, this produces a message “Authenticated with partial success”. Then the next step goes to PAM which will perform a keyboard-interactive verification asking the OTP. IF this second pass is successful, then the user access is granted.

Keyboard-interactive: The authentication is passed to PAM who will ask for a password and the OTP.

Hostbased: It’s similar to publickey. If the keys between hosts are successfully verified, the user access is granted. There is no Two-Factor configured for hostbased authentication, but it could be.

The other keyword is “Match User root”. This keyword is for giving the root the special privilege of not being asked for OTP. We don’t want to lock out the root user. The only authentication method for the root user is publickey; no password (keyboard-interactive) and no OTP. Anyway, the keyword “PermitRootLogin without-password” restricts the root user to use publickey ONLY.

Match User root
  AuthenticationMethods publickey

This section could be used to add others users. If we ever make Two-Factor mandatory, here we can add users which have unattended workflows such as scinet-monitor.

PAM configuration

Thist is the content of the file /etc/pam.d/sshd:

# ssh nia-login03 cat /etc/pam.d/sshd
auth     required
auth  [success=1 default=ignore] quiet /usr/bin/pubkey_used 1>/dev/null 2>&1
auth       substack     password-auth
auth     required secret=/gpfs/fs1/scinet/authenticator/${USER} echo_verification_code [authtok_prompt=One-Time Code: ] nullok
auth       optional
auth       include      postlogin
# Used with polkit to reauthorize users in remote sessions
-auth      optional prepare
account    required
account    include      password-auth
password   include      password-auth
# close should be the first session rule
session    required close
session    required
# open should only be followed by sessions to be executed in the user context
session    required open env_params
session    required
session    optional force revoke
session    include      password-auth
session    include      postlogin
# Used with polkit to reauthorize users in remote sessions
-session   optional prepare

Again here, the above configuration is pretty straightforward, except for two new lines:

auth  [success=1 default=ignore] quiet /usr/bin/pubkey_used 1>/dev/null 2>&1

auth     required secret=/gpfs/fs1/scinet/authenticator/${USER} echo_verification_code [authtok_prompt=One-Time Code: ] nullok

The first line runs a script that verifies if the user has already partially authenticated using publickey. If yes, (success=1), then it will skip the next one line (“auth substack password-auth”); that is what the numbre “1” in success=1 means. In this case, PAM will not run the skipped line so it will ask for password and will go directly to the Google Authenticator line which will ask for the OTP.

The seconds line performs the Google Authenticator verification (OTP).

Setup script

Finally we need this script so the user can do his/her own Two-Factor authentication. It creates the seed file and shows a QR code to the user with the seed:

# This program verifies is the user has setup their key for google_authenticator
# If the user has not setup, the this script forces them to do the setup
# This script by Marco Saldarriaha
# Copyright ® 2018, SciNet - University of Toronto
trap 'exit 1' INT TSTP KILL TERM
export USER=`/usr/bin/id -un`
echo '****************************************************************'
echo "You have about to setup your Two-factor authentication."
echo "Please download and install the 'Google Authenticator' app in your"
echo "smartphone or tablet (iOS, Android, Blackberry, Windows Phone),"
echo "then press 'Enter' to continue or Ctrl-C to exit without setup."
echo '****************************************************************'
read cont < /dev/tty
echo '****************************************************************'
echo "Google Authenticator is going to generate your new secret key."
echo "A lot of output will scroll past, including a large QR code."
echo "At this point, use your authenticator app on your phone to scan"
echo "the QR code OR manually type in the secret key. If the QR code"
echo "is too big to scan, you can use the URL above the QR code to get"
echo "a smaller version. Once it's added, you'll see a six digit code"
echo "that changes every 60 seconds in your app."
echo "If the QR code is too big to see it completely, you may reduce the"
echo "font size of your terminal window and enlarging the window again."
echo "Press 'Enter' to continue or Ctrl-C to exit without setup."
echo '****************************************************************'
read cont < /dev/tty
/usr/bin/google-authenticator -t -d -f -W --rate-limit=3 --rate-time=30 --emergency-codes=7 -s /gpfs/fs1/scinet/authenticator/$USER
echo '****************************************************************'
echo "Make sure you record the secret key, verification code, and the"
echo "emergency scratch codes in a safe place."
echo "Keep your scratch codes in the good old fashion way: in a piece of paper"
echo "in your wallet. Do not keep them in your phone or your computer"
echo "The scratch codes are used when you cannot generate a new One-Time Code."
echo "For example, if you have lost your phone. A scratch code will give you access"
echo "to the system while you recover your phone; scratch codes can be used only once."
echo "Please login again. You will be prompted for the One-Time Code"
echo "after you sucessfully authenticate."
echo "Press 'Enter' to continue"
read cont < /dev/tty
exit 0

"Seed" files

The "seed" files reside in /gpfs/fs1/scinet/authenticator:

# ssh nia-login03 ls -la /gpfs/fs1/scinet/authenticator/
total 123
drwx-wx-wt  2 root     root    4096 Jun 24 11:51 .
drwxr-xr-x 19 root     root    4096 Jun 23 11:26 ..
-r--------  1 dgruner  scinet   173 Jun 22 14:36 dgruner
-r--------  1 mponce   scinet   173 Jun 20 16:36 mponce
-r--------  1 mts      scinet   228 Jun 22 11:34 mts
-r--------  1 northrup scinet   173 Jun 23 16:19 northrup

Note the permissions of the directory and of the files. Users cannot access or list this directory, and a user can only read his/her own file.


Since the login nodes are diskless, the above configuration is performed by a postscript run at boot time in the login node. The location of this postscript is: /install/postscripts/login/2FA_setup.