06 April 2012 ~ 26 Comments

How To: CentOS Two-factor SSH and Virtualmin Authentication via Google-Authenticator

This is my guide to setting up Two-factor SSH and Virtualmin Authentication via Google-Authenticator on CentOS.

What is Google Authenticator
code.google.com/p/google-authenticator/

Overview
The Google Authenticator project includes implementations of one-time passcode generators for several mobile platforms, as well as a pluggable authentication module (PAM)The whole one-time passcode is based on the time of the server and device with the Google-Authentication program installed being in sync. The device and the server will then know what one-time code is correct for a 30 second period, and then it will change. 

The Idea behind using this with SSH and Virtualmin is to greatly increase the security level of your server. You will install the Google-Authentication PAM module on your server and a Google Authenticator application on Android, iPhone or Blackberry phone – you will then be able to use this phone/device 

A couple of warnings. Open two ssh sessions, the reasoning is that if you get this wrong you will lock yourself out of your own system remotely, use the second session to remove or make changes to sshd and pam

So here is what we will do:

1. Install NTP to synchronize the system clock (Very important or nothing will work)

2. Install and setup the Google-Authentication PAM module on your server

3. Setup PAM authentication on the SSH server to work with the Google-Authentication PAM module

4. Setup Virtualmin to work with the Google-Authentication PAM module

So lets get started:

 

1. Install NTP to synchronize the system clock (Very important or nothing will work)

Login via ssh as root user

Type the following command to install ntp

yum install ntp

Turn on service on boot

chkconfig ntpd on

Synchronize the system clock with 0.pool.ntp.org server:

ntpdate pool.ntp.org

Start the NTP service:

/etc/init.d/ntpd start

 

2. Install and setup the Google-Authentication PAM module on your server

Make sure that you have the “EPEL” repo installed so that you will be able to install everything. I normally install it and then disable it, and only –enablerepo it when I need it.

On CentOS 5.x these two commands will be a bit differnent than on CentOS 6.x

If you don’t yet have Python 2.6 installed install it: – this will install in in parallel with python2.4 so as not to break yum

yum --enablerepo=epel install python26

once  installed lets install some dependencies – I have added a couple just in case I need them

yum --enablerepo=epel install gcc gcc++ pam-devel subversion python26-devel

 On Centos 6.x 

You will already have Python 2.6 running so you wont need to install that – lets just install some dependencies in case we need them.

yum --enablerepo=epel install gcc gcc++ pam-devel subversion python-devel


Now we need to download and install git

yum --enablerepo=epel install git

Make a directory for the authenticator

mkdir ./google-authenticator
cd google-authenticator/

Download the SVN for google authenticator

git clone https://code.google.com/p/google-authenticator/

 

Change to to downloaded directory (on mine I also had to cd into libpam) 

cd google-authenticator/libpam/

Run make and make install 

make && make install

If all goes well you should now have the Google-Authentication PAM module on your server

 3. Setup PAM authentication on the SSH server to work with the Google-Authentication PAM module

Now we need to configure Pam auth for SSH

vim /etc/pam.d/sshd

change the file to this – basically adding the “auth required pam_google_authenticator.so” line

#%PAM-1.0
auth required pam_google_authenticator.so
auth include system-auth
account required pam_nologin.so
account include system-auth
password include system-auth
session optional pam_keyinit.so force revoke
session include system-auth
session required pam_loginuid.so

Now we need to edit the ssh daemon configuration file (you can also do this from virtualmin if you like)

vim /etc/ssh/sshd_config 

uncomment

ChallengeResponseAuthentication yes

comment out

#ChallengeResponseAuthentication no

Make sure that

UsePAM yes

To make your system truly secure – you might want to disable PubkeyAuthentication

PubkeyAuthentication no

 

**NOW STOP and make sure that second SSH session is working because you can then edit /etc/ssh/sshd_config & /etc/pam.d/sshd if something goes wrong. Otherwise you are going to need to make these changes on the local console – you would also still be able to edit things from Virtualmin if needed

Restart the SSH daemon

service sshd restart

Then run the google authenticator on the server by running:

google-authenticator

You should see something like

