Setting Up OpenVPN with Active Directory Authentication

Okay, we now have working certificate authentication so we are ready to take things a step further and finally get our OpenVPN server to authenticate users against our Active Directory Domain Controller. I am just going to remind you of a few pre-requisites…

  1. A Domain Controller that your OpenVPN server can talk with over TCP port 389
  2. A Microsoft Active Directory USER account with a non-expiring password
  3. A regular Active Directory user account that you can test the VPN connection with

On your OpenVPN server go ahead and run the following command:

apt-get install openvpn-auth-ldap

That installs the LDAP authentication module for OpenVPN. Thankfully, Microsoft Active Directory is actually built more or less on LDAP (lightweight directory access protocol) which is open-source. Using LDAP calls, openVPN can check a username and password against an LDAP directory (like Active Directory) and authenticate users.

Once it is finished installing run the following commands:

mkdir /etc/openvpn/auth
vim /etc/openvpn/auth/auth-ldap.conf

The last command should have created a new config file in the new auth directory we just made and opened up the conf file for editing in VIM. Copy and paste the following code verbatim into your new conf file:

<LDAP>
        # LDAP server URL
        URL             ldap://XXX.XXX.XXX.XXX:389    # modify this lin! Replace X's with your Domain Controller's local IP address

        BindDN          "CN=username,OU=taskaccounts,OU=users and groups,DC=contoso,DC=local"    #modify this line to!

        Password        "[email protected]$wrD123"     # Enter the password of the user account that OpenVPN will use to talk to your domain controller

        Timeout         15
        TLSEnable       no
        FollowReferrals no
</LDAP>

<Authorization>
        BaseDN          "OU=employees,OU=users and groups,DC=contoso,DC=local"   # MODIFY THIS LINE!
        SearchFilter    "(sAMAccountName=%u)"
        RequireGroup    false
</Authorization>

Okay, this is pretty much the most simplified version of this file I could create. I am not going to lie here, you need some basic Active Directory administration knowledge. Assuming you do, we will move forward with an explanation of what you are looking at.

This conf file has two sections. The LDAP section, and the AUTHORIZATION section. The LDAP section is where all of the information about how your OpenVPN server makes a connection to and talks with your Domain controller. The AUTHORIZATION spells out what question the OpenVPN server is going to ask the Domain Controller in order to authenticate users. There is actually very little here you need to modify but you need to know how your domain is structured.

