Making DigitalOcean's Private Networking Secure
A few weeks ago here at Hone, we decided to spin a new server cluster in DigitalOcean’s NYC3 data center. DigitalOcean introduced ‘private’ networking just over a year ago. However, it turns out that DigitalOcean actually refers to this as Shared Private Networking—and many of the comments under their announcement point out that their private networking isn’t really too private.
We decided to use OpenVPN to layer a secure network on top of DigitalOcean’s shared private networking.
What we wanted to accomplish:
- Install an OpenVPN server on our load balancer
- Install an OpenVPN client on all of our other machines
- Drop any traffic other than OpenVPN on
eth1
(DO’s shared private network) - Allow all traffic over
tun0
(our secured private network)
With traffic passing through the tun0
interface between machines, we gain the ability to more quickly and easily spin up new machines and add them to our infrastructure.
Here’s how to setup a virtual private network on DigitalOcean (or whichever provider you might be using):
Setup / Configure Your OpenVPN Server
Update your packages and install OpenVPN and Easy RSA:
Copy some Easy RSA files over to a more permanent location so that you can upgrade OpenVPN in the future without losing your configuration settings:
Edit /etc/openvpn/easy-rsa/vars
and change the various exports for default certificate values.
At the very least, you’ll want to change the following keys in the vars
file to suit your needs:
With your vars
configured, you can now generate a master Certificate Authority (CA) Certificate and Key for your server:
Generate a certificate and private key for the server:
Generate some Diffie–Hellman–Merkle parameters for the OpenVPN server (This will take a minute or two):
Copy the keys, certs, and the Diffie–Hellman–Merkle params that you generated from /etc/openvpn/easy-rsa/keys
into your OpenVPN directory, /etc/openvpn/
:
Generate Certificates For VPN Client(s)
You’ll need to generate a certificate and key for each VPN client:
Securely copy these the following files to the client machine (via rsync
, scp
, etc.):
/etc/openvpn/ca.crt
/etc/openvpn/easy-rsa/keys/<vpn_client_name>.crt
/etc/openvpn/easy-rsa/keys/<vpn_client_name>.key
After you’ve copied these keys and certs to your client machine(s), delete them from the VPN server. They’re no longer needed on that machine and keeping them there poses a security risk if unauthorized access is gained.
Edit Your OpenVPN Server Config
Copy over and unpack the provided example server config—server.conf.gz
—to /etc/openvpn/server.conf
Edit /etc/openvpn/server.conf
to ensure it contains the settings that make sense for your intended setup.
You’ll want to make sure it points to the correct location of your certs, keys, and dh2048.pem
file (Diffie–Hellman–Merkle parameters) that you generated earlier.
Here’s an example of some lines you should configure (or uncomment) in server.conf
Note: Uncommenting client-to-client
will enable your VPN clients to communicate with one another directly. By default, VPN clients will only see the VPN server.
Start OpenVPN on your server
Check That it Works
After you start your openvpn service, you should see tun0
interface details when you run:
If you’ve set up your server correctly, you should see some output like this:
If you run the ifconfig tun0
command above and see the error ifconfig: interface tun0 does not exist
, then you’ll need to check your OpenVPN server.conf again and make sure to reconfigure it.
Setup / Configure Your OpenVPN Client(s)
Update your packages and install OpenVPN:
Copy the example client.conf
file over to /etc/openvpn/client.conf
:
If you haven’t already done so: Make sure that you’ve generated and then securely transferred (or manually copied over) ca.crt
, <vpn_client_name>.crt
, and <vpn_client_name>.key
to your new VPN client.
(For the purposes of this tutorial, I’ve copied them into /etc/openvpn/
.)
Edit /etc/openvpn/client.conf
and make sure everything points to correct certs and keys. You should also make sure to specify the IP address corresponding to your OpenVPN server’s eth1
interface (DO’s shared private network):
Having finished editing client.conf
, you can restart the OpenVPN service on your VPN client machine:
Check to see that you’ve got a tun0
interface (and that it has the correct IP):
Ping Your VPN Server (From Client Machine)
If you’d like to sanity-check your connection to your VPN server, try pinging the OpenVPN server directly:
In this example, I’m pinging 10.8.0.1
, which is set by OpenVPN default server config. You may have selected something different, in which case you should find the IP corresponding to your OpenVPN server’s tun0
interface.
You can grab this IP quickly by running (on the OpenVPN server itself): ifconfig tun0
.
If you can’t ping the OpenVPN server, then something is wrong with your config. Consider re-reading all of the above.
Assign Static IPs to VPN Clients
You may desire to assign static IP addresses to some or all of your client machines. (Hat-tip to Michael Albert for a great post which helped here.)
On your OpenVPN server, create a folder in which to save the information of your static clients.
In this example, we’ll name our folder static_clients
:
Make sure to uncomment and edit this line in server.conf
:
Previously, when you generated a cert and key for your new VPN client, recall the common_name
that you chose.
Create a file—naming it whatever you chose for the common_name
— in /etc/openvpn/static_clients/
with the following content:
(Note that in this example, we’d like this VPN client’s tun0
interface to be assigned the IP 10.8.0.4
)
OpenVPN will need to read these files after it drops privileges. You can do that do that with the following:
Configure Your iptables
If you want to further secure your VPN, you should edit your VPN client machine’s iptables
. With your OpenVPN server and clients set up correctly and pingable (in both directions) via their tun0
interfaces, you can begin restricting traffic over your eth1
(DO’s shared private network interface) to accept only traffic over port 1194
(OpenVPN’s default port) on that interface.
For example, if you’re routing traffic through a load balancer, you may want to lock down VPN client boxes as such:
- Restrict access on
eth0
interface (public) to port 22 only - Restrict access on
eth1
interface (DO’s shared private network) to udp/tcp traffic over port 1194 only - Unrestricted access on
tun0
interface (OpenVPN tunnel interface).
Here’s an example iptables
config that would restrict traffic in the way I mention above:
Hone is Hiring!
Check out all of the positions for which we’re currently hiring.
Credit Where Credit Is Due
While figuring out how to do everything above—and while I was writing this tutorial—I was reading and consulting with the following sources:
- https://openvpn.net/index.php/open-source/documentation/howto.html
- http://grantcurell.com/2014/07/22/setting-up-a-vpn-server-on-ubuntu-14-04/
- https://help.ubuntu.com/14.04/serverguide/openvpn.html
- http://www.slsmk.com/getting-started-with-openvpn/installing-openvpn-on-ubuntu-server-12-04-or-14-04-using-tap/
- https://www.digitalocean.com/community/tutorials/how-to-setup-and-configure-an-openvpn-server-on-debian-6
- https://www.digitalocean.com/community/tutorials/how-to-setup-and-configure-an-openvpn-server-on-centos-6
- https://www.digitalocean.com/community/tutorials/openvpn-access-server-centos
- https://gist.github.com/padde/5689930
- https://github.com/tinfoil/openvpn_autoconfig/blob/master/bin/openvpn.sh