Let your servers join your Tailscale tailnet with Terraform and cloud-init

First generate an oauth client credentials for use in Terraform by going to https://login.tailscale.com/admin/settings/oauth and clicking “Generate oauth client”:

Screenshot 2024-08-03 at 13.57.36.png

Note down your oauth_client_id and you oauth_client_secret.

Inside Terraform first add the Tailscale provider:

terraform {
  required_providers {
    tailscale = {
      source  = "tailscale/tailscale"
      version = "0.16.1"
    }
  }
}

After running terraform init, you can then create a file named tailscale.tf and insert this:

provider "tailscale" {
  oauth_client_id = ""
  oauth_client_secret = ""
}

resource "tailscale_tailnet_key" "hourlykey" {
  reusable      = true
  ephemeral     = true
  preauthorized = true
  expiry        = 3600
  description   = "Hourly key Terraform managed"
  tags          = ["tag:server"]
}

Now Terraform will automatically create tailnet keys that works just for an hour, and they will automatically expire, but give you enough time to bootstrap servers and for them to join your Tailnet, neat!

So how do we use it? #

Most providers allow for a user_data configuration option that uses cloud-init, some commands that will be run when the server boots:

resource "digitalocean_droplet" "server" {

  user_data = <<EOF
#cloud-config
runcmd:
  - tailscale up --authkey ${tailscale_tailnet_key.hourlykey.key} --accept-routes --accept-dns
EOF

Some people like to add a command that also downloads the Tailscale client, this means that your Tailscale will be up to date, but I don’t like the idea of installing software when I boot up servers, instead I prebake the Tailscale installation into my Packer images. But if you’d like to setup Tailscale as part of cloud-init you do this:

resource "digitalocean_droplet" "server" {

  user_data = <<EOF
#cloud-config
runcmd:
  - ['sh', '-c', 'curl -fsSL https://tailscale.com/install.sh | sh']
  - tailscale up --authkey ${tailscale_tailnet_key.hourlykey.key} --accept-routes --accept-dns
EOF

So now everything is great, right? #

Not so fast! Because what happens if we run Terraform an hour later after our key have expired? Terraform will try and replace our servers with new servers using the newly generated Tailscale key!

The way to avoid is to ignore changes to user_data, so the final configuration looks like this:

resource "digitalocean_droplet" "server" {

  user_data = <<EOF
#cloud-config
runcmd:
  - ['sh', '-c', 'curl -fsSL https://tailscale.com/install.sh | sh']
  - tailscale up --authkey ${tailscale_tailnet_key.hourlykey.key} --accept-routes --accept-dns
EOF

  lifecycle {
    ignore_changes = [
      user_data
    ]
  }
 
0
Kudos
 
0
Kudos

Now read this

Easier installation of NixOS on Linode

The guide from the official wiki on how to install NixOS at Linode is very manual, and that can get a bit time consuming if you have to do it a lot of times. I have therefore made a script that does the same, but is more automated. 1.... Continue →