A reasonably secure OpenVPN configuration

OpenVPN is one of those great open source success stories. It is used in many organisations and almost single handedly powers the whole VPN market segment. OpenVPN 2.4.0 was independently audited for security vulnerabilities twice. There are mature clients for almost any operating system making it an appealing choice as either remote access server or for extending private networks.

Using a minimal configuration OpenVPN will select a sensible set of defaults that will work well in many scenarios. However there are quite a few configurable options that provide additional defenses and are hardening OpenVPN’s security. These could be desirable properties depending on your internal security, or regulatory, requirements.

The following is our current OpenVPN server template. Each organisation has different requirements and this template should be reviewed and tailored for every specific environment. Lines starting with a hash or semicolon are remarks. Some of the configuration options are described in more detail below the template.

# Port to listen on
port 13210

# Protocol to use
proto udp4

# Virtual network device
dev tun

# CA and CRL
ca /etc/openvpn/ca.crt
;crl-verify /etc/openvpn/crl.pem

# Server certificate and key
cert /etc/openvpn/server/server.crt
key /etc/openvpn/server/server.pem

# Configure server role and allocate addresses out of the given network
server 10.198.149.0 255.255.255.192

# Use a subnet rather than point-to-point topology
topology subnet

# Persist ifconfig-pool data to file, at seconds intervals
ifconfig-pool-persist ipp.txt 600

# Instruct client to redirect default gateway to the VPN
;push "redirect-gateway def1"

# Ping if inactive for 20 seconds and trigger a SIGUSR1 restart after 180 seconds without reception of a ping
keepalive 20 180

# Require that peer certificate was signed with explicit client key usage
remote-cert-tls client
;remote-cert-eku 'TLS Web Client Authentication'

# Verify fingerprint of the CA (or intermediate cert) that signed the peer's certificate
verify-hash CB:33:3F:AC:BE:8E:FB:F8:CB:F2:44:35:55:01:A2:B4:40:94:90:3B:A2:11:E2:11:51:08:09:03:51:C3:ED:F8 SHA256

# File containing Diffie Hellman parameters
dh /etc/openvpn/server/dh2048.pem

# Key to authenticate and encrypt the TLS control channel
tls-crypt /etc/openvpn/server/tls.key

# Set the minimum TLS version we will accept from the peer
tls-version-min 1.2

# Allowable ciphers for TLS 1.2 (or lower)
tls-cipher TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256

# Allowable ciphers for TLS 1.3
tls-ciphersuites TLS-CHACHA20-POLY1305-SHA256:TLS-AES-256-GCM-SHA384:TLS-AES-128-GCM-SHA256

# Allowable ciphers to negotiate for the data channel
ncp-ciphers AES-256-GCM:AES-256-CBC:AES-128-GCM:AES-128-CBC

# When negotiation is disabled use this cipher
cipher AES-128-GCM

# Digest algorithm for HMAC authentication
auth SHA1

# Silence the output of replay warnings, which are a common false alarm on WiFi networks
mute-replay-warnings

# Change to this user ID after initialization
user nobody

# Change to this group ID after initialization
group nobody

# Don’t re-read key files across SIGUSR1 because privileges were dropped
persist-key

# Don’t close/reopen TUN/TAP device or run scripts across SIGUSR1 because privileges were dropped
persist-tun

# Output verbosity
verb 3

# Restrict usage of external programs and scripts
script-security 1

# Notify clients when the server restarts
explicit-exit-notify 1

port: The default OpenVPN port is 1194. Running software on a non-standard port can reduce noise in the logs from automated scans or drive-by brute-force attempts. It may also avoid some generic monitoring or blocking. However it does not offer any additional protections against a targeted reconnaissance or attack.

proto: When possible UDP is the preferred transport for VPN connections. Tunneling TCP over TCP is generally considered a bad idea. We specify IPv4 to avoid ambiguity in dual stacked environments.

crl-verify: OpenVPN 2.4 uses the SSL/TLS library’s CRL validation which is stricter than before. Now the CA must match the issuer of the CRL and the CRL cannot be expired. While there are no revoked certificates it is possible to leave the crl-verify option remarked so there is no need to track the expiry date and update an empty CRL. However that would also mean reconfiguring OpenVPN and implementing the update process if you do have to use it later down the track.

topology: In subnet topology, the tun device is configured with an IP and netmask like a “traditional” broadcast-based network. This allows better utilization of IP space. It is safe and recommended to use subnet topology when no old/outdated clients exist that are running OpenVPN 2.0.9 under Windows.

