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!



Dude, nice walk through! But it doesn’t include Ubuntu ;-P
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
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!
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
Jim,
I am really glad I could help you out!
Thanks you for the link back to my site on your blog!
Regards,
David
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,
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,
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
I followed this and i can still login via ssh without being prompted at all for any token information. Am i missing something here?
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!
Worked great, thanks for a great guide.
Glad you liked it! Let me know if you have any other Virtualmin, SSH, Google Authenticator or Security questions!
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?
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?
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?
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?
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!
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!
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?
Did you install “yum –enablerepo=epel install perl-Authen-PAM” ??
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