https://www.google.com/chart?chs=200x200&chld=M|0&cht=qr&chl=otpauth://totp/user@server%3Fsecret%3DSAEP64T5VZAVWAFB
Your new secret key is: SAEP64T5VZAVWAFB
Your verification code is 376046
Your emergency scratch codes are:
67868696
26247332
54815527
54336661

Answer each of the question to best suit your needs – I said Yes to everything except the “you can increase the window from its default
size of 1:30min to about 4min. Do you want to do so? ” option

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

In your browser, load the URL noted above; it will show a QRCode that you can scan into your phone using the Google Authenticator application for Android, iPhone or Blackberry. If you already have a Google Authenticator token being generated on your phone, you can add a new one and it will display them both.

Start the appon your phone:

In your phone select time based 

For account use ssh enabled user i.e. root
Account: root@clearosipgoeshere 
Key: SAEP64T5VZAVWAFB

If all is working you should be able to SSH in with the username, then authentication code from your phone/device and then your password. 

** If something does not work, make sure your time on the server and phone has synced and that you have followed the all the steps. You can always change things back in the second SSH window you kept open or via Virtualmin.

Once you are are 100% sure that everything is working with the SSH you can go on to setting it up on Virtualmin.

4. Setup Virtualmin to work with the Google-Authentication PAM module

For PAM authentication to work on Virtualmin you have to make sure you have the “perl-Authen-PAM” module installed.

Install the perl-Authen-PAM module:

yum --enablerepo=epel install perl-Authen-PAM

Then make sure that you have a webmin user setup and the password option set to UNIX Authentication:

You can do that by logging in to Virtualmin

Click on the:

 Webmin >> Webmin >>Webmin Users 

Then click on the user you already set the google-authenticator up for in the SSH section – root in my case.

Change the password to >>  UNIX Authentication

This way the password and google-authenticator code will be the same for the user all around as it authenticates the user via PAM

 

Then edit - /etc/pam.d/webmin in the same way you edited /etc/pam.d/sshd 

vim  /etc/pam.d/webmin

Adding the “auth required pam_google_authenticator.so” line:

#%PAM-1.0
auth required pam_google_authenticator.so
auth required pam_unix.so nullok
account required pam_unix.so
session required pam_unix.so

Since the login process will now prompt for more than just a username and password, you would need to enable “Full PAM conversion” mode in Webmin. This can be done by editing /etc/webmin/miniserv.conf and adding the line pam_conv=1

so edit:

vim /etc/webmin/miniserv.conf

adding to the bottom:

pam_conv=1

 

Now restart the webmin service:

/etc/webmin/restart

You should now be able to login to your Virtualmin and see it asking you for a username, then the verification code and then the password.

Normally if a user Attempts to login with the pam module enabled, it will fail if a secret file for that user is not setup. There is a patch that changes this and causes google_authenticator() to return PAM_IGNORE and not ask for a code if the user has not setup a secret file or if there was an error reading the file. Here is a link to that.

http://code.google.com/p/google-authenticator/issues/detail?id=18

I will update this when I have tried this patch and also when I have set this up on Centos6.

I hope this helps!

If you enjoyed this post, why not leave a comment or consider a Donation as a token of your appreciation. If you need help implementing something you saw on this site or any other project why not Hire Me?

