Quick Links

If you really want to lock down your cloud server, you can enable two-factor authentication for SSH in the same way you would add it to your Gmail account, preventing anyone from gaining access if they've stolen your SSH private key.

Is This Really Necessary?

Compared to having two factor on an email or web-based account, two factor on SSH isn't as useful. For something like email, the point of failure is usually password reset schemes, easily crackable passwords, or data breaches. Really, anything involving bad passwords or poor password management.

For SSH, this isn't much of an issue. SSH uses very good encryption for the public and private keys it uses to make connections. If your SSH server is locked down and doesn't allow password access, nobody is getting in unless they have the physical device that the key is located on, and it's not very likely that anyone will bruteforce your SSH key anytime this century. So, in a sense, it's almost as if you already have two factor, because your key will remain on your laptop.

But, in some fringe cases, two factor can be a good choice. If some lunatic hacker decides to steal your laptop with the intent of nabbing your SSH keys along with it (and not just selling it on Craigslist when they can't crack your device password), having two factor would put you one step ahead.

A more real-world issue though is with SSH agent forwarding; With agent forwarding turned on, the key requests to sign into additional servers get forwarded back to your device. This allows you to SSH into a public server, and---from that public server---SSH again into another private server on the same network, giving you access similarly to how a VPN would work.

The problem, though, is that if the public server is compromised, if you have agent forwarding enabled, an attacker is able to act as you while you're connected to the public server. This is a potential privilege escalation, depending on how you've set up your network. Two-factor SSH would solve this issue.

Again, this is a very edge case solution, and will probably cause more issues than it prevents, but if you're serious about locking everything down, we'll show you how.

How to Enable Two Factor for SSH

To handle two factor requests, we'll use Google's Pluggable Authentication Module (PAM), which works with Authy and Google Authenticator. Install it from your distro's package manager:

sudo apt-get install libpam-google-authenticator

Then, run this initialization command:

google-authenticator

Answer yes to the first question about having authentication tokens be time based. This is more secure. Your terminal will then be flooded with a gigantic QR code, and you'll likely have to zoom out a bit.

Gigantic QR code.

Open up your authenticator app, and scan your code (not the screenshot). Your app should sync, and start outputting six-digit codes that change every 30 seconds.

You'll also want to make a note of all of the additional output, including the secret key and emergency scratch codes. These are used to gain access again to your server if you are locked out for any reason, though you should be warned that any issues related to misconfiguration can still leave you locked out permanently. We'll turn on two factor optionally for testing before making it mandatory.

For the next questions, answer the following:

  • Answer yes to updating your config, otherwise nothing will work.
  • Answer yes to disallowing multiple uses of each token. They should expire once they are used.
  • Answer no to extending the valid code window, as there isn't really any point to it.
  • Answer yes to allow rate limiting, which will block out attackers after three attempts. Your last three codes will be valid for a minute and a half, so you won't have to worry about locking yourself out by being too slow.

All of your configuration is saved to ~/.google-authenticator. You can copy this file to an additional server to apply the same configuration; don't rerun the initialization tool again, or you'll have to link two seperate devices.

Configure SSH to Work with Google PAM

Open up the PAM configuration file at /etc/pam.d/sshd in your favorite text editor, and add the following line at the very bottom:

auth required pam_google_authenticator.so nullok

The nullok directive means that this is temporary, so two factor will be optional until you change this. Leave it this way for testing. You'll also want to find the line that contains @include common-auth, and comment this out with a #:

# Standard Un*x authentication.
    

#@include common-auth

This turns off password-based authentication, which you don't want.

Next, open up SSH's settings at /etc/ssh/sshd_config. Find the ChallengeResponseAuthentication option, and turn it on:

# Change to yes to enable challenge-response passwords (beware issues with
    

# some PAM modules and threads)

ChallengeResponseAuthentication yes

This enables 2FA, however, SSH keys override 2FA by default, so you'll have to fix that by adding the following line to the end of sshd_config:

AuthenticationMethods publickey,keyboard-interactive

This requires a public key and "keyboard-interactive," which is the prompt that asks you for your two factor code.

SSH is now configured, so you can restart sshd to turn it on these new settings:

sudo systemctl restart sshd.service

This won't close your open connection, so you should do any connection testing in a separate terminal tab. Open a new tab, and try to connect to your server. You should see a prompt asking for a verification code. Enter in one from your phone, and if everything is linked properly, it should work. If it doesn't, you should still be able to access the account by leaving it blank.

If everything works properly, and you've double-checked that there are no issues with signing in, you can remove the "nullok" directive in /etc/pam.d/sshd to make 2FA mandatory.

If you lose access, you can still log in using the emergency codes given to you when you configured PAM, and the secret key should allow you to relink a TOTP app should yours become unlinked for any reason.

Add Access for Service Accounts

If you have a service account that needs to access your server (for example, rsync), you must disable 2FA for that account. This is pretty easy to do; first, we'll want to make a new group to add service accounts to:

sudo groupadd service

Then add the user to that group:

sudo useradd <username>
    

sudo usermod -a -G service <username>

Next, open up the PAM configuration at /etc/pam.d/sshd, and add the following line:

auth [success=done default=ignore] pam_succeed_if.so user ingroup service

Note that this does allow access to your server without the 2FA, but if the user isn't root it may not be a huge deal.