Routed OpenVPN HOWTO

This is my OpenVPN HOWTO. There are many like it, but this one is mine.

It seems every few months I get asked the question by one of my friends “How do I set up a VPN?”. Sometimes the person is looking to set up a MS VPN variant, other times, OpenVPN. The principles and concepts seem simple to me, now, however for someone new to VPN architectures and perhaps even routing, it can be confusing. This is my attempt to make the mysterious understandable. Since roadwarrior (individual laptop clients) configs are fairly well documented by the official OpenVPN wiki, I’ll concentrate on a simple routed, LAN-to-LAN VPN networking concept, and cover roadwarrior config as an afterthought.

My weapon of choice distro-wise is CentOS, however these instructions could be applied to any other distro (ie, Ubuntu) with a basic understanding of your particular platform’s networking configuration methods. Really, OpenVPN can run on just about anything, including Windows, if you feel so inclined. However, you’ll probably get the most bang for your buck (free) using Linux. In my test environment, running stock CentOS 6.4, I had the scenario below running on a server with less than 90MB of total system memory usage.

Why CentOS?
(BEGIN RANT)
I have two main reasons for promoting the use of CentOS:
1) CentOS is based upon RedHat Enterprise Linux (RHEL), which currently enjoys status as the most vendor-supported OS in enterprise environments. Translation? Knowledge of an RHEL derivitaves like CentOS is marketable skill to put on your resume. Yes, Ubuntu is gaining popularity in tech circles, but still doesn’t compare to RHEL for vendor support. There’s a reason both VMWare and Citrix use RHEL derivitaves as their baremetal OS.
2) CentOS has long-term-support (LTS). I’ve used Fedora for years, and I enjoy(ed) playing with some of the bleeding-edge features it offers. But the bleeding edge is on a double-edged sword. Fedora has a relatively aggressive release and support schedule. Install Fedora X, and expect that Fedora Z will replace it in about a year, leaving version X effectively without support. This gets to be a pain when you need to “yum update” your system just a year or so after you installed it. CentOS however has a support schedule that will ensure you likely have updates for far more years than the lifecycle of your hardware. For example CentOS 6, released in 2011, reaches EOL in late 2020. That’s almost 10 years of support, on a free platform!
(END RANT)

First, let’s diagram the network we are going to design:

Remote Office 1 (10.101.0.x/24)
|
VPN Tunnel (10.200.101.1/30)
|
Main Office (10.100.0.x/24)
|
VPN Tunnel (10.200.102.1/30)
|
Remote Office 2 (10.102.0.x/24)

For this guide, we’re going to assume you want all remote offices to have routing enabled to each other (via the Main office).

Note that the IP addresses above are just for example. You could create your own IP addressing scheme with FAR better utilization of the the private address space. The subnets I have used (ie 10.200.x.x/16) are just for increased clarity.

Each OpenVPN server/endpoint can have one interface (assuming you are doing NAT/firewalling elsewhere on your network), OR you could have dual interfaces: One on the LAN, the other on the WAN/Internet connection. It’s up to you depending on where you want to do your firewalling. For the purposes of this guide, we’re putting the VPN server behind another firewall.

On your firewall
Forward UDP port 1194 for your external internet connection to the internal IP of your VPN servers/endpoints, ie:

Main Office 10.100.0.5:1194
Remote Office 1 10.101.0.5:1194
Remote Office 2 10.102.0.5:1194

If for some reason UDP/1194 were blocked by your ISP, you could switch to something like TCP/80, but for the purposes of this guide, we’ll stick with the default UDP/1194.

On each server/endpoint
Install your base OS. I chose to just install CentOS 6.4 minimal installation with the default options. Once installed, get networking set up and run

yum update

and get everything up-to-date.

Install the EPEL Repo configs

yum install http://download.fedoraproject.org/pub/epel/6/x86_64/epel-release-6-8.noarch.rpm

