This article explains how to authenticate OpenVPN clients that connect to an OpenVPN server that runs on OpenBSD using a Yubikey as the second factor, in addition to the regular authentication that employs X.509 certificates.
OpenBSD provides an excellent support for the Yubikey as a part of its implementation of the BSDAuth framework. Unfortunately, the openvpn_bsdauth program that is supposed to bridge between OpenVPN and BSDAuth suffers from a number of shortcomings that call for a better solution:
Below I am offering a program which is an alternative to openvpn_bsdauth. This program is much more flexible and somewhat more secure.
There are several places that explain how to do that. Please do not proceed until you are familiar with the setup. I recommend you first getting OpenSSH to work with Yubikeys: as a by-product, you will have a system that uses a stronger authentication of remote shell sessions, which is a good thing.
You will need to install OpenVPN from the ports tree. Please follow the instructions given in OpenBSD FAQ. The explanation below assume that you use the default location of the ports tree, /usr/ports.
First, download bsdauth-20160320.tar.gz, which is a Git checkout of my repository. Second, download bsdauth-20160320.tar.gz.sig, which is the signature of the package. Third, download firstname.lastname@example.org, which is the public key. When you have all the three files in the same directory, please verify the signature:
Please do not proceed if you see anything different from Signature Verified in the output. Please let me know if verification of the signature fails.
signify -V -p email@example.com -m bsdauth-20160320.tar.gz
If you do not trust this signify(1) public key, you can verify it using my public PGP key (I have only one PGP key which is published and is not revoked, its ID is 0x009E3949, you can find this key on the nearest public PGP key server) and the following signature:
-----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQEcBAABCAAGBQJY2ToTAAoJEHX3u/sAnjlJD60H/3+zgmP9mKdds9dcut70ZsuA huRfeTu7Qu19R3k2eVEFv4qbEX1ePR/RPGDyAiSTTvJmeyRj5If59l/wo2MbSVjh wv53Y0B2TkEL1WoyGjPRuzomaztTdL92QW9iF48L8F5rYceJthwINuBxoVe9Id4J zuptIFU/NHdcQx6H0wxxgrGZJ2x1ptxVLMU8zOwWLZGiMMzzxFL5KiRxzPBix1qu 1GHmtrlU7f/tBIK4JKw5Fxk7I9iYciyYHwoyTEOyZGLWeBRBKOfGW9VZhKECILLC Gni6nCERnA8BdWylWJSgvAchwIVlKDAeR6D0MFZLEiVmLqDvpbHAWn2LvTrTqHg= =TAvt -----END PGP SIGNATURE-----
tar xzf bsdauth-20160320.tar.gz cd bsdauth-20160320
On OpenBSD, a process that uses BSDAuth must belong to the auth group (otherwise it will not be able to execute BSDAuth's helper programs like login_passwd(8), login_yubikey(8), and such). The openvpn_bsdauth program works around this requirement by installing itself as a SGID binary that belongs to that group.
On OpenBSD, OpenVPN usually runs as the user _openvpn and the group _openvpn. One way of making OpenVPN being capable of using BSDAuth would be running it as the group auth but, at very least, this means breaking the default setup of the package that OpenBSD users are accustomed to.
A much better way of solving this problem is making the user _openvpn a member of the group auth which is a trivial task. There is a problem, however. This may sound surprising but OpenVPN does not initialize secondary (supplementary) groups when it switches to the GID/UID specified in the server configuration file with --user and --group directives.
To address this issue, I developed a set of patches that introduce an optional parameter to OpenVPN, --secondary-groups which tells OpenVPN to initialise secondary groups that the user specified with --user belongs to, just before it switches the UID.
To apply the patchset, copy the contents of the directory patches to the appropriate location of the ports tree:
and proceed to the regular, straightforward installation of the OpenVPN port:
doas cp ports/* /usr/ports/net/openvpn/patches
cd /usr/ports/net/openvpn doas make install cd -
There will be a number of warnings about unused parameters, you can ignore them safely.
make && doas make install
The plugin, /usr/local/libexec/bsdauth.so has the following parameters, all of them optional:
If you decided to have auth as a secondary group of the user _openvpn then the server configuration file must contain the following:
Obviously, you must not forget to add the user _openvpn as a member of the group auth in group(5).
user _openvpn group _openvpn secondary-groups
If you decided not to use secondary-groups then the server configuration file must contain the following:
Again, I recommend against this approach.
user _openvpn group auth
The plugin must be enabled in the server configuration file using the plugin option of OpenVPN. For instance, the following enables the plugin and specifies the authentication style yubikey and checking for membership in the group _openvpnusers:
plugin /usr/local/libexec/bsdauth.so style yubikey group _openvpnusers
In the client configuration file, enable the username and password authentication using the option auth-user-pass.
At the top level:
At the end of the definition of the class default:
The user _openvpn is a member of the group auth:
The user vadimp is a member of the group _openvpnusers:
server 192.168.5.0 255.255.255.0 dev tun0 persist-key persist-tun keepalive 10 60 user _openvpn group _openvpn secondary-groups dh dh1024.pem ca ca.pem cert cert.pem key key.pem plugin /usr/local/libexec/bsdauth.so type auth-vpn group _openvpnusers route 192.168.5.0 255.255.255.0
(aa.bb.cc.dd is the public IP address or a FQDN of the OpenVPN server.)
client ca ca.pem cert cert.pem key key.pem auth-user-pass dev tun remote aa.bb.cc.dd 1194 udp persist-key persist-tun
Vadim Penzin, March 20th, 2016
I hereby place this article along with the accompanying source code into the public domain.
You are welcome to contact me by writing to howto at this domain.
I publish this information in the hope that it will be useful, but without ANY WARRANTY.
You are responsible for any and all consequences that may arise as the result of using this information.