Secure Tailscale networks with firewalld
Table of Contents
Much of my daily work involves using multiple clouds and I do the same for my personal infrastructure, too. Building mesh networks between each piece of cloud infrastructure, my home, and my mobile phone quickly became overwhelming. That’s where Tailscale came in and completely changed my workflow.
What is Tailscale? #
The company claims it’s “a secure network that just works” and that definition fits well. Tailscale builds on protocols used in Wireguard to dynamically maintain a mesh network between any number of devices. Forget about sharing keys, managing complex IP space, and automating configuration changes. It handles all of that for you.
Setting up Tailscale is outside of the scope of this post, but once you get going, you can add a node to the network and access anything else running Tailscale within your account. The free account comes with 20 devices and a subnet router.
A subnet router allows you to install Tailscale on one device (perhaps one device in your home) and then relay traffic to all devices on that network through that single node. I use this on my home router and this saves me the work of installing Tailscale on multiple devices at home.
Even private networks need security #
Tailscale does give you a private mesh network with automatically updating encryption keys and access control lists (ACLs), but it needs to be secured like any other private network. If an attacker gains access to any of the nodes you have running Tailscale, then they could potentially wander throughout your Tailscale network.
You may be tempted to trust all traffic on your Tailscale network, but a firewall gives you one extra layer of protection so you’re only exposing the right ports to the right nodes. I wrote about the need for host firewalls (even in the cloud) on the Red Hat blog.
Tailscale and firewalld #
I use firewalld to manage my firewall configuration and to keep it consistent for both IPv4 and IPv6 connections. You can use it to easily secure your Tailscale network.
For those unfamiliar with firewalld, it uses zones to define what traffic should be allowed in or out of a system. Each zone can have lots of rules assigned for certain services, ports, sources, and destinations. You can add network interfaces to each zone to control access.
A router has a public-facing port that goes out to the internet and an
internal-facing port that goes to the local area network (LAN). I put my
internet-facing network device in the public
zone and I put the
internal-facing network device in the internal
zone. Then I can allow inbound
DNS on the internal
zone but block it in the public
zone.
Tailscale adds a network interface called tailscale0
by default. All of the
traffic that flows into and out of your mesh network goes through that device.
First off, decide which firewall zone you want to use for Tailscale. You could
certainly create a new zone, but I’m using dmz
for mine.
$ sudo firewall-cmd --list-all --zone=dmz
dmz
target: default
icmp-block-inversion: no
interfaces:
sources:
services: ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
By default, dmz
allows the ssh service and nothing else. If you want to expose
a web server to the Tailscale network, just add the services:
$ sudo firewall-cmd --add-service=http --zone=dmz
$ sudo firewall-cmd --add-service=https --zone=dmz
The last step is to add the tailscale0
interface to the dmz
zone:
$ sudo firewall-cmd --add-interface=tailscale0 --zone=dmz
Now we can check the zone to be sure everything is ready:
$ sudo firewall-cmd --list-all --zone=dmz
dmz
target: default
icmp-block-inversion: no
interfaces: tailscale0
sources:
services: http https ssh
ports:
protocols:
forward: no
masquerade: no
forward-ports:
source-ports:
icmp-blocks:
rich rules:
The last step is to save the firewall configuration to permanent storage so that it’s applied after a reboot:
$ sudo firewall-cmd --runtime-to-permanent
Enjoy! 💻
Photo credit: zhang kaiyv