OpenVPN Access Server on Active Directory via LDAP

Introduction

This guide shows how to configure Windows Server 2016 running an Active Directory so that OpenVPN Access Server can connect to it and use the objects in the AD for authentication. The process is reasonably simple but there are some things to consider. By default for example the connection is not protected with SSL encryption, so the default setup makes information travelling between the Access Server and the LDAP connector on the AD server reasonably easy to intercept and read by network traffic capturing tools. If your Access Server is in the same private network as the AD server, then the security risks of this are minimal. SSL encryption can however be enabled with command line options in the Access Server, and with additional configuration on the AD server. For ease of implementation this guide assumes the standard unencrypted connection. Adding SSL is explained later on and refers to command line options of Access Server and refers you to documentation of your chosen Active Directory platform.

Connecting to an LDAP server to look up objects like users and groups can be done either anonymously, which by default is blocked on Windows Server 2016, or it can be done with a bind user, which is basically just an account that lets you into the LDAP server after which you can then do a search on a specific object in the directory, or you can use the administrative account. That last option would obviously be the least preferred option. The best option is to set up a bind user, which is explained in this guide. However, we do also show later on how to set up allowing anonymous binding to see specific objects. Not the whole LDAP directory, although that is of course possible, but just the objects you want to be visible via anonymous binding.

The Access Server only uses the LDAP server to look up user objects and check the password. It does not synchronize the users present in the LDAP directory somehow to the User Permissions table in Access Server. It just takes a user name and password provided by a user, tries to look up the user in the LDAP directory, and if found, tries the password to see if it is valid. If it is valid, then some user properties in the LDAP directory are sent to the Access Server along with an "ok" message indicating that the credentials were fine. Then, based on settings in the User Permissions page on the Access Server, the user is allowed to connect, with standard permissions or with permissions you've set in the User Permissions table.

It is however possible to have the User Permissions table automatically populated as users are logging in, and permissions like group assignments and such can be also automatically set, when you are using a post_auth LDAP group mapping script.

Create and configure a bind user

Since we are only going to be contacting the LDAP server for authentication of users, all we really need is the ability to look up the user and verify the password for the account. This requires only limited access. In our guide we are going to be creating a new standard user without administrative privileges, and give it a secure password, and deny it the ability and requirement to alter the password. This is to ensure the account credentials will continue to function in the future. This user account will be part of the group Domain Users but will have no additional security access granted. If you are familiar with security settings you may of course implement it in whatever you wish and limit this user account even further, just as long as you can still use it to bind to the LDAP server and perform user authentication.

Open the Active Directory Users and Computers panel.

Right click where you want to create the new user and choose New > User.

Enter the necessary information for a new bind user for Access Server LDAP access.

Set a secure password and make it so the password never changes.

Configure Access Server to use LDAP authentication

If you have followed our security recommendations after installation of the OpenVPN Access Server, then the default administrative account openvpn has been disabled by removing the password on it, and you are using another user account for administrative purposes. All accounts on the Access Server except the openvpn account authenticate through the authentication system you have configured in the Access Server. The openvpn account always authenticates through PAM and therefore, if you make a mistake when reconfiguring the authentication system and nobody can authenticate and log in to the Access Server anymore, then the only user that still can is the openvpn account. Therefore as the very first step we recommend that you revive this account again and use that to log on to the Admin UI, and then reconfigure the authentication system. You can then make mistakes in this process without losing access to the Admin UI.

If you have disabled the openvpn account by removing its password only, then restore it on the command line as root user:

passwd openvpn

And then follow the simple steps below.

Log on to the Admin UI as openvpn administrative user.

Go to Authentication, LDAP, and set address of your server, bind user, and base DN of your LDAP directory.

Click save settings to store the changes. There's no need to click Update Running Server yet.

Go to Authentication, General, and set it to LDAP, and save settings.

This time make sure to click Update running servers to implement the changes.

