The Background
Recently I’ve set up an OpenVPN (Community Edition 2.4.11) server on a CentOS 7 box. While there were multiple1 resources2 that3 helped4 immensely in getting the task done, below is the process that was actually followed.
Configuring EasyRSA and Generating the Server Keys
Once we have a CentOS 7 box up and running, we can start by enabling the EPEL repository and optional extras.
yum install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
subscription-manager repos --enable "rhel--optional-rpms" --enable "rhel--extras-rpms" --enable "rhel-ha-for-rhel-*-server-rpms"
Then, we can install openvpn and easy-rsa5 as below.
yum install openvpn easy-rsa
Next, we’ll need to create a Public Key Infrastructure6. The Certificate Authority7 machine involved is recommended to be separate from the OpenVPN server, but I’ve used the same box since the setup was required only for testing purposes. Hence, I copied the easy-rsa
(v3.0.8) installation directory to the /etc/openvpn
directory.
cp -r /usr/share/easy-rsa /etc/openvpn/
Then we can create a file called vars
include config variables within that directory (i.e. /etc/openvpn/easy-rsa/3/vars
). An example of the content I used there is as follows.
set_var EASYRSA "$PWD"
set_var EASYRSA_PKI "$EASYRSA/pki"
set_var EASYRSA_DN "cn_only"
set_var EASYRSA_REQ_COUNTRY "ID"
set_var EASYRSA_REQ_PROVINCE "EXAMPLE PROVINCE"
set_var EASYRSA_REQ_CITY "EXAMPLE CITY"
set_var EASYRSA_REQ_ORG "EXAMPLE ORG"
set_var EASYRSA_REQ_EMAIL "example@hsen.tech"
set_var EASYRSA_REQ_OU "EXAMPLE OU"
set_var EASYRSA_KEY_SIZE 2048
set_var EASYRSA_ALGO rsa
set_var EASYRSA_CA_EXPIRE 7500
set_var EASYRSA_CERT_EXPIRE 365
set_var EASYRSA_NS_SUPPORT "no"
set_var EASYRSA_NS_COMMENT "EXAMPLE COMMENT"
set_var EASYRSA_EXT_DIR "$EASYRSA/x509-types"
set_var EASYRSA_SSL_CONF "$EASYRSA/openssl-1.0.cnf"
set_var EASYRSA_DIGEST "sha256"
Now, let’s get into the business of creating the required keys for cryptographic purposes. Enter a pass phrase for the PEM8 file when prompted.
chmod u+x vars
./easyrsa init-pki
./easyrsa build-ca
Above will generate and save the ca.crt
and ca.key
inside /etc/openvpn/easy-rsa/3/pki/
. Generating a key pair for the server can be accomplished with the below command (nopass
is to leave the private key unencrypted). Signing the generated private key, and verifying the activity with OpenSSL[^9] can be done as shown below (i.e. hsen-openvpn
is the certificate name).
./easyrsa gen-req hsen-openvpn nopass
./easyrsa sign-req server hsen-openvpn
openssl verify -CAfile pki/ca.crt pki/issued/hsen-openvpn.crt
Once above is done, we’ll have the server private key and certificate files in pki/private/hsen-openvpn.key
and pki/issued/hsen-openvpn
directories (i.e. inside /etc/openvpn/easy-rsa/3/pki/
) respectively.
Generating the Client Keys and Similar
In order for us to connect to the OpenVPN server as a client, we’ll need to perform authentication. For that, let’s create a key and sign it, then verify the activity (i.e. client-1
is the client key name).
./easyrsa gen-req client-1 nopass
./easyrsa sign-req client client-1
openssl verify -CAfile pki/ca.crt pki/issued/client-1.crt
A key to be used in Diffie-Hellman9 exchange which would be carried out in conjunction10 with the certificate based authentication shall be created along with a Certificate Revoking List (pretty self explanatory, wouldn’t you say?) shall be generated with the below commands.
./easyrsa gen-dh
./easyrsa gen-crl
Once above is done, two files, namely dh.pem
and crl.pem
will be present inside the pki/
directory.
After above, we may copy the created files to suitable locations for better organization and ease.
cp pki/ca.crt /etc/openvpn/server/
cp pki/issued/hsen-openvpn.crt /etc/openvpn/server/
cp pki/private/hsen-openvpn.key /etc/openvpn/server/
cp pki/ca.crt /etc/openvpn/client/
cp pki/issued/client-1.crt /etc/openvpn/client/
cp pki/private/client-1.key /etc/openvpn/client/
cp pki/dh.pem /etc/openvpn/server/
cp pki/crl.pem /etc/openvpn/server/
Configuring the OpenVPN Server
Let’s create a file for including the OpenVPN server configurations as follows (i.e. /etc/openvpn/server.conf
).
# OpenVPN Port, Protocol and the Tun
port 1194
proto udp
dev tun
# OpenVPN Server Certificate - CA, server key and certificate
ca /etc/openvpn/server/ca.crt
cert /etc/openvpn/server/hsen-openvpn.crt
key /etc/openvpn/server/hsen-openvpn.key
#DH and CRL key
dh /etc/openvpn/server/dh.pem
crl-verify /etc/openvpn/server/crl.pem
# Network Configuration - Internal network
# Redirect all Connection through OpenVPN Server
server 172.16.1.0 255.255.255.0
push "redirect-gateway def1"
# Using the Cloudflare DNS
push "dhcp-option DNS 1.1.1.1"
#Enable multiple client to connect with same Certificate key
duplicate-cn
# TLS Security
cipher AES-256-CBC
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256
auth SHA512
auth-nocache
# Other Configurations
keepalive 20 60
persist-key
persist-tun
comp-lzo yes
daemon
user nobody
group nobody
# OpenVPN Log
log-append /var/log/openvpn.log
verb 3
Changing the Server Network Configuration
We shall now enable port forwarding, make necessary changes to the firewall, and enable Network Address Translation between the OpenVPN internal IP and the external IP that is assigned to the CentOS 7 box (i.e. W.X.Y.Z
is the external IP).
echo 'net.ipv4.ip_forward = 1' >> /etc/sysctl.conf
sysctl -p
firewall-cmd --permanent --add-service=openvpn
firewall-cmd --permanent --zone=trusted --add-interface=tun0
firewall-cmd --permanent --zone=trusted --add-masquerade
firewall-cmd --permanent --direct --passthrough ipv4 -t nat -A POSTROUTING -s 172.16.1.0/24 -o W.X.Y.Z -j MASQUERADE
firewall-cmd --reload
Once the above is done, we may start the OpenVPN daemon, and then check how it’s doing.
systemctl start openvpn@server
ss -tulpn
systemctl status openvpn@server
Configuring the OpenVPN Client
Since we already have the client keys created for client-1
, we can copy those (i.e. inside client/
directory in /etc/openvpn
) to a potential OpenVPN client machine and create a configuration file there so we can use that when establishing a connection with the OpenVPN server. A sample configuration to use from the same directory as the copied files would be as follows (i.e. client-1.ovpn
).
client
dev tun
proto udp
remote W.X.Y.Z
remote-cert-tls
ca ca.crt
cert client-1.crt
key client-1.key
cipher AES-256-CBC
auth SHA512
auth-nocache
tls-version-min 1.2
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256
resolv-retry infinite
compress lzo
nobind
persist-key
persist-tun
mute-replay-warnings
verb 3
Establishing the Connection and Closing Thoughts
Now, what is left to be done is initiating the VPN connection with the server from the client machine. If we are using a Linux terminal on the client, the process is as simple as entering the command that follows.
sudo openvpn --config client-1.ovpn
Also, most Linux desktop environments provide options for conveniently setting up an OpenVPN connection. On Windows, one may use the official OpenVPN client application while on MacOS one might use Tunnelblick .
The above process covers the steps for setting up an OpenVPN server instance that is just operational. If you intend to use the server in a production environment, it is advisable to follow the recommended security routines and procedures among others.
https://www.howtoforge.com/tutorial/how-to-install-openvpn-server-and-client-with-easy-rsa-3-on-centos-7/ ↩︎
https://en.wikipedia.org/wiki/Privacy-enhanced_Electronic_Mail ↩︎
Diffie–Hellman key exchange is a method of securely exchanging cryptographic keys over a public channel. ↩︎
https://security.stackexchange.com/questions/65864/why-openvpn-is-using-both-certificates-and-dh ↩︎