ifconfig-pool-persist: Persist ifconfig-pool data to file. The goal of this option is to provide a long-term association between clients and the virtual IP address assigned to them from the ifconfig-pool. Maintaining a long-term association is good for clients because it allows them to effectively use the “persist-tun” option. Note that the entries in this file are treated by OpenVPN as suggestions only, based on past associations between a common name and IP address. They do not guarantee that the given common name will always receive the given IP address.

keepalive: Ping remote over the control channel if inactive for the set number of seconds and trigger a SIGUSR1 restart after the timeout value without reception of a ping. This directive is pushed to the client as well and does not have to be specifically set there. The timeout will be twice as long on the server side. This ensures that a timeout is detected on client side before the server side drops the connection.

remote-cert-tls: Require that peer certificate was signed with an explicit key usage and extended key usage based on RFC3280 TLS rules. This is an important security precaution to protect against a man-in-the-middle attack. The “remote-cert-eku” option is an alternative equivalent notation.

verify-hash: Specify the fingerprint and algorithm of the CA, or intermediate, certificate that signs the client’s certificate. Of course OpenVPN already has the CA certificate, and therefore fingerprint, that signed the server certificate. This option is useful when managing multiple CA’s or intermediates and as an additional check for automated configuration management/deployments. You can extract the fingerprint with: [openssl x509 -noout -fingerprint -sha256 -inform pem -in ca.crt].

dh: File containing Diffie Hellman parameters. Fundamentally, Diffie Hellman allows two users to exchange a secret key over an insecure medium without any prior secrets. Set “none” to disable Diffie Hellman key exchange and use ECDH only. Note that this requires peers to be using an SSL library that supports ECDH TLS (also see tls-cipher). Use [openssl dhparam --out /etc/openvpn/server/dh2048.pem 2048] to generate 2048-bit DH parameters. You can generate larger sizes which will take significantly longer and increase computational usage cost. Currently 2048 bit is generally expected to be safe.

tls-crypt: Authenticate and encrypt all control channel packets with this key. This includes packets which are sent before the TLS level has had a chance to authenticate the peer. The result is that with unauthorized connections even the first packet can be dropped immediately upon reception, before they have a chance to consume additional system resources such as initiating a TLS handshake. This feature is optional and the key file used gives a peer nothing more than the power to initiate a TLS handshake. It is not used to encrypt or authenticate any tunnel data.
The same denial of service protection is provided by the tls-auth option which uses the exact same key file. The tls-crypt option provides more privacy by hiding the certificate used for the TLS connection and makes it harder to identify OpenVPN traffic as such. Use [openvpn --genkey secret /etc/openvpn/server/tls.key] to generate your own.

tls-cipher & tls-ciphersuites: Allowable TLS ciphers that can be negotiated for the TLS connection. There are two separate options due to changes in OpenSSL for TLS 1.3. These are advanced options that can also reduce your security or break the connection. OpenVPN 2.4 and newer limits the default cipher list more than earlier versions did and will negotiate a secure cipher by default. The main considerations for using these options are to prevent undesirable ciphers intentionally being used by client side configuration changes or to meet internal security, or regulatory, requirements. You can check the available ciphers on your platform with: [openvpn --show-tls].

ncp-ciphers: Allowable ciphers that can be negotiated for the data channel. Without any cipher directive OpenVPN v2.4 client/server will automatically try to negotiate AES-256-GCM in TLS mode. As with the tls ciphers the main considerations here are to prevent undesirable ciphers being used by client side configurations or to meet internal security, or regulatory, requirements. You can check the available ciphers on your platform with: [openvpn --show-ciphers].

cipher: The cipher to be used when negotiation is disabled by the client. Again a safeguard to prevent the use of undesirable ciphers. However this can also be useful to define the preferred cipher for equipment on small sites, or IoT devices, with limited cpu capabilities.

auth: Authenticate data channel packets and, if enabled, tls-auth control channel packets with HMAC using this message digest algorithm. While SHA1, the OpenVPN default, has been deprecated for most uses it is still safe to use with HMAC (because HMAC is less affected by collisions than the underlying hashing algorithms alone). Using a larger hash size increases computational and bandwidth usage cost. For example SHA1 produces a 160-bit (20-byte) and SHA256 a 256-bit (32-byte) hash value. Use [openvpn –show-digests] to check the available algorithms.

user & group: Drop root privileges after startup by changing to these uid and gid. The actual uid and gid differ per platform.

The following is our current OpenVPN client template. This template should also be reviewed and tailored to individual requirements before use. We keep the client configuration minimal and where possible let the server push the options. This often makes it easier to manage change later. Some of the configuration options are described in more detail below the template.