Turn off the built-in firewall (remember, we’re using a 3rd party device for this). You could leave it on, but then you’d have to configure it to pass traffic to/from your VPN tunnel interface. I’ll leave that up to you to figure out should you choose to do so.

chkconfig iptables off ; service iptables stop

Install the OpenVPN packages and dependencies:

yum install openvpn

Server (Main Office)

Copy the the easy-rsa environment to /etc/openvpn/easy-rsa, do some config prep, and alter the vars file

cp -rp /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/easy-rsa
cd /etc/openvpn/easy-rsa/
cp -rp vars vars.orig
cp -rp openssl-1.0.0.cnf openssl.cnf
vi vars

Go down to “KEY_COUNTRY” and edit the Country, Province, etc, down to the OU, ie:

export KEY_COUNTRY="US"
export KEY_PROVINCE="MN"
export KEY_CITY="Minneapolis"
export KEY_ORG="Muchtall"
export KEY_EMAIL="me@my.domain.com"
export KEY_EMAIL=me@my.domain.com
export KEY_CN=vpn.mydomain.com
export KEY_NAME=MuchtallOpenVPNServer
export KEY_OU=Muchtall

Now generate your server’s certificate authority:

. ./vars
./clean-all
./build-ca

Accept the defaults for the prompts (we already set them)

Now build the server key

./build-key-server vpn.mydomain.com

Similar to above, accept the default prompts. You will have to answer “y” to the questions “Sign the certificate? [y/n]:” and “1 out of 1 certificate requests certified, commit? [y/n]”

Now generate certs/keys for each remote site

./build-key remote-office-1
./build-key remote-office-2

Rinse, repeat on the prompts.

And generate the Diffie-Hellman parameters:

./build-dh

Great! Our certificates are all set up!

Next time you want to generate a new client key, just run

cd /etc/openvpn/easy-rsa/
. ./vars
./build-key remote-office-3

Now, let’s set up the configs. There’s a sample config at /usr/share/doc/openvpn-2.2.2/sample-config-files/server.conf, however we’re going to set one up using this template, just to keep things simple:

port 1194
proto udp
dev tun
ca easy-rsa/keys/ca.crt
cert easy-rsa/keys/vpn.mydomain.com.crt
key easy-rsa/keys/vpn.mydomain.com.key
dh easy-rsa/keys/dh1024.pem
server 10.200.0.0 255.255.0.0
ifconfig-pool-persist ipp.txt
# Tell clients that we can handle routes for these networks
push "route 10.100.0.0 255.255.0.0"
push "route 10.101.0.0 255.255.0.0"
push "route 10.102.0.0 255.255.0.0"
client-config-dir ccd
# Tell OpenVPN that it routes for anything within these subnets
route 10.101.0.0 255.255.0.0
route 10.102.0.0 255.255.0.0
client-to-client
keepalive 10 120
comp-lzo
persist-key
persist-tun
status openvpn-status.log
verb 3

Now create the ccd directory

mkdir /etc/openvpn/ccd

And lets create the client-specific configs to route each individual subnet to the respective site:

# In /etc/openvpn/ccd/remote-office-1
iroute 10.101.0.0 255.255.255.0

And

# In /etc/openvpn/ccd/remote-office-2
iroute 10.102.0.0 255.255.255.0

Good? Good!

Normally, IP subnets for the tunnels are allocated as new tunnels connect to the server. Let’s pre-set the IPs for each tunnel. This part isn’t necessary, however I like to do this to assist with clarity in troubleshooting with traceroutes. In /etc/openvpn/ipp.txt:

remote-office-1,10.200.101.4
remote-office-2,10.200.102.4

And re-set the SELinux permissions on the ipp.txt file

restorecon -v './ipp.txt'

Now we’re ready to start the the OpenVPN service up:

service openvpn restart

Check the syslog to see if anything serious got spit out:

tail -100 /var/log/messages

You should see something similar to this:

