Python OpenVPN LDAP Auth
An auth verify script for OpenVPN to authenticate via LDAP. Each VPN login is
forwarded to this script and the script in turn attempts a simple bind against the specified LDAP server. When the bind
is successful the script returns exit code 0 telling OpenVPN that the credentials are valid.
Although there already is the openvpn-auth-ldap plugin I felt the
need to write this auth script. First the source code is more accessible due to it being written in Python. Second it
offers more possibilities regarding
OpenVPN's static-challenge
parameter (see
below).
The downsides of using a script instead of a C-plugin
are less performance and slightly reduced security.
If you are fine with that go ahead.
Quickstart
Install the package via pip:
pip install openvpn-ldap-auth
Then create /etc/openvpn/ldap.yaml
:
ldap:
url: 'ldaps://first.ldap.tld:636/ ldaps://second.ldap.tld:636/'
bind_dn: 'uid=readonly,dc=example,dc=org'
password: 'somesecurepassword'
timeout: 5
authorization:
base_dn: 'ou=people,dc=example,dc=org'
search_filter: '(uid={})'
static_challenge: 'ignore'
Find out where openvpn-ldap-auth
lives:
which openvpn-ldap-auth
Add the following line to your OpenVPN server configuration:
script-security 2
auth-user-pass-verify /path/to/openvpn-ldap-auth via-file
Now you can start your OpenVPN server and try to connect with a client.
Installation
Single Executable
For those who wish to sacrifice a little more performance for not having to install or compile a Python interpreter or you just want to quickly try the script out this option might be interesting.
Each release also has executables attached to it: openvpn-ldap-auth-<distro>-<distro-version>-<arch>. They are created via PyInstaller on the respective Linux distro, version and architecture. They might also work on other distros provided they use the same or a later libc version that the distro uses.
Important: /tmp must not be read only.
From Source
Download or clone this repository, cd into it and run
pip install poetry
poetry install --no-dev
poetry build
pip install --upgrade --find-links=dist openvpn-ldap-auth
Exchange pip
with pip3
if applicable.
Configuration
Static Challenge
If you want users to provide a normal password combined with a one-time-password OpenVPN's
static-challenge
parameter is what you
are looking for.
In the client configuration you need to add a line like
static-challenge "Enter OTP" 1 # use 0 if the OTP should not be echoed
When connecting you will now be prompted for your password and your OTP. By setting authorization.static_challenge
you
can now influence how the OTP is used:
- ignore (default): Just use the password for binding.
- prepend: Prepend the OTP to your password and use that for binding.
- append: Append the OTP to your password and use that for binding.
The last two options are useful if your LDAP server offers internal 2FA validation
like oath-ldap.
Using via-env
In the server configuration the following alternative setting is also supported but discouraged:
auth-user-pass-verify /path/to/openvpn-ldap-auth via-env
OpenVPN's manpage about that topic:
If method is set to "via-env", OpenVPN will call script with the environmental variables username and password set to
the username/password strings provided by the client. Be aware that this method is insecure on some platforms which
make the environment of a process publicly visible to other unprivileged processes.
If you still want to use via-env
make sure to set script-security
to 3
.
Running Tests
First make sure to install Docker
with docker-compose
and tox. Then run
tox
To run a specific Python-OpenVPN combination run something like
tox -e python38-openvpn25
To see a full list of current environment see the tool.tox
section in pyproject.toml.