OpenVPN with LDAP + 2-Factor Authentication and Network Access Polices

Contents

Introduction

This blog post will explain the steps taken to configure OpenVPN to authenticate users using LDAP authentication and 2-Factor authentication. LDAP authentication will be performed against Active Directory, and 2-Factor authentication will be performed with a Time-based One-Time password (TOTP). Furthermore, the network access of users will be restricted to only what the administrator wants them to access.

This post is split up into 5 sections:

The first section will configure the server on which the VPN server will be setup on. Next, OpenVPN itself will be setup without any authentication. After LDAP authentication will be configured against Active Directory. Then 2-Factor authentication will be added. Lastly, network access polices will be configured for each user.

The first two sections are required in order to have a functioning OpenVPN server, the third section is required in order to have authentication on the OpenVPN server. The fourth section will add additional authentication. And the last section will be used to authorize users to specific services on a network. If you want, you can only work up to the third section if you do not need 2-Factor authentication or network based access polices.

The following picture shows the flow of the whole process.

VPN Server Initial Configuration

In this section the prerequisite server configurations will be performed on the server that will host OpenVPN.

The following versions of software:

  • CentOS 7.6.1810
  • OpenVPN 2.4.7
  • EasyRSA 3.0.6

Begin by updating the server.

1
[user@vpnserver]$ yum update -y

Next disable firewalld. Instead iptables will be used.

1
[user@vpnserver]$ systemctl stop firewalld; systemctl disable firewalld; systemctl mask firewalld

Install the iptables service in order to keep iptables rules on boot.

1
[user@vpnserver]$ yum install iptables-services -y; systemctl start iptables ; systemctl enable iptables 

There are some default iptables rules, clear everything and save them. Configuration of firewall will be done at a later time.

1
[user@vpnserver]$ iptables -F ; iptables-save > /etc/sysconfig/iptables

Install the Fedora extended repository which contains OpenVPN.

1
[user@vpnserver]$ yum install epel-release -y

Install OpenVPN.

1
[user@vpnserver]$ yum install openvpn -y

Install wget for later

1
[user@vpnserver]$ yum install -y wget

Install your favorite text editor, it does not have to be Vim.

1
[user@vpnserver]$ yum install -y vim

Base OpenVPN Configuration

In this section OpenVPN will be configured with a CA and certificate. It will be setup to accept any username and password combination in order to confirm that it is running and operating as it should.

Setting up Certificate and CA for VPN Server

Begin by downloading EasyRSA . This software will be used to create a CA along with key and certificate for the OpenVPN server.

1
2
3
[user@vpnserver]$ cd /etc/openvpn/
[user@vpnserver]$ wget https://github.com/OpenVPN/easy-rsa/releases/download/v3.0.6/EasyRSA-unix-v3.0.6.tgz
[user@vpnserver]$ tar -xf EasyRSA-unix-v3.0.6.tgz ; rm EasyRSA-unix-v3.0.6.tgz

Enter the extracted EasyRSA folder.

1
[user@vpnserver]$ cd /etc/openvpn/EasyRSA-v3.0.6/

Copy the EasyRSA configuration file, and enter it using vim (or another editor).

1
[user@vpnserver]$ cp vars.example vars ; vim vars

Uncomment following lines which will enable the use of RSA with 2048 bits. There is also an option to use elliptic curves.

1
2
3
#set_var EASYRSA_DN             "cn_only"
#set_var EASYRSA_KEY_SIZE       2048
#set_var EASYRSA_ALGO           rsa

Create the CA, VPN key, certificate, and Diffie Hellman parameters.

1
2
3
4
5
6
[user@vpnserver]$ cd /etc/openvpn/EasyRSA-v3.0.6

[user@vpnserver]$ ./easyrsa init-pki
[user@vpnserver]$ ./easyrsa build-ca
[user@vpnserver]$ ./easyrsa build-server-full vpnserver nopass
[user@vpnserver]$ ./easyrsa gen-dh

Copy needed files to root of OpenVPN configuration directory. The files being copied are the CA certificate, Diffie Hellman parameters, VPN server certificate, and VPN server key.

1
2
[user@vpnserver]$ cd /etc/openvpn
[user@vpnserver]$ cp EasyRSA-v3.0.6/pki/{dh.pem,ca.crt} EasyRSA-v3.0.6/pki{/issued/vpnserver.crt,/private/vpnserver.key} .

The following shows all the files that where copied.

1
2
3
4
5
6
[user@vpnserver]$ ls -l *.crt *.key *.pem
-rw-------. 1 root root  818 Jul 10 22:46 ca.crt
-rw-------. 1 root root  245 Jul 10 22:46 dh.pem
-rw-------. 1 root root 3181 Jul 10 22:46 vpnserver.crt
-rw-------. 1 root root  916 Jul 10 22:46 vpnserver.key
[user@vpnserver]$

Creating OpenVPN config