26 Responses to “How To: CentOS Two-factor SSH and Virtualmin Authentication via Google-Authenticator”

  1. johnnyb 19 April 2012 at 1:43 pm Permalink

    Dude, nice walk through! But it doesn’t include Ubuntu ;-P

  2. Miro 9 June 2012 at 11:26 pm Permalink

    So i have tried following this and a few other guides .. and no go .. my server still allows me to just login with only the password.. Although i did keep pubkey on ..

    Would really like to see get implemented .. any help would be great.
    CentOS 6

    feel to ask for more details

    • DieSkim 10 June 2012 at 1:46 am Permalink

      Hi,

      Make sure that you have edited
      vim /etc/pam.d/sshd
      and
      vim /etc/ssh/sshd_config
      as shown – also make sure that you do not have any other ssh files in /etc/pam.d

      Also make sure that you SU to the user you want it to run on and then run the google-authenticator command.

      Let me know if you still cant get it to work!

  3. Jim Ciallella 4 July 2012 at 10:46 pm Permalink

    In case anybody is looking for Webmin + Duo Security integration, here are my install steps for CentOS.

    http://www.orangecoat.com/how-to/duo-security-and-webmin-virtualmin-two-factor-authentication-login-integration

    The above was very helpful in getting this to work in less than an hour.

    Thanks

    • DieSkim 5 July 2012 at 1:51 am Permalink

      Jim,
      I am really glad I could help you out!
      Thanks you for the link back to my site on your blog!
      Regards,
      David

  4. Dominique 5 September 2012 at 1:15 pm Permalink

    I’m trying to get this to work on CentOS6.3 32bit and can’t quite get there.

    I’m only trying to use the SSH part of the guide.

    I have compiled the GIT repository with no issues. I have run and generated a google authenticator secret key for my root user.

    The issue comes when I connect via SSH, basically putty is telling me it will use “keyboard-interactive authentication.” but instead of asking for verification code, it’s asking for password. And anything I enter is rejected.

    I have verified /etc/pam.d/sshd and /etc/ssh/sshd_config multiple times to match what is show in the guide.

    I’ve checked to make sure there were no other “ssh” files in /etc/pam.d/ so no conflict can arise.

    At first I tought it could be some sort of default lock for root accounts. But it doesn’t seem like it.

    This is a clean install of CentOS 6.3 32bit, running on Virtualbox.

    Thanks,

    • Dominique 5 September 2012 at 2:09 pm Permalink

      Ok,

      I’ve looked at some logs, and found this:

      localhost sshd(pam_google_authenticator)[17997]: Failed to read “/root/.google_authenticator”

      After a google search, I ended up here:

      https://bugzilla.redhat.com/show_bug.cgi?format=multiple&id=754978

      From the 2nd post by Daniel I ran the chcon line, and now it all works… seems like a long discussion over there, so I might have to read it to make sure I didn’t render my system unsafe.

      Thanks,

      • DieSkim 7 September 2012 at 1:06 am Permalink

        Hi Dominique,

        I am glad you got this working – but I am not sure that you really needed to run that command.

        Do you have setenforce set to 0 on your server or not?

        Lets me know and then we can take it from there.

        Peace

  5. Brian 16 November 2012 at 8:11 am Permalink

    I followed this and i can still login via ssh without being prompted at all for any token information. Am i missing something here?

    • DieSkim 16 November 2012 at 2:59 pm Permalink

      Hi Brian, I am glad you found my guide on setting up Two-Factor SSH authentication via Google Authentication for Virtualmin and CentOS!

      Have you made sure that
      1. You have added the “auth required pam_google_authenticator.so” line to the top of /etc/pam.d/sshd ?
      2. You have added “ChallengeResponseAuthentication yes” and removed “ChallengeResponseAuthentication no” from /etc/ssh/sshd_config ?
      3. You have restarted SSH
      4. Have you run “google-authenticator” as the user you are trying to add Two Factor Authentication for?

      Let me know if you still need help!

  6. Brian Tobin 22 January 2013 at 7:01 pm Permalink

    Worked great, thanks for a great guide.

    • DieSkim 25 January 2013 at 4:17 pm Permalink

      Glad you liked it! Let me know if you have any other Virtualmin, SSH, Google Authenticator or Security questions!

  7. KKS 28 January 2013 at 6:20 pm Permalink

    Hi,

    I am getting some errors on make command with libpam as below,

    [root@server libpam]# make
    gcc –std=gnu99 -Wall -O2 -g -fPIC -c -fvisibility=hidden -o pam_google_authenticator.o pam_google_authenticator.c
    pam_google_authenticator.c:50:31: error: security/pam_appl.h: No such file or directory
    pam_google_authenticator.c:51:34: error: security/pam_modules.h: No such file or directory
    pam_google_authenticator.c:82: error: expected declaration specifiers or ‘…’ before ‘pam_handle_t’
    pam_google_authenticator.c: In function ‘log_message’:
    pam_google_authenticator.c:85: error: ‘pamh’ undeclared (first use in this function)
    pam_google_authenticator.c:85: error: (Each undeclared identifier is reported only once
    pam_google_authenticator.c:85: error: for each function it appears in.)
    pam_google_authenticator.c:86: warning: implicit declaration of function ‘pam_get_item’
    pam_google_authenticator.c:86: error: ‘PAM_SERVICE’ undeclared (first use in this function)
    pam_google_authenticator.c: At top level:
    pam_google_authenticator.c:113: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:124: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:136: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:263: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:325: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:377: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:414: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:464: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:513: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:540: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:626: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:642: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:763: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:772: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:806: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:862: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:896: error: expected declaration specifiers or ‘…’ before ‘pam_handle_t’
    pam_google_authenticator.c: In function ‘invalidate_timebased_code’:
    pam_google_authenticator.c:899: warning: implicit declaration of function ‘get_cfg_value’
    pam_google_authenticator.c:899: error: ‘pamh’ undeclared (first use in this function)
    pam_google_authenticator.c:899: warning: initialization makes pointer from integer without a cast
    pam_google_authenticator.c:910: warning: implicit declaration of function ‘window_size’
    pam_google_authenticator.c:973: warning: implicit declaration of function ‘set_cfg_value’
    pam_google_authenticator.c: At top level:
    pam_google_authenticator.c:1018: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1148: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1218: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1260: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1292: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1327: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1570: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1573: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1578: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1581: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1586: error: expected ‘)’ before ‘*’ token
    pam_google_authenticator.c:1589: error: expected ‘)’ before ‘*’ token
    make: *** [pam_google_authenticator.o] Error 1
    [root@server libpam]# pwd
    /root/google-authenticator/libpam

    I am running with CentOS 5.9. How can I solve this problem?

    • DieSkim 29 January 2013 at 4:17 pm Permalink

      Hi! It looks like everything did not download when you were downloading the files from Github – have you tried to repeat the process from the beginning? Did any of the steps before this on give errors?

  8. Oli 1 March 2013 at 11:11 am Permalink

    I have just been trying installing this on a Ubuntu system – just the webmin part for now, and keep coming up against this error.
    When I enter the username at the login prompt the log shows this
    #### webmin(pam_google_authenticator)[##]: Did not receive verification code from user
    #### webmin(pam_google_authenticator)[##]: Invalid verification code
    #### USER perl[##]: pam_unix(webmin:auth): authentication failure; logname= uid=0 euid=0 tty= ruser= rhost= user={WEBMINUNIXUSER}

    And then upon typing in the confirmation code I get this
    #### webmin[##]: Non-existent login as unknown from {MY_IP}

    Now this looks to me like at first it is trying to do the whole process with just the username, and then just with the code – and never even getting as far as the password
    Does anyone have any suggestions?

    • Oli 1 March 2013 at 11:23 am Permalink

      Just been carrying out further tests and there seems to als be a more general issue that it is not possible to login in with the default pam file (Before above changes) with pam_conv turned on, in the log it just shows
      webmin[##]: Non-existent login as WEBMINUNIXUSER from IP
      and on the login form it just shows login failed every time, before even entering password – has anyone else seem simmilar issues?

      • DieSkim 2 March 2013 at 2:37 pm Permalink

        Hi Oli, this happens to me some times on one of my servers – all I need to do is restart the Webmin service and then I can log in!

    • DieSkim 2 March 2013 at 2:40 pm Permalink

      Hi!

      I think it could be something to do with you not selecting unix authentication for the user.

      Webmin >> Webmin >>Webmin Users

      Then click on the user you already set the google-authenticator up for in the SSH section – root in my case.

      Change the password to >> UNIX Authentication

      Did you do that? If you are still having problems let me know!

      • Oli 1 May 2013 at 10:30 am Permalink

        Sorry didnt get back for a while, I lost the link to this page and have been busy moving th server to another provider.
        I have the user password set to unix auth & have tried restarting the webmin server multiple times and it still insists on attempting to og in with just the usernme & then just the password – and never even getting to the code request at the moment
        Anyone got any ideas?

        • DieSkim 1 May 2013 at 1:50 pm Permalink

          Did you install “yum –enablerepo=epel install perl-Authen-PAM” ??

      • Oli 1 May 2013 at 11:23 am Permalink

        Out of curiousity & frustration, I tried removing the google auth part in pam and attempting pam_conv with just username & pass nd it looks like this is nothing to do with the two factor auth, just a bug in pam_conv, as it will not let me log in with just username & pass with conversations enabled. I have opened a webmi bug tracker for this and will see what comes up
        https://sourceforge.net/tracker/?func=browse&group_id=17457&atid=117457&artifact_id=3612404
        Oli


Leave a Reply