This howto will show you the way to set up OpenVPN to authenticate users against the LinOTP authentication backend. Thus you can bring up your VPN using two factor authentication with different kind of OTP tokens.
If you only have a few users or a few machines and using your smartphone as your token suites you, you should probably take a look at this howto on this site.
But on the other hand if you need to manage several users with different kind of tokens, you should go on reading this howto.
Setting up LinOTP
First you need to set up LinOTP. There are several ways to do this. You can download Debian and Ubuntu packages or you can install the system using the Python Package Index. It provides a good quick start to get the service up and running for demo purposes (check for the latest version).
You might install the LinOTP backend together with the OpenVPN daemon on the same machine to keep things straight and simple.
Configuring PAM for LinOTP
There are different ways to authenticate against LinOTP. You can use the Web API or a RADIUS server, but you can also use a PAM module to authenticate with your OTP tokens.
LinOTP provides a pam_linotp written in C, which is contained in the authentication modules. But we do not want to go through the hassle of compiling the C stuff today and install all the necessary devel packages.
So we turn to another PAM module: pam_py_linotp.
We now are going to install this pam module on the OpenVPN server.
You can download it, unpack it, install it:
tar -ztf pam_py_linotp-0.1.tar.gz
sudo python setup.py install
Alternatively you can use the pip tool to do it much quicker:
sudo pip install pam_py_linotp
or you can just copy the single python module to a given location:
cp src/ pam_linotp.py /lib/security
To use this module you need to install libpam-python.
libpam-python allows you to use the pam_py_linotp.py python module in your PAM stack.
Install libpam-python according to your distribution like:
sudo apt-get install libpam-python
yum install libpam-python
To make the usage more comfortable and to also be able to simply add two factor authentication to your other services like ssh, gdm or kdm, we define a stackable auth file common-linotp:
auth [success=1 default=ignore] pam_python.so /lib/security/pam_linotp.py \ debug url=https://localhost/validate/check auth requisite pam_deny.so auth required pam_permit.so
Please note, the first parameter after the pam_python.so module is the python module, that you installed or copied. And you need to provide a URL, where the LinOTP server is located. If you installed LinOTP on the same machine like OpenVPN is about to run, you can leave this as “localhost”. Otherwise adapt the name or IP address accordingly.
In the URL you also need to adapt the protocol (running LinOTP on https or http) and the port.
We now have a simple file common-linotp, that we can later use to include into our PAM definitions.
Setting up OpenVPN with PAM
On the client machine setup your client configuration client.ovpn like this:
client dev tun proto udp remote your.server.com 1194 resolv-retry infinite nobind persist-key persist-tun ca ca.crt cert client.crt key client.key comp-lzo verb 3 auth-user-pass
Of course you need to adapt the servername and the certificate names.
On your OpenVPN server set up the server.conf like this:
port 1194 proto udp dev tun ca ca.crt cert server.crt key server.key dh dh2048.pem server 192.168.42.0 255.255.255.0 ifconfig-pool-persist ipp.txt keepalive 10 120 comp-lzo persist-key persist-tun status openvpn-status.log verb 3 plugin /usr/lib/openvpn/openvpn-auth-pam.so openvpn
Adapt your certificate names and your IP pool.
Finally we need to edit /etc/pam.d/openvpn which should contain the following lines:
@include common-linotp session sufficient pam_permit.so account sufficient pam_permit.so
The session and the account use pam_permit.so, so that we do not need to create local user accounts for the VPN users on the OpenVPN server.
When the user entered the correct OTP value and optional OTP PIN the VPN is established.
We set up an OpenVPN server to authenticate with OTP tokens managed by LinOTP.
The interesting part is, that we were also using client certificates, so that the VPN only gets established if the machine has the right client certificate and the user has the right OTP token.