Background
VPN creates a secure and encrypted connection between your computer and the VPN server. It allows you to access your company’s private networks through this connection. There are many VPN solutions available. OpenVPN is a popular open-source VPN solution available today.
OpenVPN was split into several sub-projects since version 2.3 – easy-rsa (PKI management) and openvpn (core project). easy-rsa is a set of scripts to build the root certificate authority (CA) and request and sign certificates. Most of the steps you need to take are documented here.
Setting up OpenVPN is straight-forward. Below are the steps to setup and configure OpenVPN.
OpenVPN Server
Install openvpn and easy-rsa.
# yum install easy-rsa -y --enablerepo=epel
# yum install openvpn -y
Copy the key and certificate generation scripts into /etc/openvpn.
# mkdir -p /etc/openvpn/easy-rsa && cp -rf /usr/share/easy-rsa/2.0/* /etc/openvpn/easy-rsa
Generate the server credentials.
# cat /etc/openvpn/easy-rsa/vars
# easy-rsa parameter settings
# NOTE: If you installed from an RPM,
# don't edit this file in place in
# /usr/share/openvpn/easy-rsa --
# instead, you should copy the whole
# easy-rsa directory to another location
# (such as /etc/openvpn) so that your
# edits will not be wiped out by a future
# OpenVPN package upgrade.
# This variable should point to
# the top level of the easy-rsa
# tree.
export EASY_RSA="`pwd`"
#
# This variable should point to
# the requested executables
#
export OPENSSL="openssl"
export PKCS11TOOL="pkcs11-tool"
export GREP="grep"
# This variable should point to
# the openssl.cnf file included
# with easy-rsa.
export KEY_CONFIG=`$EASY_RSA/whichopensslcnf $EASY_RSA`
# Edit this variable to point to
# your soon-to-be-created key
# directory.
#
# WARNING: clean-all will do
# a rm -rf on this directory
# so make sure you define
# it correctly!
export KEY_DIR="$EASY_RSA/keys"
# Issue rm -rf warning
echo NOTE: If you run ./clean-all, I will be doing a rm -rf on $KEY_DIR
# PKCS11 fixes
export PKCS11_MODULE_PATH="dummy"
export PKCS11_PIN="dummy"
# Increase this to 2048 if you
# are paranoid. This will slow
# down TLS negotiation performance
# as well as the one-time DH parms
# generation process.
export KEY_SIZE=2048
# In how many days should the root CA key expire?
export CA_EXPIRE=3650
# In how many days should certificates expire?
export KEY_EXPIRE=90
# These are the default values for fields
# which will be placed in the certificate.
# Don't leave any of these fields blank.
export KEY_COUNTRY="US"
export KEY_PROVINCE="Manhattan"
export KEY_CITY="New York City"
export KEY_ORG="Acme Corp"
export KEY_EMAIL="admin@acme.com"
export KEY_OU="IT"
# X509 Subject Field
export KEY_NAME="server"
# PKCS11 Smart Card
# export PKCS11_MODULE_PATH="/usr/lib/changeme.so"
# export PKCS11_PIN=1234
# If you'd like to sign all keys with the same Common Name, uncomment the KEY_CN export below
# You will also need to make sure your OpenVPN server config has the duplicate-cn option set
# export KEY_CN="CommonName"
Source the parameters to generate the server credentials. You will source these parameters again later to generate the client credentials.
$ source ./vars
Build the certificate authority (CA) certificate and key.
$ ./build-ca
Generate a certificate and private key for the server.
$ ./build-key-server server
When the Common Name is queried, enter “server”. Two other queries require confirmation, “Sign the certificate? [y/n]” and “1 out of 1 certificate requests certified, commit? [y/n]”.
Generate the Diffie Hellman key exchange for the OpenVPN server.
$ ./build-dh
Copy ca.crt, dh2048.pem, server.crt, and server.key into /etc/openvpn.
Create the server configuration file.
# cat > /etc/openvpn/server.conf << EOF
#################################################
# OpenVPN 2.0 config file for multi-client #
# server. #
#################################################
# Which TCP/UDP port should OpenVPN listen on?
port 1194
# TCP or UDP server?
proto tcp
# "dev tun" will create a routed IP tunnel
dev tun
# SSL/TLS root certificate (ca), certificate (cert), and private key (key).
# Each client and the server must have their own cert and key file. The
# server and all clients will use the same ca file.
ca ca.crt
cert server.crt
key server.key # This file should be kept secret
# Prevent any form of downgrade attack on the TLS protocol level by
# setting the minimum version.
tls-version-min 1.2
# Restrict the VPN control channel to strong cipher suites.
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
# Change the VPN data channel to use AES with a 256 bit key in CBC mode.
cipher AES-256-CBC
# Diffie hellman parameters.
# Generate your own with:
# openssl dhparam -out dh2048.pem 2048
dh dh2048.pem
# Configure server mode and supply a VPN subnet for OpenVPN to draw client
# addresses from. The server will take 10.8.0.1 for itself, the rest will be
# made available to clients. Each client will be able to reach the server
# on 10.8.0.1.
server 10.8.0.0 255.255.255.0
# Maintain a record of client <-> virtual IP address associations in this
# file. If OpenVPN goes down or is restarted, reconnecting clients can be
# assigned the same virtual IP address from the pool that was previously
# assigned.
ifconfig-pool-persist ipp.txt
# If enabled, this directive will configure all clients to redirect their
# default network gateway through the VPN, causing all IP traffic such as
# web browsing and and DNS lookups to go through the VPN (The OpenVPN server
# machine may need to NAT or bridge the TUN/TAP interface to the internet
# in order for this to work properly).
# push "redirect-gateway def1"
# Certain Windows-specific network settings can be pushed to clients, such
# as DNS or WINS server addresses.
push "dhcp-option DNS 8.8.8.8"
push "dhcp-option DNS 8.8.4.4"
# The keepalive directive causes ping-like messages to be sent back and forth
# over the link so that each side knows when the other side has gone down.
# Ping every 10 seconds, assume that remote peer is down if no ping received
# during a 120 second time period.
keepalive 10 120
# Enable compression on the VPN link. If you enable it here, you must also
# enable it in the client config file.
comp-lzo
# It's a good idea to reduce the OpenVPN daemon's privileges after
# initialization.
user nobody
group nobody
# The persist options will try to avoid accessing certain resources on restart
# that may no longer be accessible because of the privilege downgrade.
persist-key
persist-tun
# Output a short status file showing current connections, truncated and
# rewritten every minute.
status openvpn-status.log
# Set the appropriate level of log file verbosity.
#
# 0 is silent, except for fatal errors
# 4 is reasonable for general usage
# 5 and 6 can help to debug connection problems
# 9 is extremely verbose
verb 4
# Set log file location.
log-append /var/log/openvpn.log
# Push routes to the client to allow it to reach other private subnets behind
# the server. Remember that these private subnets will also need to know to
# route the OpenVPN client address pool (10.8.0.0/255.255.255.0) back to the
# OpenVPN server.
push "route 192.168.0.0 255.255.255.0"
EOF
Remove the chance of our OpenSSL configuration not loading due to the version being undetectable. Do this by copying the required configuration file and removing the version number.
# cp /etc/openvpn/easy-rsa/openssl-1.0.0.cnf /etc/openvpn/easy-rsa/openssl.cnf
Verify dh2048.pem, ca.crt, server.crt, and server.key are on the OpenVPN server.
# chmod 600 /etc/openvpn/server.key
Add a rule to iptables to forward our routing to our OpenVPN subnet.
# iptables --flush
# iptables -A INPUT -i tun+ -j ACCEPT
# iptables -A FORWARD -i tun+ -j ACCEPT
# iptables -A FORWARD -i tun+ -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -A FORWARD -i eth0 -o tun+ -m state --state RELATED,ESTABLISHED -j ACCEPT
# iptables -t nat -A POSTROUTING -s 10.8.0.0/24 -o eth0 -j MASQUERADE
# iptables -A OUTPUT -o tun+ -j ACCEPT
# iptables-save > /etc/sysconfig/iptables
Restart the network to enable the latest changes.
# service network restart
Start the openvpn service.
# service openvpn restart
OpenVPN Client
Each client needs there own key and certificate to authenticate with the OpenVPN server. Any OpenVPN client is supported. They are listed here. Below are the steps to create a client key and certificate for the user “tpham” (you need to change to a unique common name).
On the client machine (e.g. CentOS), install OpenVPN.
# yum install easy-rsa -y --enablerepo=epel
# yum install openvpn -y
Generate the client key and certificate. Source the parameters to use for easy-rsa (these are the same parameters as the server).
$ cd /etc/openvpn/easy-rsa
$ source ./vars
Generating client certificates.
$ ./build-key tpham
This will generate tpham.crt and tpham.key. Put these files under /etc/openvpn.
Create a client configuration file for openvpn to use, e.g. /etc/openvpn/tpham.conf.
cat > /etc/openvpn/tpham.conf << EOF
##############################################
# Client-side OpenVPN 2.0 config file #
# for connecting to multi-client server. #
##############################################
# Specify that we are a client and that we
# will be pulling certain config file directives
# from the server.
client
# Use the same setting as you are using on
# the server.
dev tun
# Are we connecting to a TCP or
# UDP server? Use the same setting as
# on the server.
proto tcp
# The hostname/IP and port of the server.
remote 192.168.0.1 1194
# Keep trying indefinitely to resolve the
# host name of the OpenVPN server.
resolv-retry infinite
# Most clients don't need to bind to
# a specific local port number.
nobind
# Try to preserve some state across restarts.
persist-key
persist-tun
# Enable compression on the VPN link.
# Don't enable this unless it is also
# enabled in the server config file.
comp-lzo
# Set log file verbosity.
verb 4
# Prevent any form of downgrade attack on the TLS protocol level by
# setting the minimum version.
tls-version-min 1.2
# Restrict the VPN control channel to strong cipher suites.
tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384
# Change the VPN data channel to use AES with a 256 bit key in CBC mode.
cipher AES-256-CBC
# SSL/TLS parms.
ca $openvpn_directory/ca.crt
cert $openvpn_directory/guest.crt
key $openvpn_directory/guest.key
EOF
Restart OpenVPN to start the client.
$ service openvpn start
There are a few good articles on OpenVPN. Below are the ones used in this setup.
- https://community.openvpn.net/openvpn/wiki/Hardening
- https://www.digitalocean.com/community/tutorials/how-to-setup-and-configure-an-openvpn-server-on-centos-7