- TLS-Auth
- Diffie Hellman Parameters
- Client Config Directory
- Persistent Pool IP
- TLS Verify
- Example Server Config
- Example Client Config
Some general stuff to secure openVPN
TLS-Auth
Use a pre-shared key on both, server and client to secure the connection
Create the key
openvpn --genkey --secret /etc/openvpn/ta.key
Activate TLS key on server, edit server.conf
tls-auth ta.key 0
tls-server
Deploy the ta.key to all clients, edit client.conf
tls-auth ta.key 1
tls-client
Diffie Hellman Parameters
Create the dhparam key for the server.
openssl dhparam -out /etc/openvpn/dh2048.pem 2048
Add it to the server.conf
dh dh2048.pem
Do the same for all clients.
Be sure to create own dhparams keys for each client.
Add the same line to the client.conf files as above shown for server.conf
Client Config Directory
You can define a client-config-dir where you can put client specific configurations.
This can be used to assign static IP addresses to clients or such.
Add to your server.conf
client-config-dir ccd
route 10.10.0.252 255.255.255.252
Add the following to the to a file in ccd directory, name that file the same as the CommonName (CN) of the connecting client.
Assuming the certificate of the connecting client has a CN of ovpn_Thor.Himself create the file /etc/openvpn/ccd/ovpn_Thor.Himself and add the following line
ifconfig-push 10.10.0.253 10.10.0.254
This will assign ip 10.10.0.254 to the server interface and 10.10.0.253 to the clients tunnel interface.
So, if a clients connects our openVPN server and has a certificate that has been signed by our CA and a CN of ‘ovpn_Thor.Himself’ the client will get IP 10.10.253 on every connect.
Every traffic to network 10.10.0.252/30 will be routed into the tunnel interface.
Persistent Pool IP
You can also assign static IP addresses out of the dynamic pool
Add the following to your server.conf
ifconfig-pool-persist ipp.txt
And create the file /etc/openvpn/ipp.txt and list the clients and their IP one per line
Omit the ‘,<IPv6>’ in each line if you have an IPv4 only setup.
# Syntax
# <CN>,<IPv4>,<IPv6>
ovpn_Thor.Himself,192.168.192.2,2a03:a:609:f999::1002
ovpn_Sif.Herself,192.168.192.3,2a03:a:609:f999::1003
ovpn_Other.User,192.168.192.4,2a03:a:609:f999::1004
TLS Verify
This is mainly to temporary block users from connecting to our server.
Assuming that someone is a longer time out of office, let’s say on maternity leave, and you don’t want to revoke her certificate from the CA completely you can use something like ‘tls-verify’
You need to write a script to do the actual validation.
I’m using the following script putting it into file /etc/openvpn/openvpn-verify-cn
Be sure to make it executable!
#!/usr/bin/perl
# verify-cn -- a sample OpenVPN tls-verify script
#
# Return 0 if cn matches the common name component of
# X509_NAME_oneline, 1 otherwise.
#
# For example in OpenVPN, you could use the directive:
#
# tls-verify "./verify-cn Test-Client"
#
# This would cause the connection to be dropped unless
# the client common name is "Test-Client"
die "usage: verify-cn cn certificate_depth X509_NAME_oneline" if (@ARGV != 3);
# Parse out arguments:
# cn -- The common name which the client is required to have,
# taken from the argument to the tls-verify directive
# in the OpenVPN config file.
# depth -- The current certificate chain depth. In a typical
# bi-level chain, the root certificate will be at level
# 1 and the client certificate will be at level 0.
# This script will be called separately for each level.
# x509 -- the X509 subject string as extracted by OpenVPN from
# the client's provided certificate.
($cnfile, $depth, $x509) = @ARGV;
my @CNs;
open(IN, "<$cnfile") or die("Unable to open CN file: $!\n");
while (<IN>) {
chomp;
next if ($_ =~ /^#/);
next if ($_ eq '');
push(@CNs, $_);
}
close(IN);
if ($depth == 0) {
# If depth is zero, we know that this is the final
# certificate in the chain (i.e. the client certificate),
# and the one we are interested in examining.
# If so, parse out the common name substring in
# the X509 subject string.
if ($x509 =~ /\/CN=([^\/]+)/) {
# Accept the connection if the X509 common name
# string matches the passed cn argument.
my $x509_cn = $1;
foreach my $validCn (@CNs) {
if ($x509_cn =~ m/^${validCn}$/s) {
exit 0;
}
}
}
# Authentication failed -- Either we could not parse
# the X509 subject string, or the common name in the
# subject string didn't match the passed cn argument.
exit 1;
}
# If depth is nonzero, tell OpenVPN to continue processing
# the certificate chain.
exit 0;
Create the file /etc/openvpn/valid-CNs and add the CommonNames of the certificates you want to enable login for
ovpn_Thor.Himself
ovpn_Sif.Herself
ovpn_Other.User
Now add the next line to your server.conf
tls-verify "/etc/openvpn/openvpn-verify-cn /etc/openvpn/valid-CNs"
At that point in time (after restart of openVPN server for sure!) our server will only accept logins by certificate that are signed by our CA and that are NOT revoked and the common name of the certificate MUST be listed in file /etc/openvpn/valid-CNs
This way you can block access temporarily by simply removing the CN of the user certificate from the valid-CNs file instead of revoking the certificate and deploy a new certificate once the user gets back to work.
Example Server Config
port 1194
proto udp
dev tun0
tls-server
tls-version-min 1.2
tls-auth ta.key 0 # use '1' for client side
ca /etc/openvpn/pki/ca.crt
cert server.crt
key server.key # This file should be kept secret
dh dh2048.pem
topology subnet
server 192.168.192.0 255.255.255.0
ifconfig-pool-persist ipp.txt
client-config-dir ccd/
push "route 192.168.192.0 255.255.255.0"
push "dhcp-option DNS 192.168.192.1"
keepalive 10 120
auth SHA256
cipher AES-256-CBC
tls-verify "./verify-cn ./allowedClientCNs"
script-security 2
max-clients 10
user nobody
group nobody
persist-key
persist-tun
status openvpn-status.log
verb 3
explicit-exit-notify 1
client-to-client
### enable tun6
server-ipv6 2a03:a:609:f999::/64
proto udp6
tun-ipv6
push tun-ipv6
push "route-ipv6 2a03:a:609:f999::/64"
push "dhcp-option DNS 2a03:a:609:f999::1"
push "dhcp-option DNS 2a03:a:609:f966:53::"
Example Client Config
client
remote vpn.thor.de 1194
proto udp
dev tun
persist-key
persist-tun
resolv-retry infinite
nobind
cipher AES-256-CBC
auth SHA256
key-direction 1
tls-client
tls-version-min 1.2
verb 3
### Deploy client keys by config file ###
<ca>
-----BEGIN CERTIFICATE-----
MIIDNTCCAh2gAwIBAgIJAJsAewXy19vjMA0GCSqGSIb3DQEBCwUAMBYxFDASBgNV
<snipp/>
l0GH1zOpZx0K
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
MIIDgjCCAmqgAwIBAgIQHSc7Pn37zew1+GFA9PFuTDANBgkqhkiG9w0BAQsFADAW
<snipp/>
OcIk44Umb3BfW+0B7AcSZHMKcMYFzPkczXWVh0FtEsWkaPEiCyc=
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCt/M1FD91s9e5T
<snipp/>
mENovB7jphbFGz2pRLL7IwU=
-----END PRIVATE KEY-----
</key>
<tls-auth>
-----BEGIN OpenVPN Static key V1-----
8b95fd6352617c07676fc997a6cbc649
<snipp/>
ee653470371e2d088e44772ffb5a9252
-----END OpenVPN Static key V1-----
</tls-auth>