Do you use let's encrypt?

Joining disparate hosts into a VPN with gvpe

The GNU Virtual Private Ethernet software allows you to join multiple distinct hosts into a small private network, via a static set of public/private keys. It is ideally suited to joining a small number of hosts in a secure fashion.

I use gvpe to allow all the virtual machines I run to have a secure link between each other. Imagine you have a typical cluster:

2-3 webservers.

1-2 database servers.

If you assign each host a private address and configure them all to be in a VPN then traffic between them will be encrypted. That means even if your hosting company were to sniff your traffic they wouldn't ever see your database queries over the wire. (Of course if you don't trust your hosting company you've got bigger problems; they could clone your disks, subvert your hardware, or worse.)

I chose gvpe because it is very simple to setup, has a low overhead, and can be configured easily for a small and static list of hosts.

Installation of the software is very simple:

apt-get install gvpe

Once that is done we'll need to configure it. That involves three simple steps:

Writing a configuration file, containing a list of all the nodes.

Generating and configuring the keys used.

Writing a simple shell-script to be invoked when the VPN is established.

The first is simple. In our case we're going to configure a VPN between the two hosts one.example.com and two.example.com. So our configuration file /etc/gvpe/gvpe/gvpe.conf will look like this:

The configuration has some boiler-plate at the top to configure how the VPN will be setup, in our case using UDP traffic over port 407, and the name of the networking devices on each node (vpn0).

Now that we've configured the list of nodes we need to generate the keys:

# gvpectrl --config /etc/gvpe/ --generate

This will poluate the two directores /etc/gvpe/hostkeys, and /etc/gvpe/pubkey with some static keys, which are used for the encryption, and session negotiation. You need to generate the keys on only one node, then copy them to any other nodes - Every node must have identical keys.

In addition to creating keys for all nodes in the mesh we need to ensure that the host key for the local host is present. So we'd run:

# On the first node
root@one:~# ln -s /etc/gvpe/hostkeys/one /etc/gvpe/hostkey
# On the second node.
root@two:~# ln -s /etc/gvpe/hostkeys/two /etc/gvpe/hostkey

(i.e. The keys are named after the node-name, but we need to ensure the key for the current host is located at /etc/gvpe/hostkey.)

The final step is to write a simple shell-script which will be launched when the link(s) are established. Create the file /etc/gvpe/if-up, with contents like so:

This script works because the nodename of the current host will be passed along with the other variables you see referenced such as $IFNAME, and $MAC.

By the time you've reached this step you'll have the following structure:

/etc/gvpe/
├── gvpe.conf - The configuration file.
├── hostkey - The key for this host, linked to from ./hostkeys
├── hostkeys
│ ├── one - Private keys for the nodes.
│ └── two
├── if-up - The script to launc the devices and configure the routing.
└── pubkey
├── one - Public keys for the nodes.
└── two
2 directories, 7 files

The only remaining step is to launch the link:

# On one side.
root@one:~# gvpe --config /etc/gvpe/ -D one
# On another side.
root@two:~# gvpe --config /etc/gvpe/ -D two

The launch command includes the name of the current node, which is why we prefer to name nodes after hostnames. It makes it nice and clear. If all goes well you'll see something like this:

Finally to allow the daemon to be launched on bootup you can update /etc/default/gvpe to read:

START_DAEMON="1"
DAEMON_ARGS="--config /etc/gvpe/ one"

Here I'm using "one" as the node-name to be nice and clear. In my case I name nodes after the local hostnames, so I can instead write ...$(hostname --short)"

At the end of this article you should be able to quickly setup a simple VPN containing 2+ hosts. There are many more options you can experiment with, which are documented via "man gvpe.conf", "man gvpe", and "man gvpectrl".

I've done a similar thing with tinc and it works really well too. The steps are mostly the same except:

you have a different key for each host -- you copy the public part of machine the key around to any host you want to be able to connect

the networking setup is less work -- it's just set the ip address of the node in an ifup script (you can do lots more funky stuff and have it route and gateway etc if you want)

tinc is a mesh network -- any node can make a direct connnection to any other node if you want it to and you can transparently use multiple hops to get indirect connections if want or need to

I have tinc set up on all my machines and I can then reach any other machine as needs be. I work in a few NATed environments so I try to have a tinc inside each of these NATs that's permanently on and connected to others and then laptops that move from one NATed environment to another just connect to whatever local tinc they can see. I can always get into the machine inside these NATs from outside when I need to over the VPN too, using an indirect connection through tinc. Given that the mesh could be quite complicated, I have tinc write out a .dot file for me whenever the graph changes... very useful when I was first learning about it, but mostly I look at it now only for amusement purposes.

I have no idea if tinc is any better or worse than gvpe... I'll be interested to hear how things go in the long run for you!

Personally I think it is an advantage you get to write a shell script for gvpe, as you say for tinc it allows you to do a lot - you can add/remove routes, restart services, etc. My setup makes sure that the VPN address uses th last octet of the main IP because that makes it simple to remember:

When you run gvpe on a desktop machine you will see that the connections go up immediately even if you set connect=ondemand. I found this is because of service advertisements on MDNS. There are two ways to stop these advertisements: