Skip to content

Tailscale

Tailscale ⧉ is a managed VPN solution built on top of the WireGuard ⧉ protocol. We use it to allow a number of our instances in different networks to communicate with each other.

Managing WireGuard servers and clients directly would be possible. Tailscale takes that work off our hands. New clients join the VPN seamlessly, and clients inactive for a while are cleaned up.

In accordance with official Tailscale lingo, we refer to instances running Tailscale as Tailscale nodes and the created VPN as our tailnet.

Documentation gap

The Tailscale-plus-DNS networking setup is complex and under-documented, the DNS half in particular. Terragrunt is also not yet used for the tailscale Terraform. See /infra/terraform.

Our tailnet

Currently our main use for Tailscale is connecting instances outside of our GCP VPC and instances within it. This works as follows:

One or more dedicated *tailscale-subnet-router* instances in our VPC run Tailscale and advertise routes to instances in said VPC. One would be sufficient, but we may run multiple subnet-routers for high availability. All of them advertise the same routes, allowing Tailscale to fail over between them.

Instances outside the VPC may also run Tailscale. They automatically become aware of the routes advertised by the subnet-router Tailscale nodes. They then send all packets headed for VPC-internal IP addresses via the tailscale0 interface. These eventually make their way to one of the subnet-router machines which is configured to forward them to the target machine.

Tailscale subnet-routers SNAT routed packets by default, so return traffic works seamlessly.

The access control list

Due to the way Tailscale operates (at least by default), all of our deployment environments are part of the same tailnet. To prevent stray traffic between them we use Tailscale's access control list (ACL) feature.

The ACL is configured via Terraform (/infra/terraform/tailscale). An excerpt of the generated ACL file ⧉ may look as follows:

{
    "action": "accept",
    "dst":    ["10.0.0.0/20:*"],
    "src":    ["tag:external-production"]
}

All Tailscale nodes tagged with external-production may send traffic to 10.0.0.0/20. Tags are supplied when first starting Tailscale on an instance.

Human and CI runner access

Other than automatically provisioned instances, human users as well as GitHub CI runners can also connect to our tailnet.

For both, who is eligible is controlled by Terraform. For human users the source of truth here is /people. All users in the tailscale group can connect to our tailnet. group:people* ACL rules control what they can access. GitHub CI runners use federated identities to authenticate with Tailscale, i.e. no secret credentials are required. tag:ci* rules control what they can access.