The WireGuard VPN challenge of provisioning clients
I mentioned in yesterday's entry that at work I'm building a VPN server that will support WireGuard. I'm quite happy with WireGuard in general and I think it has some important attractive features (such as the lack of 'sessions'), but we won't be offering WireGuard for general use. I would like to, but every time I even consider the idea, I run headlong into the problem of provisioning, specifically of provisioning WireGuard clients in some way that ordinary people can successfully set them up.
Right now, to set up a WireGuard client you need the server's name
and port (which every VPN needs), the server's public key, the IP
the server expects you to have inside the WireGuard connection (its
AllowedIPs setting for you), and a private key that the server
has the public key for. We also
need you to set your DNS server(s) to correctly point to us, and
for general VPN usage you have to set your
AllowedIPs to 0.0.0.0/0.
This is a lot more things for you to set up than other VPN servers
need, partly because other VPN servers will push your internal IP,
the DNS servers to use, and often other information to you. Much
of this is also sensitive to typos or, in the case of keys, must
be cut and pasted to start with (no one is typing a base64 WireGuard
key). If you get your client IP wrong, for example, things just
quietly don't work (the server will discard your traffic).
The client keypair is an especially touchy problem. The ideal would
be to securely generate it on the client and upload the public key.
In practice this is asking a lot of people to do more or less by
hand, so in a realistic setup we would probably want to generate
your client keypair on the server and then somehow give you access
to the private key for you to configure along side the server's
public key. Given this, possibly the most generally usable way of
provisioning WireGuard client connections would be to generate the
wg.conf that a client would use with the normal WireGuard command
line tools, then provide it to people and hope that any WireGuard
client will be able to import it.
(The official WireGuard client for iOS and Android will apparently
do this, including decoding the configuration from a QR code. I
believe the official Windows client does as well. On Unix, you can
wg.conf directly or import it into NetworkManager.)
An additional complication is that you need a separate WireGuard configuration on each device that you want to use WireGuard on at the same time. So we wouldn't have to just provision one WireGuard setup per person, we're looking at one for your laptop, one for your phone, one for your tablet, and so on. This also complicates naming them and keeping track of them (for people and for us), and likely would tempt people into reusing configurations across devices, which leads to fun problems if both devices are in use at the same time.
I don't blame the WireGuard project for this state of affairs. Provisioning is both a hard problem and a high level concern that is sort of out of scope for a project that's deliberately low level and simple. I'm honestly impressed (and happy) that there are official WireGuard clients on as many platforms as there are. I do wish there was some officially supported way to push configuration information to clients, although I understand why there isn't.
(Tailscale is not a solution for us for various reasons, including price. I do admire them for solving the provisioning problem, though.)