At this point, authentication via LDAP should now be working. You can test it by for example using the web interface to log on or using the authcli tool to debug and test authentication. If you have problems authenticating we suggest checking the authentication problems troubleshooting page.

Once you have authentication against LDAP working properly, we recommend you add a user to the User Permissions table for administrative purposes only, and assign it the admin privilege. This user account must of course be a valid and existing user account in the LDAP directory server. This user account can then be used to perform administrative tasks. We also recommend that once this is working, to disable access to the openvpn account again by removing its password via the command line as root user with the command below. By default, removing a password in the Linux operating system automatically means you cannot use the account to log in.

Remove password to disable the openvpn account:

passwd -d openvpn

Applying specifics settings to Access Server users

As mentioned, there is no synchronization going on between users in the LDAP directory, and the User Permissions table in the Access Server. But you can still apply permissions to users authenticating at the Access Server. Something to keep in mind however is that LDAP is by default case insensitive. But Access Server is not. The exact name as it is known in the LDAP directory is what is leading here and should be adhered to when implementing permissions for an LDAP user in OpenVPN Access Server's User Permissions page.

Let's try to explain why this is important with an example: let's say a user logs on at the Access Server's web page or through an OpenVPN client, and what the user enters can be JDRAAISMA or JDraaisma and both get sent to, and would then be accepted by, the LDAP server. It doesn't care about uppercase or lowercase. It is case-insensitive. So either spelling is considered fine by the LDAP server. Passwords however are always case-sensitive of course. The LDAP server reports back the exact correct name as it is known in the LDAP directory back to the OpenVPN Access Server after a successful authentication however, and the Access Server uses that exact name to look up any special settings for this user. So if in the LDAP server the actual name is jdraaisma then the Access Server will go to the User Permissions table and try to find any entries there that are spelled exactly jdraaisma, even when you logged on with a different spelling. If it is spelled in the User Permissions table as JDRAAISMA or JDraaisma it will not recognize it. And then any settings you try to apply to this user, will simply not be applied.

So in short, when using LDAP authentication and trying to apply user-specific settings, make sure to use the name and spelling as it is known in the LDAP directory. If the user is known as Billy.Bob then user that exact same spelling and case when adding the user to User Permissions in the Access Server. Any settings you then place on the account will be applied when this user logs in.

Allow only specific users to log on - user in deny list

By default, on the User Permissions page in the Admin UI, the checkbox at the bottom is unchecked. This checkbox controls the require user permissions record for VPN access restriction. If this option is enabled then only users that have been specifically added to the User Permissions page in the Access Server are allowed to log on. That means that even if for example a user account like D.Sommerseth exists in the LDAP directory, but it doesn't exist in the User Permissions table, then this user simply cannot log on to the Access Server. He will be considered to be in the "deny" list. To allow this user access while this restriction is enabled, you can simply add the user name D.Sommerseth exactly as it is known in the LDAP directory server, to the User Permissions table, and the user can then log on. This is a useful method of restricting VPN access to only a very select few people, but to use the same password credentials as they are known in the LDAP directory. If you have problems authenticating we suggest checking the authentication problems troubleshooting page.

Only allow users from one specific group to log on

If for example you have a group in your LDAP directory that is called VPN Users and you want only users from that group to be able to log on you can use the additional LDAP requirement option under Authentication, LDAP, in the Admin UI of the Access Server. Be sure that you specify the full DN or the query may fail to find the user in your LDAP directory. In fact the whole idea is that you are restricting your query to only a portion of the LDAP directory that meets your requirements, and any user that doesn't meet that requirement, simply cannot be found in the LDAP directory. If you see user not found that meets specified requirements then either the user account you are testing with does not meet your query requirements, or your query requirements are wrong and can never be met.

So if for example I have a group called VPN Users in my Active Directory and the user jdraaisma is a part of that group, but the user bad_user is not, then when I use this additional requirement in my LDAP query:

