Better two factor ssh authentication on Ubuntu

In the past, true two factor authentication in ssh has been something of a hack to set up. Now that OpenSSH 6.2 has now been released with full and proper support, the next release of Ubuntu (Saucy Salamander) will include it.

Quick Start

All you have to do is:

  1. apt-get install libpam-google-authenticator.

  2. Users who want to continue using ssh must each run the command google-authenticator. This tool interatively helps you to create the file ~/.google_authenticator, which contains a shared secret and emergency passcodes. It's a terminal application, but it does still display a QR code for quick loading of the shared secret into your two factor device (in my case, this is the Google Authenticator app on my Android smartphone).

  3. Edit /etc/ssh/sshd_config. Set:

    ChallengeResponseAuthentication yes
    PasswordAuthentication no
    AuthenticationMethods publickey,keyboard-interactive
    

    In case you have changed them in the past, you should also check the following two settings (these are both defaults on Ubuntu):

    UsePAM yes
    PubkeyAuthentication yes
    
  4. Run sudo service ssh reload to pick up your changes to /etc/ssh/sshd_config.

  5. Edit /etc/pam.d/sshd and replace the line:

    @include common-auth
    

    with:

    auth required pam_google_authenticator.so
    

That's it! Now ssh logins will require a key, and after your key is verified will additionally require proof that you hold your second factor device.

Your existing ssh session should not be affected by these changes. So before you continue, make sure that you can still access the machine by authenticating with your new two factor system in another session. If you're using shared connections (or aren't sure), be sure to use the -Snone option to ssh in order to make sure that you don't accidentally skip authentication by re-using an existing connection.

How It Works

Traditionally, ssh only verified one thing. That was either your password, or verification that you held your private key, or something else (GSSAPI/Kerberos and other things I won't cover here). Multiple methods were allowed, and success using any one method was considered a successful authentication.

ssh continues to be able to defer to PAM for authentication. However, authentication with an ssh key happens outside PAM, and ssh treats any one of these (key or PAM) as successful. This means that it checks for your password, or that you hold your private key, but not both. This makes it difficult to use a key together with PAM for a second factor, since ssh will just go ahead and never consult PAM for the second factor if your client proves that you hold your key.

With the new feature, AuthenticationMethods can be used to specify two methods that are both required. This means that you can require both ssh key authentication and PAM, and adjust your PAM configuration to be the second factor device in the case of the ssh service.

Why is this more secure?

It's always a good idea to reduce your attack surface, and limit authentication code only to areas designed with security in mind. Previous methods to implement this kind of support involved hacks or patches. With this new support, the only security sensitive code used is PAM and ssh itself, being used as they were designed to be used, and without any third party patches. Both were designed for security from the beginning.

Any catches?

The Google Authenticator PAM module (libpam-google-authenticator) is in universe, which means that it is only community supported for security updates. But this can be changed through the main inclusion process. If this method to implement two factor security in Ubuntu becomes popular, then I'd love to see this happen, and would be happy to drive it.

Variations

This is a clean and flexible mechanism. For example: you can leave /etc/pam.d/sshd alone, and then you'll get a system which requires both a key and the user's password. Or leave the @include common-auth line in place, insert auth required pam_google_authenticator.so before it, and you'll get a system which requires all three: a key, the password and the code from the second factor device.