iA Blog

Automatically Connect to Tailscale in NixOS with OAuth Secrets

22 Feb 2024 | servers, nixos, tailscale

On my NixOS powered machines, I wanted the machines to automatically connect to Tailscale. Usually, you would need to authenticated via a web browser in order to add a device to Tailscale. You could bypass (for automation purposes etc.) using an auth key, but auth keys only have a max validity of 90 days. If I were to reinstall NixOS after that the auth key would cease to work and I’ll need to regenerate the key, which isn’t very ideal. As a result, I just opted to manually authenticate every NixOS machine I own.

Recently, I came across a Tailscale blog post on how to add docker containers to Tailscale. It turns out, apart from auth keys, you can also use an OAuth secret to authenticate with Tailscale.

Auth Keys vs OAuth Secret

As summarized by the blog post mentioned above, OAuth secrets do not expire, but you must assign a tag to the machines authenticated via OAuth secrets. Tagged machines have a different set of access control rules applied, so you’ll need to set those rules. After updating the ACL file, I was able to recover most of the features, except for SSH-ing to untagged machines. At the time of writing, there is no way to allow tagged machines to SSH to untagged machines, but it is a tradeoff that I’m willing to make.

Setting it up

Step 1: Creating a new tag in Tailscale

Go to Tailscale dashboard > Access control, and add the following to the ACL file:

  // Define the tags which can be applied to devices and by which users.
	"tagOwners": {
		"tag:nixos": ["autogroup:admin"],

Step 2: Allow SSH to and from tagged machines

In the same ACL file, we add the two entries below to SSH to and from tagged machines via Tailscale SSH without authenticating. As mentioned before, SSH from a tagged machine to an untagged one is unsupported.

  "ssh": [
      // SSH without authenticating
      "action": "accept",
      // SSH from untagged machines
      "src":    ["autogroup:member"],
      // SSH to untagged machines owned by the same user and all tagged machines
      "dst":    ["autogroup:self", "autogroup:tagged"],
      // Allow all SSH users except root
      "users":  ["autogroup:nonroot"],
      // SSH without authenticating
      "action": "accept",
      // SSH from tagged machines
      "src":    ["autogroup:tagged"],
      // SSH to all tagged machines
      "dst":    ["autogroup:tagged"],
      // Allow all SSH users except root
      "users":  ["autogroup:nonroot"],

Step 3: Enable Tailscale daemon in NixOS

Add the following in your NixOS config:

{ pkgs, ... }: {
  services.tailscale.enable = true;

  # use the latest and greatest version of tailscale
  services.tailscale.package = pkgs.unstable.tailscale;

Step 4: Add systemd Startup Script

I stole the example found in Tailscale’s blog on how to set up Minecraft in NixOS with Tailscale and tweaked it like so:

  # create a oneshot job to authenticate to Tailscale
  systemd.services.tailscale-autoconnect = {
    description = "Automatic connection to Tailscale";

    # make sure tailscale is running before trying to connect to tailscale
    after = [ "network-pre.target" "tailscale.service" ];
    wants = [ "network-pre.target" "tailscale.service" ];
    wantedBy = [ "multi-user.target" ];

    # set this service as a oneshot job
    serviceConfig.Type = "oneshot";

    # have the job run this shell script
    script = with pkgs; ''
      # wait for tailscaled to settle
      sleep 2

      # authenticate with tailscale
      ${tailscale}/bin/tailscale up --auth-key=$TAILSCALE_AUTH_KEY

Where $TAILSCALE_AUTH_KEY is a secret that is managed by the NixOS secrets manager of your choice.

Full Example

A real life example could be found in my dotfiles repository. I’ve added a few Nix options so I could toggle specific options for different machines.

Adwin Ying's avatar
Adwin Ying

Self-taught full-stack web dev based in Tokyo. Occasionally wrecks servers through  self-hosting  and  homelab-ing.

← Back to all posts