memberOf=CN=VPN Users,CN=Users,DC=example,DC=com

And if I then use authcli to authenticate with a correct user account that is part of the VPN Users group I see this:

root@DEBIAN8x64:/usr/local/openvpn_as/scripts# ./authcli -u jdraaisma -p [redacted]
API METHOD: authenticate
AUTH_RETURN
 status : SUCCEED
 session_id : byOKdf+Od5x+XB2uh+xCSw==
 reason : LDAP auth succeeded on ldap://192.168.47.131/
 expire : 1506864634
 user : jdraaisma
 proplist : {'prop_autogenerate': 'true', 'prop_deny': 'false', 'type': 'user_connect'}

And trying the same with a bad user account that is not part of a the VPN Users group I see this:

root@DEBIAN8x64:/usr/local/openvpn_as/scripts# ./authcli -u bad_user -p [redacted]
API METHOD: authenticate
AUTH_RETURN
 status : FAIL
 reason : LDAP exception on ldap://192.168.47.131/ (facility='search (u'CN=Users, DC=example, DC=com', 2, u'(&(sAMAccountName=bad_user)(memberOf=CN=VPN Users,CN=Users, DC=example, DC=com))')'): user not found that meets specified requirements: memberOf=CN=VPN Users,CN=Users, DC=example, DC=com: auth/authldap:127,python2.7/threading:774,python2.7/threading:801,python2.7/threading:754,python/threadpool:210,python/context:59,python/context:37,auth/authldap:94,auth/authldap:127,util/error:61,util/error:44
 user : bad_user

Please note that nesting groups is not supported. So if you make a group a member of another group, that type of nesting of groups is not currently supported. If you have problems authenticating we suggest checking the authentication problems troubleshooting page.

Optional: enabling SSL over the connection

According to Microsoft documentation, as soon as an Enterprise Root CA is installed on a domain controller, LDAPS is enabled. If that is the case then you should be able to enable SSL connectivity on the Access Server by going to the Admin UI, Authentication, LDAP, and checking the Use SSL checkbox there and save settings and updating the running servers. But if you have no use for an Enterprise Root CA on your server and you want only to enable SSL for LDAP purposes, you could choose to only implement a digital certificate just on the domain controller for LDAP SSL purposes. This does mean verification of the certificate cannot occur automatically but you can import the certificate on the Access Server manually and use that for verification that you're talking to the correct server.

For the specific options that govern how SSL certificates are verified for a secure SSL LDAP connection from Access Server to your LDAP server, see this command line options overview for LDAP authentication.

As to how to configure your LDAP server to allow SSL, we refer you to documentation of your chosen Active Directory platform, and this excellent article that explains a lot about the actions to take.

Optional: how to enable anonymous binding

We don't recommend doing this, and to instead use a bind user. But if for whatever reason you want to do this, follow these steps to allow anonymous bind to LDAP and to allow searches in the Users container in the LDAP directory anonymously. This way you can use the Bind anonymously option in the OpenVPN Access Server's LDAP authentication settings page, if you want to do this.

Open the ADSI Edit tool.

Right click ADSI Edit and select Connect To...

Set the Naming Context to Configuration, as we want to edit a setting there.

Navigate to the CN=Directory Service entry, and right click it and open properties.

Edit the dSHeuristics setting. If its not set, enter 0000002. If it is set, alter the 7th digit to 2.

Open Active Directory Users and Computers panel.

In the top menu click View, and make sure Advanced Features is enabled.

Right click the object you want to make available to anonymous LDAP bind and select Properties.

Go to the Security Tab and click on Advanced. (not visible if advanced features not enabled)

Click Add, click Select a principal, and enter: ANONYMOUS LOGON. Click ok, ok, ok.

Now anonymous bind to LDAP is possible and you can do anonymous searches on the LDAP directory server contents of this object you have given anonymous logon read and list permissions to.