18 Feb 2011

Two Factor SSH with Google Authenticator 

By - Security 36 Comments

Last week, Google enabled two factor authentication for everyone. This article explains how to install and configure Google Authenticator in conjunction with SSH for two factor authentication. Two-factor authentication relies on something you know (a password) and something you have (your phone).

Update: I have posted another article describing this same implementation with a Yubikey.

You can use this existing implementation and Google Authenticator application with SSH via an included PAM in the Google Authenticator open source application.

Download the Google Authenticator application

First, download and install Google Authenticator on your Iphone/Android/Blackberry.

Compile, install, configure Google authenticator PAM

You may need a few dependencies. On RHEL 5 I was missing ‘pam-devel’.

$ hg clone https://google-authenticator.googlecode.com/hg/ google-authenticator/
$ cd google-authenticator/libpam/
$ make
$ sudo make install
$ sudo vi /etc/pam.d/sshd

Add the following line to the beginning of /etc/pam.d/sshd:
auth required pam_google_authenticator.so

You also need to update /etc/ssh/sshd_config and add/update:
ChallengeResponseAuthentication yes

Setup your user to require two-factor authentication

As a user, you can now run ‘google-authenticator’. This will generate a secret key, and add a file to your home directory that the newly installed PAM uses.

$ google-authenticator

https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@host.com%3Fsecret%3DAAAAAAAAAAAAAAAA

Your new secret key is: AAAAAAAAAAAAAAAA
Your verification code is 123123
Your emergency scratch codes are:
81283812
18283182
18128381
38383838
18283120

Do you want me to update your "~/.google_authenticator" file (y/n) y

Do you want to disallow multiple uses of the same authentication
token? This restricts you to one login about every 30s, but it increases
your chances to notice or even prevent man-in-the-middle attacks (y/n) y

Note: The emergency scratch codes are one-time use verification codes in the event your phone is unavailable.

Configure this new secret key in Google Authenticator

In your Google Authenticator application on your phone, add this new secret key that was generated in the previous step. Note, a URL is also displayed, that can be scanned from your Google Authenticator application.

Wrapping up the setup

You will now need to restart SSH for the pam/ssh changes to activate.

At this point, you will want to stay logged into the server while you test in another shell.

Testing

Test that two-factor authentication is working.

$ ssh example.com
Verification code:
Password:
[user@host ~]$

Enter the verification code as shown on your phone.

Your SSH sessions are now protected with two factor authentication

Running Linux Servers?

We provide 24×7 monitoring and response, proactive updates, and more. Priced per server, per month. Give us a call at 888-877-7118 or click here for further detail.

