One tag for all the worker machines

Christian Drexler

A couple of machines in my Tailscale network are never touched by hand: an always-on Mac for scheduled jobs and a small Linux box that builds things. Then there is my laptop and my phone. The first version of my access rules named each machine, and every time something joined I edited three places and got one of them wrong. Tags fix this: a machine carries a label, and the rules talk about the label.

What a tag is

In Tailscale a device normally belongs to the user who logged it in. A tagged device belongs to no user; it belongs to the tag, and the tag is owned by whoever the policy file says. Two consequences I like. Rules can say "any member may reach tag:worker" without listing machines. And tagged devices have no login to expire, so the 180-day key expiry that strands headless machines does not apply to them.

The policy

The policy file is HuJSON in the admin console. Three sections matter:

{
  "tagOwners": { "tag:worker": ["autogroup:admin"] },
  "acls": [
    { "action": "accept", "src": ["autogroup:member"], "dst": ["tag:worker:22,8080"] }
  ],
  "ssh": [
    { "action": "accept", "src": ["autogroup:member"], "dst": ["tag:worker"], "users": ["autogroup:nonroot"] }
  ]
}

tagOwners says admins may apply the tag. The ACL lets any member of the network (laptop, phone) reach a worker on SSH and one web port. The SSH rule lets me log in to a worker as any non-root account with my Tailscale identity, no key files. There is no rule with a worker as the source, so a worker cannot open a connection to my laptop or to another worker. A one-way street by default, which is what I want from a machine that runs unattended.

Tagging a machine

On the machine: sudo tailscale up --ssh --advertise-tags=tag:worker, logged in as an account that owns the tag. For a fresh box I generate an auth key in the admin console with the tag preselected and "pre-approved" ticked; then tailscale up --auth-key=... --advertise-tags=tag:worker joins it with the right tag and no browser login at all. That is the whole onboarding for a new worker: one command, and the rules already apply.

What changed day to day

Adding a machine is no longer a policy edit. My phone opens a worker's status page on port 8080 because the phone is a member and the rule says member to worker. tailscale status shows tagged machines with their tag, so I see at a glance what is a worker and what is a person. When I retire one, I delete it from the console and nothing else references it.

Two gotchas

Once a device is tagged, the default rule that lets you SSH to "your own" devices (autogroup:self) no longer matches it, because it is not yours any more. If you tag a machine and SSH stops, that is why; the explicit tag rule above is the fix. And --advertise-tags fails with a permission error when the logged-in account is not in tagOwners. The message is clear enough, but the first time it looks like a typo in the tag name.

Three machines is where this started to pay off. With one it is ceremony; with a handful it is the difference between a policy you read and a policy you search.