OpenVPN with dual layer authentication (keys and pam)

Currently, my original 'how-to' on getting OpenVPN running with OpenVPN-GUI used the standard key based authentication. You can configure your client to password protect your connection, but I wasn't comfortable with that scheme. If a laptop is stolen, it would be possible (and not hard to bypass this password). Now, we can add a additional layer with pam and server side interaction.

We still need keys to create the tunnel and send our authentication, so the 'base' security layer is untouched, but now we're going to add pam to authenticate our user. This can be handy if you're creating multiple VPN users, simply removing their system account, will remove their ability to VPN, etc.

To do this (and assuming that we already have a working OpenVPN setup), we will need to make some change to our server config as well as client configs. This how-to is based on a Gentoo, install, so others may have to play with various pam settings to get this to work.

First item is to make sure that OpenVPN is built with pam support. Here are my current USE flags:

[ebuild   R   ] net-misc/openvpn-2.0.6  USE="examples pam ssl threads -iproute2 -minimal -passwordsave (-selinux) -static" 650 kB

With pam added a .so file is compiled and is available on our system. We will need to add this to the server configuration

plugin /usr/lib/openvpn/openvpn-auth-pam.so system-auth

Note: system-auth is needed for Gentoo, this could be login for other linux distros.

Remember to restart OpenVPN and verify the start up was fine by verifying the logs.

/etc/init.d/openvpn restart

Now, pam will look at system users for to authenticate against. But, while I was writing this, I felt that this could be a bit tighter, since any 'valid' user with a password will allow the VPN connection. I thought restricting this to the vpn group might be the best way.

I first created the vpn group

groupadd vpn

Then I added a user to test with

useradd -s /bin/false -g vpn vpntestuser
passwd vpntestuser

To restrict OpenVPN to only allow users in the vpn group, we need to make some changes to the plugin call, but first we need to make a quick adjustment in pam. I copied /etc/pam.d/system-auth to a new file called /etc/pam.d/ovpn. I did this because we're going to be using pam_listfile.so and did not want to taint system-auth with my change, since this would break things like SSH.. not good. pam_listfile.so uses a list to determine access by either group or user, since I don't want to continually add to this list, I felt that group was the way to go.

We need to create the list, and I created mine here:

/etc/security/vpn.group.allowed

This file has one line with a single value

vpn

We now have a group.allowed value, so we need to adjust our /etc/pam.d/ovpn to use this. Here is the copy of my ovpn file:

#%PAM-1.0
auth       required     pam_listfile.so onerr=fail item=group sense=allow file=/etc/security/vpn.group.allowed
auth       required     pam_env.so
auth       sufficient   pam_unix.so try_first_pass likeauth nullok
auth       required     pam_deny.so

account    required     pam_unix.so

# This can be used only if you enabled the cracklib USE flag
password   required     pam_cracklib.so difok=2 minlen=8 dcredit=2 ocredit=2 try_first_pass retry=3
# # This can be used only if you enabled the cracklib USE flag
password   sufficient   pam_unix.so try_first_pass use_authtok nullok md5 shadow
# # This can be used only if you enabled the !cracklib USE flag
# # password   sufficient pam_unix.so try_first_pass nullok md5 shadow
password   required     pam_deny.so
#
session    required     pam_limits.so
session    required     pam_unix.so

As you can see, pam_listfile.so will fail on error, check group and use the file we created. Since we're moving away from system-auth to ovpn, we need to adjust the openvpn.conf with this new value:

plugin /usr/lib/openvpn/openvpn-auth-pam.so ovpn

Again, remember to restart OpenVPN when done.

Ok. We're lookin' good on the server side of things. We need to make a simple change to our client side OpenVPN config. Simple add this single line to your config, and you'll be using a combination of keys and user/pass authentication to connect to your vpn:

auth-user-pass