May 7 14:54:53 mainoffice openvpn[13362]: OpenVPN 2.2.2 x86_64-redhat-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] built on Aug 10 2012
May 7 14:54:53 mainoffice openvpn[13362]: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
May 7 14:54:53 mainoffice openvpn[13362]: Diffie-Hellman initialized with 1024 bit key
May 7 14:54:53 mainoffice openvpn[13362]: TLS-Auth MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
May 7 14:54:53 mainoffice openvpn[13362]: Socket Buffers: R=[229376->131072] S=[229376->131072]
May 7 14:54:53 mainoffice openvpn[13362]: ROUTE default_gateway=10.0.3.2
May 7 14:54:53 mainoffice openvpn[13362]: TUN/TAP device tun0 opened
May 7 14:54:53 mainoffice openvpn[13362]: TUN/TAP TX queue length set to 100
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip link set dev tun0 up mtu 1500
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip addr add dev tun0 local 10.200.0.1 peer 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.101.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.102.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: /sbin/ip route add 10.200.0.0/16 via 10.200.0.2
May 7 14:54:53 mainoffice openvpn[13362]: Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:135 ET:0 EL:0 AF:3/1 ]
May 7 14:54:53 mainoffice openvpn[13369]: UDPv4 link local (bound): [undef]:1194
May 7 14:54:53 mainoffice openvpn[13369]: UDPv4 link remote: [undef]
May 7 14:54:53 mainoffice openvpn[13369]: MULTI: multi_init called, r=256 v=256
May 7 14:54:53 mainoffice openvpn[13369]: IFCONFIG POOL: base=10.200.0.4 size=16382
May 7 14:54:53 mainoffice openvpn[13369]: IFCONFIG POOL LIST
May 7 14:54:53 mainoffice openvpn[13369]: remote-office-1,10.200.101.4
May 7 14:54:53 mainoffice openvpn[13369]: remote-office-2,10.200.102.4
May 7 14:54:53 mainoffice openvpn[13369]: Initialization Sequence Completed
May 7 14:54:53 mainoffice kernel: tun0: Disabled Privacy Extensions

Once you’ve verified based upon the above output that everything is running fine, go ahead and mark the service to start automatically

chkconfig openvpn on

Client Configs (Remote Offices)
On each server, create the file “/etc/openvpn/vpn.mydomain.com.conf”, and populate with the following:

client
dev tun
proto udp
remote 192.168.56.100 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert remote-office-1.crt
key remote-office-1.key
comp-lzo
verb 3

Be sure to change the cert name as appropriate.

Copy the ca.crt, remote-office-1.key, and remote-office-1.crt to the /etc/openvpn/ directory of the client. Repeat for Office 2.

Set the permissions on the key file so that it can’t be copied by non-root users.

chmod 600 /etc/openvpn/remote-office-1.key

Start the OpenVPN service

service openvpn start

Check the output of syslog for similar output:

May 7 16:26:39 remote-office-1 openvpn[1566]: OpenVPN 2.2.2 x86_64-redhat-linux-gnu [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] built on Aug 10 2012
May 7 16:26:39 remote-office-1 openvpn[1566]: WARNING: No server certificate verification method has been enabled. See http://openvpn.net/howto.html#mitm for more info.
May 7 16:26:39 remote-office-1 openvpn[1566]: NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
May 7 16:26:39 remote-office-1 openvpn[1566]: LZO compression initialized
May 7 16:26:39 remote-office-1 openvpn[1566]: Control Channel MTU parms [ L:1542 D:138 EF:38 EB:0 ET:0 EL:0 ]
May 7 16:26:39 remote-office-1 openvpn[1566]: Socket Buffers: R=[229376->131072] S=[229376->131072]
May 7 16:26:39 remote-office-1 openvpn[1566]: Data Channel MTU parms [ L:1542 D:1450 EF:42 EB:135 ET:0 EL:0 AF:3/1 ]
May 7 16:26:39 remote-office-1 openvpn[1566]: Local Options hash (VER=V4): '41690919'
May 7 16:26:39 remote-office-1 openvpn[1566]: Expected Remote Options hash (VER=V4): '530fdded'
May 7 16:26:39 remote-office-1 openvpn[1567]: UDPv4 link local: [undef]
May 7 16:26:39 remote-office-1 openvpn[1567]: UDPv4 link remote: x.x.x.x:1194
May 7 16:26:39 remote-office-1 openvpn[1567]: TLS: Initial packet from x.x.x.x:1194, sid=f439995e ac9dd302
May 7 16:26:39 remote-office-1 openvpn[1567]: VERIFY OK: depth=1, /C=US/ST=MN/L=Minneapolis/O=Muchtall/OU=Muchtall/CN=vpn.mydomain.com/name=MyOpenVPNServer/emailAddress=me@my.domain.com
May 7 16:26:39 remote-office-1 openvpn[1567]: VERIFY OK: depth=0, /C=US/ST=MN/L=Minneapolis/O=Muchtall/OU=Muchtall/CN=vpn.mydomain.com/name=MyOpenVPNServer/emailAddress=me@my.domain.com
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Encrypt: Cipher 'BF-CBC' initialized with 128 bit key
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Encrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Decrypt: Cipher 'BF-CBC' initialized with 128 bit key
May 7 16:26:39 remote-office-1 openvpn[1567]: Data Channel Decrypt: Using 160 bit message hash 'SHA1' for HMAC authentication
May 7 16:26:39 remote-office-1 openvpn[1567]: Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
May 7 16:26:39 remote-office-1 openvpn[1567]: [vpn.mydomain.com] Peer Connection Initiated with 192.168.56.150:1194
May 7 16:26:41 remote-office-1 openvpn[1567]: SENT CONTROL [vpn.mydomain.com]: 'PUSH_REQUEST' (status=1)
May 7 16:26:41 remote-office-1 openvpn[1567]: PUSH: Received control message: 'PUSH_REPLY,route 10.100.0.0 255.255.0.0,route 10.101.0.0 255.255.0.0,route 10.102.0.0 255.255.0.0,route 10.200.0.0 255.255.0.0,topology net30,ping 10,ping-restart 120,ifconfig 10.200.101.6 10.200.101.5'
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: timers and/or timeouts modified
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: --ifconfig/up options modified
May 7 16:26:41 remote-office-1 openvpn[1567]: OPTIONS IMPORT: route options modified
May 7 16:26:41 remote-office-1 openvpn[1567]: ROUTE default_gateway=10.0.3.2
May 7 16:26:41 remote-office-1 openvpn[1567]: TUN/TAP device tun0 opened
May 7 16:26:41 remote-office-1 openvpn[1567]: TUN/TAP TX queue length set to 100
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip link set dev tun0 up mtu 1500
May 7 16:26:41 remote-office-1 kernel: tun0: Disabled Privacy Extensions
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip addr add dev tun0 local 10.200.101.6 peer 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.100.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.101.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.102.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: /sbin/ip route add 10.200.0.0/16 via 10.200.101.5
May 7 16:26:41 remote-office-1 openvpn[1567]: Initialization Sequence Completed

And verify that the routing is taking place

ping 10.100.0.1

Set the openvpn service to start automatically

chkconfig openvpn on

Repeat these steps for the Office 2 client. And verify that you can ping across both tunnels to Office 1

Roadwarrior Config (this is optional)
As an afterthought, I said I’d cover Roadwarrior configuration. Here’s a basic rundown:

– Generate a new cert/key pair for your username using the above ./build-key commands
– Install OpenVPN for Windows (if you’re on Mac or Linux, you likely know how to do this already)
– Copy the ca.crt, username.crt, and username.key files to “C:\Program Files\OpenVPN\config\”
– Create a config file named C:\Program Files\OpenVPN\config\vpn.mydomain.com.ovpn with these contents:

client
dev tun
proto udp
remote vpn.mydomain.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
ca ca.crt
cert myusername.crt
key myusername.key
comp-lzo
verb 3

Right-click on the OpenVPN GUI in the taskbar and click “Connect”.