# Configure client role
client

# Virtual network device
dev tun

# Don't cache credentials in virtual memory
auth-nocache

# Remote host name or IP address, port and protocol
remote dvpn.takala.consulting 13210 udp4

# Number of seconds to wait between connection attempts and max wait
connect-retry 60 600

# How long to retry if hostname resolve fails
resolv-retry infinite

# Do not bind to local address and port
nobind

# Don't re-read key files across SIGUSR1 because privileges were dropped
persist-key

# Don't close/reopen TUN/TAP device or run scripts across SIGUSR1 because privileges were dropped
persist-tun

# CRL
;crl-verify /etc/openvpn/crl.pem

# Require that peer certificate was signed with explicit server key usage
remote-cert-tls server
;remote-cert-eku 'TLS Web Server Authentication'

# Verify fingerprint of the CA (or intermediate cert) that signed the peer's certificate
verify-hash CB:33:3F:AC:BE:8E:FB:F8:CB:F2:44:35:55:01:A2:B4:40:94:90:3B:A2:11:E2:11:51:08:09:03:51:C3:ED:F8 SHA256

# Match the peer's certificate subject
verify-x509-name 'C=JP, O=Takala Consulting, CN=dvpn.takala.consulting, role=VPN Server' subject

# Disable cipher negotiation
;ncp-disable

# Use this cipher when negotiation is disabled
cipher AES-128-GCM

# Digest algorithm for HMAC authentication
auth SHA1

# Output verbosity
verb 3

# PKCS #12 file containing private key, certificate, and root CA certificate
pkcs12 /etc/openvpn/client/alfred@takala.consulting.p12

# Key to authenticate and encrypt the TLS control channel
<tls-crypt>
-----BEGIN OpenVPN Static key V1-----
28c67c8eddbe68fb9ccc462a0e325a18
7cd7a9497081e98d12684ce7691011b0
bfba38f6f16079608c71a49d2e850f2c
4bb3b6ae66d774bb77c01172f54884ef
eb5cbc9463d026e604d1ed2a0394dcf7
949369f16f80040b3050bf6e666c2037
3c687782f952ae8b822e7294f5b2618a
d551e98535619f9bf95792fe9406c183
29801a3fd06e2b1997838a0f31d14966
51e9c1d02c90514b5c03a5cb25780424
fa966afb59157c990b343148ca11a9bc
86a14cb002d0132e2f136609d139e2ab
351afac9d71c87aaba2e9be378abf529
288f0fe79a2132662b53e11a5a53aa19
75d954eb8d1e7446ebe13d3aa0f5a541
83e6ba849b0f877b93344e595cb6f98f
-----END OpenVPN Static key V1-----
</tls-crypt>

# Restrict usage of external programs and scripts
script-security 1

verify-x509-name: Verify the server’s certificate subject to make sure we are connecting to the expected server. As this option is more specific you can safely omit the remote-cert-tls option. You can find the subject with: [openssl x509 -in server.crt -text -noout | grep Subject].

ncp-disable: Completely disable cipher negotiation and use what is defined in the cipher option (also see the cipher description under the server template).

pkcs12: OpenVPN supports a few ways to store certificates and keys. In the server template we used separate files for each. Storing everything inline is also a convenient option especially when automatically generating configurations. In this example we use a PKCS #12 archive which allows us to store all certificates and private key in an encrypted, password protected, format. This option is not available with mbed TLS.

tls-crypt: The same key we generated on the server except stored inline with the client configuration.

auth: This must match the server configuration (also see the auth description under the server template).

Security Considerations

All peers use the same “tls-crypt” pre-shared group key to authenticate and encrypt control channel messages. To ensure that IV collisions remain unlikely, this key should not be used to encrypt more than 2^48 client-to-server or 2^48 server-to-client control channel messages. This limits the tls-crypt key lifetime to a ballpark figure of 8171 years divided by the number of users. So a setup with 1000 users should rotate the key at least once each eight years. (And a setup with 8000 users each year.)

If IV collisions were to occur, this could result in the security of “tls-crypt” degrading to the same security as using “tls-auth”. That is, the control channel still benefits from the extra protection against active man-in-the-middle-attacks and DoS attacks, but may no longer offer extra privacy and post-quantum security on top of what TLS itself offers.

Using “verify-x509-name” is a useful alternative to managing a CRL (Certificate Revocation List) on the client, since it allows the client to refuse all certificates except for those associated with designated servers.

You can always contact us for additional help and more specific configurations.

Takala Consulting
Excellence begins here