OpenVPN Access Server post_auth hardware address checking script
The post_auth programming hook in OpenVPN Access Server gives you the ability to extend the possibilities of the Access Server to authenticate against a source of credentials. This document provides examples for creating your post_auth script that includes the hardware address as part of the authentication process.
Authentication and role of post_auth
OpenVPN Access Server’s Authentication System
Without using a post_auth script, OpenVPN Access Server supports several robust authentication systems—whether you manage it from the Admin Web UI or authenticate against a third-party system. These are the systems already supported:
- Local: Access Server’s authentication system using a SQLite3 database to store user properties and credentials with management handled in the Admin Web UI.
- PAM: Linux’s system that requires management in the console or an SSH session on the OS itself.
- LDAP: Access Server can authenticate against an LDAP server once you set up the connection in the Admin Web UI.
- RADIUS: Access Server can authenticate against a RADIUS server once you set up the connection in the Admin Web UI.
Refer to this detailed reference guide for more information about these systems: OpenVPN Access Server’s User Authentication System.
The post_auth script process
- User signs in with a VPN client or on the Client Web UI.
- They successfully authenticate with their username and password.
- The post_auth script runs (hence, post_auth—after authentication).
The post_auth script itself is a text file in the programming language Python. With it, you can do all sorts of interesting things like automating assigning users to groups based on specific criteria, implementing a custom authentication system, adding an extra filter to the login process, or checking the user device’s hardware address.
The hardware address checking post_auth script
You can create a hardware address checking script to enhance the security of your authentication by only allowing users with registered MAC addresses and UUID strings to connect to the VPN server successfully.
Our sample script automatically registers the device’s MAC address or UUID string, but you can configure it to have complete control over it as the administrator. The post_auth script can accept two hardware addresses per account but only auto-registers the first; you can manually add the optional, secondary address.
An important thing to note here is that it depends on what the client sends: either a MAC address or a UUID string:
- In general, OpenVPN2 clients send MAC addresses.
- Recent OpenVPN3-based clients may send UUID strings.
Both options are unique identifiers for the device, and our post_auth script accepts and stores either one. Each time the client attempts to connect, it must offer the same string to succeed. Originally, only MAC addresses were accepted, and the documentation may still reference only MAC addresses, but it also accepts UUIDs.
From a user perspective
When a new user signs in and you’re using the default settings for our post_auth script, here’s the process:
- New user signs in with valid credentials.
- The MAC or UUID isn’t in your Access Server’s user properties database.
- Access Server automatically registers and stores the MAC or UUID in the user properties database.
- The next time the user signs in, their MAC or UUID must match the value stored in the user properties database.
For this authentication, users can use most open-source clients or recent versions of OpenVPN Connect. See below for more detailed information about client compatibility. Older clients don’t provide a MAC address or UUID string, which will lead to an error message when a user tries to connect.
How to install/update the script
To install or update the script, we assume:
- You’re signed in through SSH or your Access Server server console.
- You’ve obtained root privileges.
- Obtain the script file from the URL below.
- Save the script file on your Access Server (even if only temporarily).
For our example, the filename is mac.py, and the file is stored in the following folder: /root/mac.py.
Example hardware-address script file:
The following command retrieves the file directly on your server as root user:
wget https://swupdate.openvpn.net/scripts/post_auth_mac_address_checking.py -O /root/mac.py
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 use the above commands to reload the new version of the script into the configuration database and reload the Access Server configuration again.
Restricting automatic registration of MAC addresses for new accounts
By default, a valid user account without a registered MAC address or UUID string—such as a new user—can connect from any device. After the first successful connection, Access Server stores the hardware address of that system. The server now only accepts a connection for this user account from that device.
You can restrict or completely disable this automatic registration, as detailed below.
Restrict automatic registration to a specific network
If you want to restrict the automatic registration to 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 hardware address registrations from one public IP, put that in the script. Let's assume the following situation:
- You have a private company network with an internet gateway at the public IP address 126.96.36.199.
- You run your Access Server on a cloud system elsewhere on the internet.
- Only systems connected to the internet through the company network can register a new device with your Access Server.
You need to write your script to allow new device registrations only from the public IP of your company network.
For example, allow new device hardware address registration only from IP 188.8.131.52:
If you leave this parameter empty, Access Server accepts first-time logins from any IP address. That is the default behavior. But if you define the item above, new registrations only succeed if their source IP matches the defined first_login_ip_addr value. This provides extra security for use cases such as the need to deny users registering from home networks, registering only on the office network, or requiring the system administrator to register devices.
Disallow automatic registration
If you don't want automatic registration at all, you can set this value to an impossible value like NONE or DISABLED. Thus the check always fails, and nobody can register their devices by themselves. In such a situation, the system administrator must do all hardware address registrations through the command line.
Notes regarding connection profile types
This script works with all three types of connection profiles: user-locked, server-locked, and auto-login. All adhere to the restrictions in this post_auth script. In some cases—such as with the auto-login connection profile—OpenVPN Connect may end up looping endlessly trying to connect when it‘s denied access based on MAC address or UUID string restriction, in which case you need to correct the situation by making sure the correct hardware 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 'openvpn' on Linux.
- The open-source client 'OpenVPN GUI' on Windows.
- The open-source client 'Tunnelblick' on macOS.
- Most open-source clients based on 'openvpn' binary version 2 or version 3 should work.
Note that we assume you’re using a recent version for all clients. If you connect with your client software of choice and it doesn’t report a MAC address or UUID string to the Access Server, then the client is denied access. To resolve this, check 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 sending the required information to the server at connection time.
How to uninstall the script
After you’ve loaded the script into the configuration database, you can remove it, if needed, using the following commands. Note that this action does not remove the MAC addresses or UUID strings already saved in the database, but Access Server will ignore these. You can clean those up manually if you wish with the sacli command, and we provide instructions 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 the user account is being used on another device or the hardware address has changed, you need to remove the MAC address or UUID string stored and locked for that particular user. You can use the following commands to remove the saved value for the user "exampleuser" and reload the server.
Remove saved MAC address or UUID string 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 specify the address for an account manually, 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 your authentication system, you may need to pay attention to lowercase/uppercase with the username. Please stick to lower case for the MAC address or UUID string itself.Manually register/update MAC address or UUID string 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
There are use cases requiring a secondary hardware address. For example, a laptop may report a different MAC address, whether it connects over wifi or an ethernet connection.
You can manually specify a secondary address accepted for a user account. This assumes a MAC address or UUID string is already present in the user database for a specific user. You can simply add a secondary address that’s also accepted. We don’t allow automatic registration for the secondary address for security reasons.
Manually register/update a secondary MAC address or UUID string 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
Remove network restrictions
If you use the restriction to allow only hardware address registrations from a specific IP address, as explained above, then you should remove that restriction when troubleshooting.
- Undo that particular restriction in your mac.py file.
- Install/update the post_auth script again.
- Reload the settings again.
- Test your connections.
That way, that restriction won't be an issue in trying to debug why things aren't working.
Use the latest software versions
Ensure you use the latest software, as older software may not support the feature of reporting MAC addresses or UUID strings to the server. That goes for both the client and server software, as running old server software is also not a good idea.
Check log files
You can find any information that the post_auth script outputs to the log file 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 processes the post_auth file.
You can filter for specific messages from post_auth with this command:
cat /var/log/openvpnas.log | grep "POST_AUTH"