External public key infrastructure (PKI)
The Access Server external public key infrastructure (PKI) feature integrates Access Server with third-party tools for X509 PKI management, instead of using the built-in certificate management capabilities. When configured for external PKI usage, Access Server doesn’t manage client certificates directly; instead, the customer's third-party PKI software generates and distributes client certificate/key pairs to client machines, and a server certificate/key pair to the OpenVPN server.This document describes how external PKI works with Access Server and provides an example setup using Access Server’s certool.
How external PKI mode works for Access Server
OpenVPN Access Server issues and manages its own certificates for the server and clients. This certificate infrastructure is the PKI and, by default, Access Server automatically manages and provisions the necessary certificates. Switching to external PKI mode involves handing off that management to a third-party tool. This changes how VPN client distribution occurs by using two channels rather than one:
- Connection profile — distribution of OpenVPN Connect and a bundled, server-locked profile. The app and profile contain instructions on how to connect to the server and the software to make a connection. This can be done using the Client UI or by generating and distributing the client installer via the command line tools. Note: you must use the instructions to create server-locked profiles/installers for external PKI integration.
- Certificate/key — the client certificate/key generated by a third-party tool. This third-party tool manages the external PKI solution. The tool generates the client certificates/keys and installs them on client machines using the host OS certificate/key store — iOS, macOS, Android Keychain, Windows certificate store, or Linux OpenSC. For a standard Access Server setup, not using external PKI, Access Server bundles the certificate/key with the connection profile. External PKI requires them to be separate
When operating in external PKI mode, Access Server only supports server-locked profiles, not user-locked profiles. For the VPN client, the server-locked profile must have a client certificate/key pair installed into the host OS keychain or certificate/key store in order to make a VPN tunnel connection. Some hardware devices or tokens contain a certificate inside that is registered with the certificate store using additional software when the token device/card is plugged in.
OpenVPN Connect does not require direct access to the private key, as it is capable of performing RSA operations on the key via the CSP (cryptographic service provider) API provided by the host OS Keychain. This allows the use of cryptographic tokens or smartcards with the private key, which makes it physically impossible for any software running on the client machine (even at root/Administrator level) to directly read the key.
Note: OpenVPN Support for external PKI systems with Access Server is limited. This is because much of the system is dependent on how the system administrator sets it up, that the external PKI mode disables many of the internal certificate management functions of Access Server, and that there is a third-party product involved and we have no control over that external system.
Configure external PKI for Access Server
When you use a third-party tool outside of Access Server, you must refer to the documentation for that software for specific directions. Here we outline the steps and provide an example using Access Server's certool script. With certool, you can create your own, new PKI structure, as we do in these instructions.
At a high level, these are the steps for your configuration:
- Create certificate/key pair with external PKI tool.
- Modify as.conf to set Access Server in external PKI mode.
- Create TLS_auth key.
- Generate Diffie Hellman parameters.
- Import the necessary certificate and key files.
- Provide certificate/key pairs to VPN client and server.
When you configure your Access Server in production, follow these high-level steps using your third-party PKI tool. We provide our example, below, using Access Server’s certool script so the steps pertain to that tool.
Here's how we configure external PKI using Access Server's certool script.
Stop Access Server:
service openvpnas stop
Edit as.conf for external PKI usage with a text editor such as nano:
Comment out certs_db:
# certificates database #certs_db=sqlite:///~/db/certs.db
Save and exit the file — with nano, hit ctrl+X, Y, then enter. After making this change, Access Server no longer uses the certificate database. Instead, an external system must handle this.
Initialize the external PKI files in the epki directory, including the CA cert/key:
cd /usr/local/openvpn_as/scripts mkdir -p epki/root
Create a root cert for signing intermediate CAs:
./certool --dir epki/root --cn "EPKI Root Test" --type ca
Create the intermediate CA:
./certool --dir epki/root --type intermediate --serial 1 --cn "EPKI Intermediate" --name inter cp epki/root/inter.crt epki/ca.crt cp epki/root/inter.key epki/ca.key cat epki/root/ca.crt epki/ca.crt >epki/cabundle.crt
Create a certificate/key pair for the OpenVPN server:
./certool --dir epki --type server --serial 1 --cn server
Create a tls_auth key for the OpenVPN server:
./certool --dir epki --tls_auth
Generate Diffie Hellman parameters for the OpenVPN server:
openssl dhparam -out epki/dh.pem 2048
Load the newly generated files into the Access Server config database:
./confdba -mk external_pki.ta_key --value_file epki/ta.key ./confdba -mk external_pki.ca_crt --value_file epki/cabundle.crt ./confdba -mk external_pki.server_crt --value_file epki/server.crt ./confdba -mk external_pki.server_key --value_file epki/server.key ./confdba -mk external_pki.dh_pem --value_file epki/dh.pem
For Access Server 2.7 and greater, you must also generate your auth token and add the generated file:
./certool --dir epki --auth_token ./confdba -mk external_pki.auth_token_key --value_file epki/auth_token.key
Configure X509 explicit/extended key usage based on RFC3280 TLS Rules:
./confdba -mk external_pki.remote_cert_usage -v eku
Configure use of the X509 “role” attribute for declaration of auto-login permission:
./confdba -mk external_pki.autologin_x509_spec -v "role,,AUTOLOGIN"
Beginning with Access Server version 2.9.0, generate the tls-crypt-v2 key. Skip this step for previous versions.
./certool --dir epki --tls_crypt2_server ./confdba -mk external_pki.tls_cryptv2_server --value_file epki/tls_crypt2.key
Start Access Server:
service openvpnas start
Note: When using an external PKI tool, make sure to designate all certificates generated by your PKI management tool as being explicitly client or server. This protects against a particular type of man-in-the-middle attack where a client certificate could be used to impersonate the server. There are two ways to do this:
- X509 explicit/extended key usage based on RFC3280 TLS rules. Configure as follows:
./confdba -mk external_pki.remote_cert_usage -v eku
- Netscape certificate type (deprecated). Configure as follows:
./confdba -mk external_pki.remote_cert_usage -v nsor for version 2.9.0 and later,
./confdba -mk external_pki.remote_cert_usage -v ns-cert
Configure a test client
To test our example, generate a test client, etest. Create the username and password for etest. To do this in the Admin Web UI, sign in, click User Management > User Permissions, then create the username and enter the password. Click Save and Update Running Server. This works for Local authentication. For PAM, LDAP, or RADIUS, create the test user in the appropriate location.
Generate a cert/key pair for etest — the key is encrypted with a password you enter at the prompt and certool generates the file epki/etest.p12 which contains the cert/key pair:
./certool --dir epki --type client --serial 2 --cn etest --cabundle epki/cabundle.crt --pkcs12
To test auto-login, generate an auto-login cert/key pair for etest:
./certool --dir epki --type client --serial 3 --cn etest --name etestauto --cabundle epki/cabundle.crt --pkcs12 role=AUTOLOGIN ./sacli --user etest --key prop_autologin --value true UserPropPut
Finally, generate a server-locked profile. The profile will be stored in client.ovpn:
./sacli GetGeneric >client.ovpn
Copy these three files to the client machine:
|epki/etest.p12:||The userlogin cert/key pair for user etest|
|epki/etestauto.p12:||The autologin cert/key pair for user etest|
|client.ovpn:||The server-locked profile for the Access Server|
In a production setting, the client cert/key pairs (the .p12 files) are distributed to clients using the external PKI tool. The client.ovpn is distributed in the same manner as existing server-locked profiles:
- Using OpenVPN Connect.
- Using a client software push capability — for example, on macOS, you can generate a pre-configured client installer, ‘DMG’, with the server-locked profile:
./sacli --itype dmg -o . GetGenericInstaller
To install the certificate/key pair:
- Start the Keychain Access application.
- Go to File > Import Items.
- Import each .p12 file — to decrypt the file, you must enter the password from when you generated the file.
- Go to Tools > Internet options.
- Click the Content tab.
- Click the Certificates button.
- Click “Import” to import the .p12 files.
To import the server-locked profile and connect:
capi -f client.ovpn importprofile capi -D -i <PROFILE_ID> -u etest -p <PASSWORD> Connect
Note: If using an auto-login profile, omit the -u and -p parameters from the command above. For our example, the auto-login requires importing the epki/etestauto.p12 into the system certificate store.
During the connection process, the system certificate store may launch a dialog box. On Windows, this may start in a minimized state rather than popping up as it comes from the system certificate store and OpenVPN Connect doesn’t control how it displays. Click it to fully open and approve it in order to complete the connection.
VPN client support
OpenVPN Connect supports the macOS Keychain and the Windows certificate store as valid sources to fetch the client certificate.
When the user attempts to connect using a profile setup for external PKI, the client backend enumerates the user's host OS certificate store and automatically selects the certificate/key pair issued by OpenVPN Access Server. If more than one certificate/key pair is eligible, the certificate with the latest expiration date is used.
Certificate naming conventions
Currently, the Access Server uses the following client certificate naming conventions:
- The Common Name of the certificate must match the username of the connecting client.
- Autologin certificates, which don't require username/password authentication (only client certificate authentication), must be tagged to indicate that they hold this right. In the above example, note that the X509 role attribute is set to AUTOLOGIN. Then we modify Access Server’s configuration to indicate that autologin is enabled if the X509 "role" attribute contains the "AUTOLOGIN" substring:
./confdba -mk external_pki.autologin_x509_spec -v "role,,AUTOLOGIN". If external_pki.autologin_x509_spec is omitted, all auto-login access is disabled. The external_pki.autologin_x509_spec string is formatted as follows: <X509 Attribute>,<optional flags>,<enabling substring in attribute value> The flags parameter is reserved for future use and is currently unimplemented. So, for example, if external_pki.autologin_x509_spec is set to "role,,AUTOLOGIN", as the confdba command above does, then Access Server would only allow auto-login connections from client certificates where the "role" X509 attribute is present and the substring "AUTOLOGIN" exists within the "role" value.
Split CA, i.e. using a separate CA chain for client and server certificates
By default, one CA chain is assumed for both client and server certificates. To use a separate chain for each, first enable split CA mode:
./confdba -mk external_pki.remote_cert_usage -v split
Next, replace the following line (from above):
./confdba -mk external_pki.ca_crt --value_file <CA_CERT_BUNDLE>
./confdba -mk external_pki.server_ca_crt --value_file <SERVER_CA_CERT_BUNDLE> ./confdba -mk external_pki.client_ca_crt --value_file <CLIENT_CA_CERT_BUNDLE>
When using split CA mode, you don’t need to mark certificates as client or server. Therefore, settings for Netscape certificate type or X509 explicit/extended key usage based on RFC3280 TLS rules can be omitted.
Controlling CN/username requirement
By default, client logins must use a username that matches the Common Name on the client certificate. This requirement may be dropped by disabling the external_pki.cn_username_requirement boolean key:
./sacli -k external_pki.cn_username_requirement -v false ConfigPut
Controlling which certificate store the client uses to fetch the client certificate
By default, the client fetches certificates from the "user" store. This corresponds to the user's ~/Library/Keychains/login.keychain store on Mac, and the "MY" store on Windows. On Mac, the store can be selected on the server using the user properties key "cert_store". Set it to "user", "system", or "both" to explicitly control the store that clients use:
|both:||try system keychain, then fall back to user|
For example, set the store to "both":
./sacli --user __DEFAULT__ --key cli_cert_store --value "both" UserPropPut
"'Parameter \"external_pki.auth_token_key\" is missing from the configuration database. For more information, please visit the following URL: https://openvpn.net/static-links/documentation-external-pki': util/cdict:286,util/cdict:258,util/cdict:522,util/cdict:555 (exceptions.KeyError)"
This error message occurs when upgrading an Access Server that’s configured for external public key infrastructure (ePKI) from a version lower than 2.7 to version 2.7 and higher. This is expected behavior because this configuration key was missing for versions prior to 2.7 and must be added after you upgrade. Note that you’ll also see “service failed to start or returned error status” in your log messages.
This error can be resolved by running these commands with root privileges:
cd /usr/local/openvpn_as/scripts ./certool --dir epki --auth_token ./confdba -mk external_pki.auth_token_key --value_file epki/auth_token.key
Then restart the service:
service openvpnas start