OpenVPN Access Server post_auth hardware address checking script
Authentication and role of post_auth
The post_auth programming hook in Access Server was put in to extend the possibilities of the Access Server to authenticate against a source of credentials. By default without using post_auth the following sources can be authenticated against in Access Server:
This method relies on using an SQLite3 database that is stored on the Access Server’s file system itself. It contains both the user properties and the user credentials. Management of credentials is handled in the ‘user permissions’ area of the admin web services of the Access Server.
This is the system that is present on Linux systems, and is the default choice for the Access Server. This uses the credentials from the Linux system itself to authenticate to. Management of credentials is done in the console/SSH session in the Linux OS itself using standard tools like adduser, deluser, and passwd.
To connect to an OpenLDAP or Windows AD, the LDAP option is fairly easy to use. For security a proxy account can be made on the LDAP server through which the Access Server can talk to the LDAP server to perform authentication against the credentials stored in the LDAP server. Management of credentials is handled by using LDAP browsing and management tools, or in Windows AD by using the “Active Directory Users and Computers” program.
Like LDAP, the credentials are stored in the RADIUS server, and management of credentials is handled by using the tools available for browsing and manipulating the contents of the RADIUS credentials database. Windows Server Active Directory supports the ability to allow the Access Server to query the AD over the RADIUS protocol, as is the case with LDAP.
The post_auth script is run during the authentication session where a user tries to log in at the Access Server from a compatible OpenVPN client or on the web interface. In this particular case we only bother to look at the VPN authentication phase. The script runs just after the VPN authentication phase has succeeded. Hence, post_auth - after authentication. The script itself is a text file in the programming language Python. With it you can do all sorts of interesting things like automate assigning users to groups based on certain criteria, or implement a custom authentication system, or in this case to add an extra filter to the login process. This MAC address checking script is designed to allow only users with a registered and correct MAC address to connect to the VPN server. The registration process of a device's MAC address to an account is automated in our sample post_auth script by default. But it can also be configured to be completely controlled by the administrator instead. The post_auth script can accept a total of 2 MAC addresses per account, but only auto-registers the first one, and an optional secondary address may be added manually by the server administrator.
An important thing to note here is that while Windows, Linux, and macOS devices will be reporting a MAC address, iOS and Android devices will not. This is due to the nature of privilege limitation and also some other design choices related to how mobile platforms work. For iOS and Android we therefore use the UUID instead, which is a unique identifier for those devices. The post_auth script will work with that. Because originally only MAC addresses were accepted the documentation may still reference only MAC address, but it will also accept UUIDs.
From a user perspective
Assuming you use the default settings for our post_auth script, whenever a user logs on and has no MAC address registered yet in the user properties database of the Access Server, then the MAC address will be automatically registered and stored there. Any following attempt to log in under that user account will require that the connection is made from the same MAC address. The MAC address is taken from the network device used for Internet access that the VPN client finds in the system. Only recent version of OpenVPN Connect are supported, as are most open-source clients. There is more information on client compatibility further on in this document. There are older clients that will simply not provide a MAC address to check, and if that is the case, then those will be shown an error message when they attempt to connect.
How to install/update the script
In our documentation we are assuming you have logged on through SSH or the console of your server running the OpenVPN Access Server and that you have obtained root privileges. The script itself is available from our website at the URL mentioned below, the script file itself has to be saved somewhere on the Access Server, even if just temporarily. The filename that you use is not important but in our documentation we will assume that it is mac.py and that it is stored in the following folder: /root/mac.py
It could be retrieved directly on your server as root user like so:
wget https://swupdate.openvpn.net/scripts/post_auth_mac_address_checking.py -O /root/mac.py
Note that if you have problems downloading the script this way, you may need to install/update the wget and/or ca-certificates package(s) on your system.
Once that is done you can load the script and reload Access Server:
cd /usr/local/openvpn_as/scripts ./sacli -k auth.module.post_auth_script --value_file=/root/mac.py ConfigPut ./sacli start
If you make alterations to the mac.py file then you will need to use the above commands again to load the new version of the script into the configuration database, and to reload the configuration of the Access Server again.
Restricting automatic registration of MAC addresses for new accounts
By default a user account without a registered MAC address, like for example a newly created account, will allow any computer to connect. Once the first connection is made, the MAC address of that system is stored and locked. The server will now only accept a connection for this user account from that MAC address. There are some options to disable or restrict this automatic registration.
If you want automatic registration to only work from a specific network, like a corporate network, you can use the first_login_ip_addr variable in the script. If the first_login_ip_addr variable is set to a specific IP address, then only first time login attempts will be accepted from that public IP address. For example if you only want to allow MAC address registrations from one public IP, put that in the script. Let's assume you have a private company network that has an Internet gateway with public IP 220.127.116.11 and your Access Server is on a cloud system elsewhere on the Internet, and only systems that are connected to the Internet through the company network are allowed to register new device MAC addresses. You can define the public IP of your company network that registrations will be allowed from.
For example, allow new device MAC address registration only from IP 18.104.22.168:
If this parameter is left empty, then first time logins will be accepted from any IP address. That is the default behavior. But if you define the item above, then new registration must have as source IP that particular IP address. It is a good way of denying users to register themselves from their home networks, forcing people to either register devices by going to the office and then logging in to the VPN server, or ask the system administrator to do it for them.
If you don't want automatic registration at all, then you can set this value to an impossible value like NONE or DISABLED so that this check always fails and nobody can register their devices by themselves. In such a situation, all MAC address registrations must be done through the command line by the server administrator.
Notes regarding connection profile types
This script works with all 3 types of connection profiles. That is, user-locked, server-locked, and auto-login. All will adhere to the restrictions in this post_auth script. In some cases, like for example with the auto-login connection profile, the Connect Client may end up looping endlessly trying to connect when it is being denied access based on MAC address restriction, in which case you need to correct the situation by making sure the correct MAC address is registered for your device.
Notes regarding client software
OpenVPN Connect v2 for Windows and macOS are supported, but only reasonably recent versions like 2.7.*. OpenVPN Connect v3 for Windows, macOS, iOS, and Android, are also supported. The following clients have also been tested to work but are not under any guarantee of support by us:
● The open source client called 'openvpn' on Linux.
● The open source client called 'OpenVPN GUI' on Windows.
● The open source client called 'Tunnelblick' on Macintosh.
● Most open source clients based on 'openvpn' binary version 2 or version 3 should work.
Please note that for all clients it is assumed that you are using a recent version. If you make a connection with your client software of choice and it turns out that it is not reporting a MAC address to the Access Server, then the client will just be denied access. To try to resolve this, the first thing to check is that you have the latest version of that software with the most recent version of the OpenVPN binary core that you can get, to have a good chance of it being capable of sending the required information to the server at connection time.
How to uninstall the script
The script is loaded into the configuration database, and can be removed from there with the following commands. Note that this action does not remove the MAC addresses already saved in the database, but these will simply be ignored and not cause further issues. It is possible to clean those up manually if you wish with the sacli command, and instructions are provided for that in the next section.
To uninstall/remove a post_auth script:
cd /usr/local/openvpn_as/scripts ./sacli -k auth.module.post_auth_script ConfigDel ./sacli start
How to unregister/reset a MAC address
If for some reason the user account is being used on another system or for some reason the MAC address has changed, you will need to remove the MAC address that is currently stored and locked for that particular user. To do this you can use the following commands to remove the saved MAC address for the user "exampleuser" and reload the server.
Remove saved MAC address for exampleuser:
cd /usr/local/openvpn_as/scripts ./sacli -u "exampleuser" -k "pvt_hw_addr" UserPropDel
How to manually register/update a MAC address
If you want to manually specify the address for an account, you can do so with the following commands, where "exampleuser" is the user account name and where "00:01:02:ab:cd:ef" is the MAC address. Depending on what authentication system you are using, you may need to pay attention to lowercase/uppercase with the username. Please stick to lower case for the MAC address itself.
Manually register/update MAC address for exampleuser:
cd /usr/local/openvpn_as/scripts ./sacli -u "exampleuser" -k "pvt_hw_addr" -v "00:01:02:ab:cd:ef" UserPropPut
Manually registering a secondary MAC address
It is possible that in cases such as with laptops, that people use WiFi or Ethernet connections to go online, and this can result in different MAC addresses being reported to the server depending on which is used. It is possible to manually specify a secondary address that will be accepted for a user account. This assumes that there is already a MAC address present in the user database for a specific user, and you can simply add a secondary address that will then also be accepted. We do not allow automatic registration for the secondary address as this could open up a security hole where a second different device could attempt to register its address.
Manually register/update a secondary MAC address for exampleuser:
cd /usr/local/openvpn_as/scripts ./sacli -u "exampleuser" -k "pvt_hw_addr2" -v "ef:cd:ba:03:02:01" UserPropPut
How to debug any problems
If you use the restriction to allow only MAC address regisrations from a specific IP address as explained in this file, then please undo that particular restriction in your mac.py file and install/update the post_auth script again, and reload the settings again, as explained earlier in this file. That way at least that restriction won't be an issue in trying to debug why things aren't working.
Also make sure you use the very latest software, as older software may not support the feature of reporting MAC address to the server. That goes for the client and server software both, as running old server software is also not a good idea.
Any information that the post_auth script outputs to the log file can be found in the /var/log/openvpnas.log file (by default) on most Access Server setups. You can also edit the mac.py file you have on your server and add 'print' lines to it to dump more information into the log file, to try and see what values are in particular variables as Access Server process the post_auth file.
You can easily filter for specific messages from post_auth with these commands:
cat /var/log/openvpnas.log | grep "POST_AUTH"