36 Responses to “Two Factor SSH with Google Authenticator”

  1. Chris Swan says:

    Can this be made to work in combination with public key login? I’ve given it a try following the steps above, but I’m not being prompted for the OTP.

  2. nwilkens says:

    I don’t think this will work in combination with a public key. PubkeyAuthentication overrides the requirement for the auth PAM methods and would likely require a patch for OpenSSH.

    I may be wrong, and would be interested in hearing if anyone knows how to make this work with PubKeyAuthentication.

  3. K.C. says:

    Works great on Ubuntu Server 10.04 LTS. Required packages “mercurial” (for hg) and “libpam0g-dev” to build the PAM modules.

  4. Brian says:

    I’ve set this up on several Linux workstations and servers, some of which I also use ssh keys with. To my knowledge, the keys overwrite the need for the 2FA, which doesn’t bother me, since I’m more worried about intruders from outside versus intruders from what I consider trusted boxes (which they, themselves, are set up with 2FA, so in theory, barring a security hole, they shouldn’t get access to anyway).

    One of the bugs I’ve encountered (and I don’t know if it’s fixed yet) is that if you have a server and you want to make 2FA optional, the original code would not allow people who didn’t have a .google_authenticator file to log in, even if their password was correct. The issue was/is fixed with the patch found http://code.google.com/p/google-authenticator/issues/detail?id=18

    Also, I had tried this on a server with AFS….after applying the patch, if the user was set up for GA, then they could log in as expected. However, if a user was not set up for GA, they could log in, but wouldn’t receive their AFS token. I don’t know if there’s a workaround for that….

    But, all in all, I love this and have it set up to not only protect ssh, but initial log in and when my screensaver locks on my workstation at work.

  5. Philippe says:

    RCDevs OpenOTP also has a nice interface and full blown server platform with RADIUS, SOAP and PAM and Google Authenticator.
    It works with LDAP acounts. It’s very convenient for a PAM-LDAP + Two-factor with GA.
    Found it here : http://www.rcdevs.com

  6. chukaman says:

    Awesome! I had to make two changes to my sshd_config, from what they were to the following:

    PubkeyAuthentication no
    UsePAM yes

    Once changed it worked perfectly.

  7. dugsong says:

    PAM and pubkey authentication are mutually exclusive in OpenSSH currently. It’s a known issue.

    But here’s how you make two-factor work with pubkeys in SSH anyhow, using Duo’s free service:

    http://blog.duosecurity.com/2011/04/announcing-duos-two-factor-authentication-for-unix/

    Supports phone callback, SMS, one-time passcodes, smartphone push authentication, etc.

  8. jamesdotcuff says:

    hehe great minds think alike :-)

    http://blog.jcuff.net/2011/02/two-factor-for-zero-dollar-love-it-long.html

    I threw together a desktop authenticator for giggles also:

    http://blog.jcuff.net/2011/02/cli-java-based-google-authenticator.html

    Best,

    j.

  9. D says:

    I don’t have a smartphone. Can this be made to work via text message?

  10. mstanislav says:

    You’re able to select if you want to use: SMS; phone call; or application code generation.

  11. pconwell says:

    I know this is a bit older, but it is one of the top Google results, and I wasn’t having luck with your directions. It seems the source has changed.

    However, I found another site (nothing against yours) that solved my problems: http://blog.theroux.ca/security/ubuntu-2-step-authentication-with-google-authenticator/

    Thanks.

  12. Daniel says:

    I get this after cloning the repository:
    $ hg clone https://google-authenticator.googlecode.com/hg/ google-authenticator/
    warning: certificate for google-authenticator.googlecode.com can’t be verified (Python too old)
    requesting all changes
    adding changesets
    adding manifests
    adding file changes
    added 83 changesets with 437 changes to 315 files
    updating to branch default
    abort: No such file or directory

  13. pconwell says:

    Okay, I’m running into problems installing this on Ubuntu 11.04. The other website I linked to only works for 10.04 and I can’t get your instructions to work. Here is my complete build log:


    ~/google-authenticator/libpam$ make
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o google-authenticator.o google-authenticator.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o base32.o base32.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o hmac.o hmac.c
    gcc --std=gnu99 -Wall -O2 -g -fPIC -c -o sha1.o sha1.c
    gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o
    google-authenticator.o: In function `displayQRCode':
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:154: undefined reference to `dlopen'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:166: undefined reference to `dlsym'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:168: undefined reference to `dlsym'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:253: undefined reference to `dlclose'
    /home/pconwell/google-authenticator/libpam/google-authenticator.c:156: undefined reference to `dlopen'
    collect2: ld returned 1 exit status
    make: *** [google-authenticator] Error 1

  14. Evade Flow says:

    Looks like the Makefile isn’t linking with libdl correctly. You could try changing this line:

    google-authenticator: google-authenticator.o base32.o hmac.o sha1.o
    $(CC) -g $(DEF_LDFLAGS) $(shell [ -f /usr/lib/libdl.so ] && \
    echo ” -ldl”) -o $@ $+

    to look like this instead:

    google-authenticator: google-authenticator.o base32.o hmac.o sha1.o
    $(CC) -g $(DEF_LDFLAGS) -ldl -o $@ $+

    That should force it to add ‘-ldl’ to the link.

  15. bla says:

    BTW. There’s also otpasswd / http://otpasswd.thera.be but without an app. It would be cool to see a support for it.

  16. dixdec says:

    sudo apt-get install libpam-google-authenticator

  17. John says:

    Has anyone been able to get this to work with FreeRADIUS for SSL VPN? Is that even possible?

  18. doncalamari says:

    I know pconwell’s problem is over a month old, but in the interest of possibly helping someone else with the same issue, I’ll post what worked for me.

    I got the same error messages in my build and traced it to the fact that I am using a 64-bit version of CentOS. That means the libraries are in a different location. The offending library reference in the Makefile is /usr/lib/libdl.so On my system they are located in /usr/lib64 but yours may be different so try to track down where it is first.

    All I needed to be do was to edit the Makefile and replace any occurrence of /usr/lib/libdl.so with /usr/lib64/libdl.so

    I don’t have the link, but someone has submitted this issue to the Authenticator project as a bug, so hopefully it will be fixed someday soon.

  19. Troy Rose says:

    @pconwell:

    Looks like you’re not linking the binary in with the dynamic linking loader library, libdl.so.*.

    Try modifying the last compile command to include “-ldl”, eg:
    gcc -g -o google-authenticator google-authenticator.o base32.o hmac.o sha1.o -ldl

  20. Srini says:

    To include Two Factor Auth also for users logging in with the Public Key, use the ForceCommand and the following Ruby script.

    https://moocode.com/posts/5-simple-two-factor-ssh-authentication-with-google-authenticator

  21. Tran The Luan says:

    Do you think after Google deploy that apps, they will charge money to us?

    Now they can free, but really don’t know in the future.

    And they can access our server, everybody already thinking that!

    Anyway, it ‘s great, like OTP in Ebanking… HEHEHE!

  22. phy1729 says:

    If you get
    pam_google_authenticator.c:41:34: error: security/pam_modules.h: No such file or directory
    pam_google_authenticator.c:65: error: expected declaration specifiers or ‘…’ before ‘pam_handle_t’

    run
    apt-get install libpam0g-dev

  23. Peter says:

    Works great on Debian Lenny 64.

    libpam0g-dev is installed, too

    Thank you

  24. Jonathan Jekir says:

    Looks like Google Authenticator’s code is now available through git, not mercurial…
    https://code.google.com/p/google-authenticator/source/checkout

  25. Reuqired Files says:

    apt-get install mercurial libpam0g-dev sudo

  26. Stephen says:

    It seems it is included in debian testing as I write this.

    apt-get install libpam-google-authenticator

  27. Jutt says:

    Just another tip this can be applied on the Mac side as well. You just need to move the pam for Google into the proper spot.

    By default it will place it in /usr/lib/

    Move pam_google_authenticator.so into /usr/lib/pam/

    Works great and thats for the article.

  28. idrositis | jdros says:

    I don’t like this google URL that it is being hit during the process. For my test it was:
    https://www.google.com/chart?chs=200×200&chld=M|0&cht=qr&chl=otpauth://totp/user2@usrv%3Fsecret%3D7N5PAQNS44UHKRUO

    So google may keep track of my user-name (user2), my server-name (usrv) and my secret (7N5PAQNS44UHKRUO)…

  29. CoolRaoul says:

    https://google-authenticator.googlecode.com/hg/ gives

    “404. That’s an error.

    The requested URL /hg/ was not found on this server. That’s all we know.”

    so what ?

  30. Henrik Storner says:

    If you dont fancy Google having your userid and secret, then dont use that URL. Instead, enter the secret directly into the google-authenticator application on your smartphone.

  31. Mazon says:

    Made a little hack with Active directory + google authenticator and freeradius.

    https://github.com/Mazon/cyclops

  32. Chris says:

    With regards to the SSH Key issue: I think this is by design and not a bug.
    SSH Key Login already *is* two-factor authentication if done according to best practice:
    1. Something you have – your encrypted SSH privkey
    2. Something you know – the passphrase für said privkey

    Thus, using the same factor again (something you have – totp token) does not increase effective security because you still only have two factors.

    In addition to remote logins via SSH, you can also use the PAM module to protect su. Just insert the line
    auth required pam_google_authenticator.so
    in /etc/pam.d/su
    I don’t think there are repercussions for cron etc., but I might be wrong. It works fine on my test machine, though.
    I didn’t test it, but this should also work for sudo, which is obviously a nice-to-have for Ubuntu users.

  33. portblanc says:

    Don’t you think this kind of auth is very weak because of the emergency scratch codes ?
    How can you prevent a brute force attack on this ?

  34. Ian Chard says:

    This works with the package ‘libpam-google-authenticator’ in the Debian testing repo. All that’s required are the lines in /etc/ssh/sshd_config and /etc/pam.d/sshd, and it just works. If a public key is available then it will be used in preference to the Google Authenticator code.

  35. Matt Rekoske says:

    @portblanc

    There’s an option to enable rate-limiting, which “limits attackers to no more than 3 login attempts every 30s”. That means it would take over 31 years to test all possibilities of the 8 digit backup codes. And you would still have to brute force the SSH password (and the username, since root login should be disabled) as well. You should also have something like fail2ban – http://www.fail2ban.org/ – running on your server.

Leave a Reply