Create file located at /etc/openvpn/server.conf and add the following configurations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
port 1194
proto tcp
dev tun
ca ca.crt
cert vpnserver.crt
key vpnserver.key
dh dh.pem
server 10.8.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
keepalive 10 120
#tls-auth ta.key 0
cipher AES-256-CBC
comp-lzo
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
log-append  openvpn.log
verb 4
remote-cert-eku "TLS Web Client Authentication"
tls-version-min 1.2
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
auth SHA512
reneg-sec 60
plugin /usr/lib64/openvpn/plugins/openvpn-plugin-auth-pam.so openvpn
client-cert-not-required
#client-config-dir /etc/openvpn/ccd
username-as-common-name

## Redirect all traffic to VPN server ##
#push "redirect-gateway def1 bypass-dhcp"
#push "dhcp-option DNS 1.1.1.1"

## Push a specfic route to redirct to VPN server ##
push "route 10.0.0.0 255.255.255.0"

SELinux Issues

NOTE: If you are using SELinux and wish to run OpenVPN on a nonstandard port, it will not let you. If you do not have SELinux, than this section does not apply to you. If you do wish to run on a nonstandard port, please follow the following.

Install policycoreutils-python package and use semanage to see what ports are allowed.

1
2
[user@vpnserver]$ yum install policycoreutils-python -y
[user@vpnserver]$ semanage port -l | grep openvpn_port_t

You can add another port using the following command:

1
[user@vpnserver]$ semanage port -a -t openvpn_port_t -p tcp 1195

Setting up PAM

This section will setup PAM authentication that OpenVPN will use, however, we will not have any actual users or LDAP authentication. This will be to make sure that the VPN server is capable of starting up properly and that the client side can connect.

Create a file /etc/pam.d/openvpn and add the following to it. This allows anyone to authenticate with any credentials.

1
2
auth required pam_permit.so
account sufficient pam_permit.so

Starting OpenVPN

Start OpenVPN

1
[user@vpnserver]$ systemctl start [email protected]

If you encounter any errors, consult /etc/openvpn/openvpn.log.

Testing Client Connection

The following is the client configuration needed to connect to OpenVPN. Create this file on a different computer from the server. Do not forget to replace X.X.X.X with the IP address of your VPN server.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
client
dev tun
proto tcp
remote X.X.X.X 1194
resolv-retry infinite
nobind
user nobody
group nobody
persist-key
persist-tun
ca ca.crt
remote-cert-tls server
#tls-auth ta.key 1
cipher AES-256-CBC
comp-lzo
verb 3
auth SHA512
auth-user-pass

Another component that is needed is the CA certificate located at /etc/openvpn/ca.crt. Copy this file to the client computer in the same directory as the client configuration.

When the OpenVPN client asks you for a username and password, type anything. Any credentials will be accepted, we are doing this to make sure that the OpenVPN server is properly working and that we can connect to it.

If the client can successfully connect to the server then everything is working.

Configuring LDAP Authentication

In this section LDAP authentication will be setup. This authentication will be performed against Active Directory, only users that are apart of a security group named vpngroup will be allowed to authenticate.

Active Directory Setup

As can be seen below there is an OU named MyUsers. Inside we have two users named tim and vpnbind, and a security group named vpngroup.

The vpnbind user account will be used to access LDAP from the VPN server.

1

The tim user account will be our VPN user, this user is apart of the vpngroup security group in order to have vpn access.

2

LDAP Service Setup

Install the LDAP PAM module.

1
[user@vpnserver]$ yum install nss-pam-ldapd -y

Paste the following into /etc/nslcd.conf. This is a deamon that will run in the background, its job is to perform LDAP queries on behalf of another process.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
uid nslcd
gid ldap
uri ldap://10.0.0.10/
base dc=test,dc=net
binddn cn=vpnbind,ou=MyUsers,dc=test,dc=net
bindpw password123!@#
scope sub


base   group  ou=MyUsers,dc=test,dc=net
base   passwd ou=MyUsers,dc=test,dc=net
base   shadow ou=MyUsers,dc=test,dc=net

bind_timelimit 30
timelimit 30

filter passwd (&(objectClass=user)(memberOf=cn=vpngroup,ou=MyUsers,dc=test,dc=net))
map    passwd uid              sAMAccountName

filter shadow (&(objectClass=user)(memberOf=cn=vpngroup,ou=MyUsers,dc=test,dc=net))
map    shadow uid              sAMAccountName


tls_reqcert never

Start the nslcd service.

1
[user@vpnserver]$ systemctl start nslcd

Configure PAM that is used by OpenVPN

Paste following into /etc/pam.d/openvpn. Only the first line is changed from what was before.

1
2
auth required pam_ldap.so
account sufficient pam_permit.so

Testing LDAP Authentication with OpenVPN

Restart OpenVPN server.

1
[user@vpnserver]$ systemctl restart [email protected]

Now use the same client configuration from last time to connect as a domain user. If you are not planning on adding 2-Factor authentication or network access polices, skip here in order to configure VPN network connectivity.

2-Factor Authentication with TOTP

This section will configure TOTP based 2-Factor authentication using Google Authenticator. The Google Authenticator or andOTP mobile application can be used to view the codes.

Begin by installing Google Authenticator.

1
[user@vpnserver]$ yum install google-authenticator

Create a new folder in the root of OpenVPN configuration which will store the shared secret between the server and user.

1
2
[user@vpnserver]$ cd /etc/openvpn
[user@vpnserver]$ mkdir otp

Alter the PAM configuration for OpenVPN in /etc/pam.d/openvpn to include Google Authenticator.

1
2
3
4
auth required pam_google_authenticator.so secret=/etc/openvpn/otp/${USER}.google_authenticator user=root forward_pass
auth required pam_ldap.so use_first_pass

account sufficient pam_permit.so

Create a OTP setting for a user.

1
2
[user@vpnserver]$ google-authenticator --time-based --disallow-reuse --force --rate-limit=3 --rate-time=30 --window-size=3 -l "[email protected]" -s /etc/openvpn/otp/tim.g
oogle_authenticator

After running this command scan QR code with app.

Please note that as the OTP expires the renegotiation time must be set to 0 so the user does not get disconnected, of course this can also be used as a mechanism to timeout the users connection if one wishes.

In order to disable renegotiation set the following in /etc/openvpn/server.conf and user config.

1
reneg-sec 0

SELinux Issues

NOTE: If using SELinux you will have to change the file context of the files in /etc/openvpn/otp. In this example run the following command.

1
2
[user@vpnserver]$ cd /etc/openvpn/otp
[user@vpnserver]$ chcon -u system_u -t openvpn_etc_rw_t tim.google_authenticator

Testing Two Factor Auth

Restart OpenVPN server

1
[user@vpnserver]$ systemctl restart [email protected]

Connect as the client once again. If your domain password is mypassword and your OTP code is 123 456 enter the password as mypassword123456.

Configuring Network Access

Now that the user can successful authenticate and connect to OpenVPN we will configure forwarding and firewall polices so the users can access either the internal network or internet.

Turn on forwarding

1
2
[user@vpnserver]$ echo 'net.ipv4.ip_forward=1'  >> /etc/sysctl.conf
[user@vpnserver]$ sysctl net.ipv4.ip_forward=1

Set up outgoing NAT. Be sure to change the source subnet to what was set in the OpenVPN server configuration.

1
[user@vpnserver]$ iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE

At this point any user that connects will be able to connect to the local LAN network that the VPN server is on. A small configration change must be made in order to redirect all the traffic of the client through the VPN server.

Don’t forget to save the iptables rules:

1
[user@vpnserver]$ iptables-save > /etc/sysconfig/iptables

In /etc/openvpn/server.conf comment out the following:

1
push "route 10.0.0.0 255.255.255.0"

And uncomment the following:

1
2
#push "redirect-gateway def1 bypass-dhcp"
#push "dhcp-option DNS 1.1.1.1"

Now restart the VPN Server

1
[user@vpnserver]$ systemctl restart [email protected]

User Based Network Access Polices

In order to regulate the network activity of each user iptables will be used. The issue is that we cannot predict which IP address a user will receive. In order to combat this a static IP address will be given to each user.

As our tunnel network we are using 10.8.0.0/24, we will split this into two subnets. One subnet will be for Administrators and the other for users.

User Type Subnet
Admins 10.8.0.0/25
Users 10.8.0.128/25

Furthermore, in this example we will have the following users.

Username Static IP
Tim 10.8.0.100/25
Bob 10.8.0.200/25

Assigning Static IP address

Create the client configuration directory

1
2
[user@vpnserver]$ cd /etc/openvpn
[user@vpnserver]$ mkdir ccd

Now we will create two files in /etc/openvpn/ccd

Add the following into the file /etc/openvpn/ccd/tim.

1
ifconfig-push 10.8.0.100 10.8.0.1

Add the following into the file /etc/openvpn/ccd/bob.

1
ifconfig-push 10.8.0.200 10.8.0.1

Also make sure to uncomment or add the following line in /etc/openvpn/server.conf.

1
client-config-dir /etc/openvpn/ccd

Now restart the VPN and each user should be getting a static ip on connect

1
[user@vpnserver]$ systemctl restart [email protected]

Firewall Polices

The following iptables configuration will create two chains, ADMINS and USERS. When an IP address falls into a specific subnet it will be sent to the corresponding chain. Any rules you wish to enforce on the users can be added into the chains.

1
2
3
4
5
6
iptables -N ADMINS
iptables -N USERS
iptables -P FORWARD DROP
iptables -A FORWARD -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
iptables -A FORWARD -i tun+ -s 10.8.0.0/25 -j ADMINS
iptables -A FORWARD -i tun+ -s 10.8.0.128/25 -j USERS