OpenVPN – creating a routed VPNIn this article, I will show you how I created a routed VPN using OpenVPN. In this network, multiple clients can attach to the server, each of which has access to the network attached to the server. Each client can also contact any other client, subject to firewall rules. In my case, I wanted a way for all my servers (on the internet, in data centers) to contact my CVS repository behind my firewall at home. Given that home has a dynamic IP address, it complicates matters. A VPN solves this issue and provides several benefits. I have outlined the problems in my other diary and I urge you to read that before proceeding. It will provide valuable background as to why I have chosen this particular solution.
AcknowledgementsTwo people have been of great help while I struggled with OpenVPN. ecrist and krzee have both pointed me to examples and features. Others within the FreeNode OpenVPN channel also listened to my goals and provided suggestions. Thanks. Here are a few good references:
AssumptionsThis article relies upon previous articles on this website:
Server configurationNOTE: since this was originally written, I have changed the configuration. The article used to show both ifconfig-pool-persist and client-config-dir settings. The latter can be used with ifconfig-push to guarantee static IP addresses. That is what I need. I have since changed the configuration shown below to reflect what I am using now. This section shows you the setup of my OpenVPN server. The main configuration file is /usr/local/etc/openvpn/openvpn.conf. This is mine:
port 1194 proto udp dev tun ca /usr/local/etc/openvpn/keys/ca.crt cert /usr/local/etc/openvpn/keys/myserver.example.org.crt key /usr/local/etc/openvpn/keys/myserver.example.org.key dh /usr/local/etc/openvpn/keys/dh1024.pem client-config-dir /usr/local/etc/openvpn/ccd server 10.8.1.0 255.255.255.0 keepalive 10 120 client-to-client comp-lzo user nobody group nobody persist-key persist-tun tls-auth /usr/local/etc/openvpn/keys/ta.key 0 status openvpn-status.log verb 4 push "route 10.55.0.0 255.255.255.0"Some of the options from above are outlined below. For full details, please refer to the OpenVPN man page. The ca, cert, key, and dh directives are straight from the basic setup given in the previous article. client-config-dir specifies the directory for custom client config files. We use these files for assigning static IPs, but they have additional uses. server indicates that our VPN server will use the 10.8.1.0/24 subnet. client-to-client allows each VPN client to see all other VPN clients. tls-auth is a shared secret, same file in each client, that is optional but allows n additional layer of HMAC authentication on top of the TLS control channel to protect against DoS attacks. push ensures that each client can access the 10.55.0.0/24 network on the VPN server. This push adds an entry to the client’s routing table.
Client configurationThe configuration file, /usr/local/etc/openvpn/openvpn.conf, contains this:
client dev tun proto udp remote myserver.example.com 1194 resolv-retry infinite nobind user nobody group nobody persist-key persist-tun pull ns-cert-type server tls-auth /usr/local/etc/openvpn/keys/ta.key 1 ca /usr/local/etc/openvpn/keys/ca.crt cert /usr/local/etc/openvpn/keys/nyi.example.com.crt key /usr/local/etc/openvpn/keys/nyi.example.com.key comp-lzo verb 4As expected, I will outline some of these directives. client designates this as a client configuration. ns-cert-type server avoids a man-in-the-middle attack. tls-auth is the same shared secret file as mentioned in the server section. I will show you how to generate it later. Notice that the direction is 1 on the client and 2 on the server. See the –secret option on the OpenVPN man page for more information. ca, cert, key, and dh have been previously explained.
Generating the tls-authYou can generate a tls-auth file with this command:
openvpn --genkey --secret /usr/local/etc/openvpn/keys/ta.keyCopy the file contents to each client.
Getting it runningStart both the server and the client. You should see this on the server:
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> mtu 1500 inet6 fe80::204:acff:fea3:74af%tun0 prefixlen 64 scopeid 0x9 inet 10.8.1.1 --> 10.8.1.2 netmask 0xffffffff Opened by PID 59658Notice that this configuration uses tun0, not tap0. On the client, you should see something like this:
tun0: flags=8051<UP,POINTOPOINT,RUNNING,MULTICAST> metric 0 mtu 1500 inet 10.8.1.14 --> 10.8.1.13 netmask 0xffffffff Opened by PID 39769You will also see that the server is configured for IPv6 but the client is not (i.e. the inet6 line). The client should be able to ping the server:
$ ping 10.8.1.1 PING 10.8.1.1 (10.8.1.1): 56 data bytes 64 bytes from 10.8.1.1: icmp_seq=0 ttl=64 time=24.077 ms 64 bytes from 10.8.1.1: icmp_seq=1 ttl=64 time=23.429 ms 64 bytes from 10.8.1.1: icmp_seq=2 ttl=64 time=23.045 ms 64 bytes from 10.8.1.1: icmp_seq=3 ttl=64 time=31.404 ms ^C --- 10.8.1.1 ping statistics --- 4 packets transmitted, 4 packets received, 0.0% packet loss round-trip min/avg/max/stddev = 23.045/25.489/31.404/3.435 msThat’s it. Now, on to static IP addresses
Static IP addressesI want static IP addresses for my clients. This will make things easier when it comes to running jobs on them. These hosts already have public IP addresses and hostnames. I will add private hostnames for them. For example, if the host can be accessed publicly by the name nyi.example.com, then I will add a new entry to my private DNS server (accessible only from my LAN at home) for nyi-vpn.example.com:
nyi-vpn IN A 10.8.1.20After reloading the name server, I can resolve that hostname:
$ host nyi-vpn nyi-vpn.example.com has address 10.8.1.20To assign that IP address to that host, I create a file in the client-config-dir, namely: /usr/local/etc/openvpn/ccd That file must have the same name as the client’s X509 common name. In this case: nyi-vpn.example.com The file will contain:
ifconfig-push nyi-vpn.example.com 255.255.255.0You can provide an IP address instead of a hostname. Restart your client and you should see something similar to this in /var/log/messages on your server:
OPTIONS IMPORT: reading client specific options from: /usr/local/etc/openvpn/ccd/nyi.example.com MULTI: Learn: 10.8.1.20 -> nyi.example.com/172.16.1.23:51376 MULTI: primary virtual IP for nyi.example.com/172.16.1.23:51376: 10.8.1.20 nyi.example.com/172.16.1.23:51376 PUSH: Received control message: 'PUSH_REQUEST' nyi.example.com/172.16.1.23:51376 SENT CONTROL [nyi.example.com]: 'PUSH_REPLY,route 10.55.0.0 255.255.255.0,route 10.8.1.0 255.255.255.0,ping 10,ping-restart 120, ifconfig 10.8.1.20 255.255.255.0' (status=1)And on the client, you’ll see messages similar to this:
gw 192.168.77.1 TUN/TAP device /dev/tun0 opened /sbin/ifconfig tun0 10.8.1.40 255.255.255.0 mtu 1500 netmask 255.255.255.255 up /sbin/route add -net 10.55.0.0 255.255.255.0 255.255.255.0 /sbin/route add -net 10.8.1.0 255.255.255.0 255.255.255.0
Well, it wasn’t really an IP address change, it was a disconnection, followed by an IP address change.
The Man Behind The Curtain