In the LDAP section…

  • URL – Very simply you need to modify those X’s with your domain controller’s IP. LEAVE THE SYNTAX ALONE. And the port! So your final might look something like URL ldap://192.168.23.10:389
  • BindDN – This line is the complete directory path to the user account that will be authenticating with the Domain Controller and asking it questions about users and whether they can authenticate in OpenVPN. This is that account I have mentioned a couple of times that just needs to be a basic user with a non-expiring password. LEAVE THE SYNTAX ALONE, just change / add / remove information. CN= is the actual username (login name) of the account. So if your user is called “ldapservice” then that is what would go here. You then need to say where that account can be found in Active Directory. So in this example the user “username” is found in the organizational unit (OU) “taskaccounts” which is inside of the organizational unit “users and groups” which is part of the contoso.local domain (so DC=contsoso,DC=local). It can take a while to get used to writing/thinking in this syntax. Get used to it if you have to work with Active Directory (or any other LDAP type server) on a regular basis.
  • Password is pretty self explanatory. Put the password for that account out next to it and keep the quotation marks around it. (remember, the syntax above is correct! Aside from the IP address, this could be a working file if the environment existed for it

In the AUTHORIZATION section…

  • BaseDN – This is very similar to BindDN above except in this case we aren’t narrowing all the way down to a single username (no CN…). Rather we are showing the location of where all of the user accounts are in active directory that OpenVPN needs to authenticate against. So in this case the accounts are all in organizational unit “employees” which is inside of organizational unit “users and groups” in the contoso.local domain.
  • SearchFilter – You don’t need to modify this. I have saved you much hell… This is very very basic but getting that bloody search syntax correct is a headache. This basically says, that active directory object attribute “sAMAccountName” on some object in the above specified location (BaseDN) must be equal to the username that is being sent by openVPN. The sAMAccountName then tells it which object to compare the sent password with.

I just want to point out that this as bare bones as it gets. You can get more involved with search filters (like making sure the account is active) and with defining groups (requiregroup in this case is false) so that they have to be a part of the vpnuser group or something. That is beyond what we are doing here. Furthermore, in the LDAP section you can add parameters to secure the connection between the Domain Controller and OpenVPN with encryption. This probably isn’t a bad idea, especially if you have something interesting going on (like they are in two different networks and have to communicate over an untrusted link). All of this more advanced configuration may get treatment in future posts by me. But are outside of the scope of what we are doing here.

Okay… we need to modify a few lines in our server.conf file now to turn off certificate authentication and turn on LDAP authentication (you can do both but in my use-case we are doing just ldap).

vim /etc/openvpn/server.conf

and then modify the following lines to look as shown here:

#DISABLE CERT AUTHENTICATION
client-cert-not-required
duplicate-cn

#PLUGIN SECTION
#LDAP (Active Directory Authentication) PLUGIN
plugin /usr/lib/openvpn/openvpn-auth-ldap.so /etc/openvpn/auth/auth-ldap.conf

All we did was remove the “#” in front of three lines. This activates 3 options. The first two will turn off the requirements for certificates and the last one turns on the LDAP authentication module/plugin. Save that file and then restart your OpenVPN server.

service openvpn restart

Your server configuration is done. Finally on your client machine you need to update the config file. To do some start the OpenVPN GUI application, right-click on the icon for it in your taskbar and select “edit config”. This will open up Notepad. Modify the following lines to look like this:

#CHOOSE AUTHENTICATION TYPE

#AD/PASSWORD AUTHENTICATION
auth-user-pass
auth-nocache

#KEY AUTHENTICATION
#cert client1.crt
#key client1.key

So we disabled key/cert authentication and enabled password authentication. Furthermore, the “auth-nocache” line means that the client won’t store/cache our password locally which is good for security. Save your file and attempt a connection. Enter the username and password of an active directory user and it should connect if all is configured properly!

If you are still tracking with me so far, great! If not, leave some comments and I will help as I can!

The final task I have for this rather long tutorial is routing all of our client traffic through the VPN connection. Hit the next (and hopefully last…) page to talk about how to do that!

11 comments on: OpenVPN – Microsoft Active Directory Authentication – Force All Traffic Through VPN Tunnel

  1. Shane
    Reply

    Just an FYI, one of the commands after the second to last reboot prevents any connection to the Linux server

    • nbeam
      Reply

      That’s interesting, do you know which command or configuration item is killing the connection? I am wondering if I fat-fingered something somewhere in the write-up. It has been a while since I worked on this. I know when I was testing that VPN connectivity still worked and that the final result was “no split-tunneling” i.e. proxy client machines had all traffic forced through the VPN tunnel. What I am not sure is if I somehow broke SSH connectivity but didn’t realize it because I was working on the machine directly (i.e. not remotely via SSH).

      If you can shed some light on this so I can fix the write-up that would be awesome. Hate to have anyone breaking things on there end 🙂

      Thanks for the heads up!

      • Shane

        Yeah so basically for some reason, doesn’t make sense to me, adding that entry into the iptables and setting the file to load upon restart locks out any connection in, the system i implemented this in is in azure so remote access is the only option, it’s most probably a requirement to add an accept for SSH?

        adding the entry without setting the file to load upon restart doesn’t cause any issues (as far as i can tell haven’t checked thoroughly enough)

  2. Anton Bach
    Reply

    great post, really love it!
    greets, Wilfried

  3. Joe
    Reply

    I did it but start openvpn is failed .
    openvpn-auth-ldap plugin is 2.03 and download using “yum instal openvpn_auth-ldap.x86_84” on Centos 6

  4. RAF
    Reply

    Thanks for this guide. I suggest copy and past attributes from AD directly into “/etc/openvpn/auth/auth-ldap.conf” . This was my issue. Good luck

  5. Adam
    Reply

    This saved me a ton of time. Thanks for taking the time to post it.

  6. RAF
    Reply

    Just wonder is there a way to secure client certificate from being compromised and used from another PC ?

  7. coolthecold
    Reply

    cp server.crt server.key ca.crt dh1024.pem ta.key /etc/openvpn/

    here should dh1024 should be changed to dh2048 i believe

  8. dataCore
    Reply

    Great article! Helped me a lot! Little supplement: Add the following to your server.config:
    push “dhcp-option DOMAIN fqdn.yourADDomain.com”
    Otherwise a had to use the fullname e.g. servername.fqdn.mydomain.ch to contact my internal infrastructur.

    • nbeam
      Reply

      Thanks! Appreciate the tip as well 🙂 – Sure it will help others. OpenVPN Community Edition is honestly a bit of a bear. I finally gave up and just moved to the paid version (which is relatively cheap vs. other similar solutions) which is like a completely different product from an administrative perspective. The thing I really needed was two-factor authentication and the community edition (at the time) was very hard to get setup with this.

Leave a Reply