Tailscale Support for OpenBSD

20200205
~07 mins
tl;dr: Learn how to configure Tailscale on OpenBSD.

Tailscale

A service called Tailscale launched at the beginning of the month and promises to be the “easiest, most secure way to use WireGuard and 2FA”.

As an early beta tester of WireGuard and someone who has been carefully tracking its progress towards mainline Linux (currently in net-next, scheduled for 5.6!), I am especially excited to see people much smarter than me start to build next generation VPN businesses centred around it.

WireGuard will allow the Tailscale folks to eschew traditional hub-and-spoke VPN models and have their customers construct their own private meshed (P2P) networks. This is similar in a sense to the features offered up by ZeroTier or what you might be able to presumably cobble together with the likes of Slack’s recently announced Nebula, though neither are based on WireGuard.

If Tailscale is executed well it could bring WireGuard to the masses and hopefully even usher in a bit of a paradigm shift for cloud networking: decentralised BeyondCorp-styled zero trust networking for the rest of us. That is, looking past perimeter-based security and not just for the usual case of privileged staff access. Why continue to build our backend SOAs out of all these layered VPCs with their NACLs, security groups and reverse proxying load balancers when some smart DNS and meshed WireGuard tunnels will suffice?

Anyway, idealist gushing aside, they do have their work cut out. The hard part in all of this is not the WireGuard data plane, but the control plane that manages it. I had a small side project going at work last year to allow temporal privileged access to cloud resources for our platform engineers using WireGuard, and solving the keypair distribution/rotation and tunnel auto-configuration for multiple OSes was not trivial! For Tailscale there’s also the issue of IAM / 2FA, DNS support and not least the tedious NAT traversal tricks that will be required for them to become a universally useful end-user SaaS. Good luck to them!

Support for OpenBSD

I’ve been using OpenBSD on and off since I was a teenager. It is without a doubt my favourite OS, and while I don’t use it as my daily driver anymore, it has remained steadfast at the helm of my homebrew router for many years.

I’ve also been using WireGuard to interconnect all of my machines for a while, but after switching them over to Tailscale last week my OpenBSD router was a notable omission.


Fret not! Thankfully Tailscale’s core is open source and on GitHub. It happened to utilise the same wireguard-go userspace library I was already familiar with from my work side project. Happily, they accepted my pull request and now Tailscale knows OpenBSD!

OpenBSD support for Tailscale

Fair warning, it does not take advantage of OpenBSD’s standout pledge(2) / unveil(2) security features yet but it should be able to given Go has the requisite syscall support (pledge, unveil).

The rest of this post will go into how you can get yourself hooked upto Tailscale from an OpenBSD userspace.

Installing Tailscale on OpenBSD

There is no native WireGuard in the OpenBSD kernel yet, and anyway Tailscale runs off a temporary fork of the wireguard-go implementation for now (which, incidentally, also means you cannot use the upstream version from OpenBSD’s ports).

20200621 UPDATE: WireGuard has since landed natively in OpenBSD-CURRENT as wg(4)! I have yet to have a play but it will be in 6.8-STABLE.

So, and accepting the arguably negligible hit for crossing the kernel<>userspace border for each packet, the first thing you’ll want to do is grab the latest Tailscale source code for local compilation.

; git clone --depth 1 https://github.com/tailscale/tailscale.git

You will also need a sufficiently modern Go toolchain (but do not necessarily need to be on an OpenBSD host).

20201012 UPDATE: As I rebuilt to latest Tailscale for my own router I noticed their repository has changed slightly. I’ve updated the following instructions to match the current structure as of this date.

Build OpenBSD compatible Tailscale binaries and move them to your target machine (presuming you’re not already on it):

; cd tailscale
; GOOS=openbsd go build ./cmd/tailscale
; GOOS=openbsd go build ./cmd/tailscaled
; scp tailscale{,d} root@openbsd:/usr/local/bin

On OpenBSD, tailscaled will correctly use /var/db/tailscale as its state directory and /var/run/tailscale/tailscale.sock for its UNIX socket.

This is the rc script I use (/etc/rc.d/tailscaled). Don’t forget to make it executable!

#!/bin/ksh
daemon="/usr/local/bin/tailscaled"

. /etc/rc.d/rc.subr

rc_start() {
    ${rcexec} "${daemon} ${daemon_flags} 2>&1 | logger -t tailscaled &"
}

rc_cmd $1

Pair this with an entry in /etc/rc.conf.local, optionally passing any Tailscale daemon flags (or use rcctl enable tailscaled):

tailscaled_flags=""

Start the daemon to make sure it is working:

; doas rcctl start tailscaled
# tailscaled(ok)

And that’s it! You should have Tailscale logs streaming in /var/log/messages and have a plumbed tunX device by now.

I’ve had my Tailscale state db configured for a while, but if you see authentication errors in the logs then you may need to run an initial:

; tailscale up