Two-Factor Authentication

I want additional security for my SSH login exposed to the Internet, specifically Two-Factor Authentication (2FA). Increasingly, websites are being built to support 2FA natively and you can take advantage of 2FA at these sites, but it typically requires you to enable 2FA for those sites only. I want to implement 2FA on my Ubuntu SSH connections use an offering called Google Authenticator. This Google web service is open sources and can be used with a companion smart phone app.

Google Authenticator implements Time-based One-time Password Algorithm (TOTP) security tokens from RFC6238 in mobile apps made by Google. The Authenticator provides a six digit one-time password users must provide in addition to their username and password to log into Google services or other sites. Google Authenticator doesn’t call Google — all the work happens on your SSH server and your phone.

Step 1

To access my home PC from out side my home via SSH, I need to configure port forwarding on your router (external interface) to my home PC's SSH server. I can either use the standard port (22) or any alternative port (something above 1024). (NOTE: For the webserver you will need to set the port forwarding from port 80 on the external interface to your server and maybe port 443 if you want to include SSL/TLS connections.) I did this via the router's configuration page. Many modern routers have presets for configuring several applications, including SSH. If you need to forward the port manually, though, set it so that any incoming connections through port 22 will be routed to the local IP of your home computer.

Also, on some routers, you'll need to configure you home PC with a static IP address, otherwise DHCP could move your assigned IP address around, effectively disabling the forwarding.

Step 2

Download the Google Authenticator app for your Apple or Android device. In my case, I used the Android App.

Step 3

Next you need to install the Google AuthenticatorPAM module. To install the package on Ubuntu, run the following command:

sudo apt-get install libpam-google-authenticator

Now log in as the user you’ll be logging in with remotely and run the comand google-authenticator to create a secret key.

Allow the command to update your Google Authenticator file by typing y. You’ll then be prompted with several questions that will allow you to restrict uses of the same temporary security token, increase the time window that tokens can be used for, and limit allowed acces attempts to hinder brute-force cracking attempts.

Finally, Google Authenticator will present you with a secret key and several “emergency scratch codes.” Write down the emergency scratch codes somewhere safe, they can only be used one time each, and they’re intended for use if you lose your phone.

Step 4

Enter the secret key in the Google Authenticator app on your phone, or you can also use the scan barcode feature (i.e. scan a QR code with your phone’s camera).

Now you’ll now have a constantly changing verification code on your phone. (NOTE: If you want to log in remotely as multiple users, run this command for each user. Each user will have their own secret key and their own codes.)

Step 5

Next you need to activate Google Authenticator on the home PC and require Google Authenticator for SSH logins. You's do this by making modification to the Pluggable Authentication Modules (PAM) for Linux. To do so, open the /etc/pam.d/sshd file on your system and add the following line to the file:

auth required

Next, open the /etc/ssh/sshd_config file, locate the ChallengeResponseAuthentication line, and change it to read as follows:

ChallengeResponseAuthentication yes

(NOTE: If the ChallengeResponseAuthentication line doesn’t already exist, add the above line to the file.)

Finally, restart the SSH server, so your changes will take effect, via ths command:

sudo service ssh restart

Step 6

At this point, when using SSH from my local network, I would need to provide the verification code. I don’t want to enter the verification code on my local network, because I trust my local network. When I SSH from remote, a verification code is required. One way to avoid this is to always login with certificates.

Luckily, there is another way to arrange this using the module This modification will allow skipping two-factor authentication when the connection originates from certain sources. This is natively already supported by PAM. The module can be used to check the source against local subnets:

make sure you have the following in /etc/pam.d/sshd:

# use Google Authenticator
# The ‘nullok’ option tells PAM whenever no config for 2-factor authentication is found,
# it should just ignore it. This will prevent you from being locked out.
auth [success=1 default=ignore] accessfile=/etc/security/access-local.conf
auth required nullok

Add create the file /etc/security/access-local.conf with the following contents:

# skip one-time password if logging in from the local network
# only allow from local IP range
+ : ALL :
- : ALL : ALL

Step 7

Test it out. You’ll be prompted for both your password and Google Authenticator code whenever you attempt to log in via SSH externally. On the other hand, when using SSH on your local network, you should not be required to enter the Google Authenticator code.


Key articles that I found helpful: