Notes on Tailscale
This is a post about Tailscale, a secure network that just works built on top of Wireguard.
The Remembering the LAN blog post by David Crawshaw resonate with me, in particular this quote:
I need to help new programmers who never got to experience simple, pleasurable programming in a safe environment understand that programming can be fun. You can set up your environment so you can focus on being creative.
With the Internet being a wild wild west it’s refreshing to be able to enjoy tinkering with computers in a private environment, in particular when you can’t keep your servers at home.
You can for example purchase a relatively cheap virtual server from
Hetzner Cloud, install Tailscale on it, then set up a simple
firewall rule to only allow inbound UDP traffic on port 41641
; now your new server is
only accessible from within your own private Tailscale network.
NOTE: you might want to disable key expiry for this virtual server in your Tailscale control panel.
Things of course can sometimes go wrong and it’s good to have a secondary way to access your server, which you have with the virtual console on Hetzner’s control panel.
The benefit of setting up this firewall rule on Hetzner itself and not on your server is that you don’t have to deal with nasty surprises, like Docker exposing your containers on the public internet despite your iptables rules were supposed to prevent that from happening.
For a good security posture you should also limit outbound network traffic, which is a completely different story. One thing you can do though is to leverage Tailscale’s ACLs to limit what other devices your new virtual server can access in your private network.
ACLs in Tailscale
Tailscale’s ACLs are documented in a knowledge base article, so here I’ll just provide a simple example.
The first thing to do is to assign a tag to your virtual server, as documented in the Server role accounts with ACL tags document; it’s important to know that when you provision a new device in Tailscale it is initially tied to your user’s permissions. If your ACL rules say “user me@github can access any device on port 22” it means that any device provisioned by “me@github” is inheriting those permissions.
Assigning tags to a device allow you to have more fine grained permissions, because it won’t inherit your user’s permissions anymore.
We can for example assign the tag internet
to our new virtual server by running the following
command on your new virtual server:
sudo tailscale up --advertise-tags=tag:internet
If you now remove the “allow-all” ACL rule from your Tailscale configuration your new virtual server won’t have access to any device on your network; for reference this is the “allow-all” rule:
{ "action": "accept", "users": ["*"], "ports": ["*:*"] },
Side note: in Emacs you can use jsonc-mode
to edit Tailscale’s ACL rules with syntax highlighting.
A more realistic example
For a better example I’ll describe the ACL rules for a small Tailscale network comprising three devices: a laptop, a Raspberry Pi server and a virtual server on the internet.
First we define a group called admin
that initially will only contain our user (me@github
):
"groups": {
"group:admin": [
"me@github"
],
}
Then we need to tell Tailscale that our user is the owner of the internet
tag:
"tagOwners": {
"tag:internet": ["me@github"],
},
Then, since the Raspberry Pi doesn’t have a tag, we need to add a hosts
entry to be able to
reference it later on (NOTE: you must replace 100.100.100.100
with the Tailscale IP of your
Raspberry Pi):
"hosts": {
"raspberry-pi": "100.100.100.100",
},
Finally we can define the actual ACLs:
"acls": [
// Allow ALL:
// { "action": "accept", "users": ["*"], "ports": ["*:*"] },
{ "action": "accept", "users": ["group:admin"], "ports": ["*:*"] },
{ "action": "accept", "users": ["tag:internet"], "ports": ["raspberry-pi:9100"] },
],
The first rule is the commented “allow-all” rule that I’ll keep around in case I need it while in a hurry; then we have two rules:
- the first rule allow any device identified as a user in the
admin
group to access everything; this means any untagged device, so in this example the “laptop” and “raspberry-pi”. - the second rule allow any device tagged with
internet
to access port9100
on the Raspberry Pi.
To summarise the rules we have defined:
- the “laptop” and “raspberry pi” devices can access all ports of any device in our Tailscale network
- the virtual server (by the virtue of being tagged with the tag
internet
) can only access the “raspberry pi” device on port9100
Logging
If you run Tailscale on a Raspberry Pi you might want to consider limiting the amount of logging
produced by the tailscaled
daemon which is written on the SD card; if you’re running the Raspberry
Pi OS (i.e. Debian) and you want to just drop all tailscaled
logs then write the following
configuration in /etc/rsyslog.d/10-tailscaled.conf
:
:programname, isequal, "tailscaled" stop
Restart rsyslog
to apply the configuration:
sudo systemctl restart rsyslog
Closing words
As a person who played with other VPN softwares in the past, like IPSEC, OpenVPN and tinc, the simplicity of Wireguard feels incredible. What Tailscale adds to that is ease of use and nice features that really bring back the joy of the LAN.
Donate to Wireguard if you can.
Get Tailscale for free or check their pricing page.