Automation and device trust

Use OAuth clients for repeated automation

Replace a long-lived reusable auth key with an OAuth client that creates short-lived, scoped auth keys when needed.

Repeated automation should never share one reusable enrollment credential across every environment. An OAuth client solves this by minting fresh, short-lived keys on demand.

Picture a reusable auth key in five CI pipelines. That is five copies of the same secret, one expiry date, and no way to tell which pipeline enrolled which node. When it leaks, and shared long-lived secrets do leak, you rotate everything at once, in a hurry.

What an OAuth client changes

A Tailscale OAuth client is a credential with limited scopes, the operations it may perform, and a fixed set of tags it may hand out. Automation uses the client secret to request a fresh auth key, then enrolls the node with that key.

Create the client in the admin console with only the auth keys scope and only the tags it needs, such as tag:ci. The client can mint keys, but never keys with broader power than its own scope and tags.

That bound is the security win. A compromised CI system can enroll tag:ci nodes. It cannot enroll tag:server nodes, so it cannot reach whatever your servers can reach.

The minting flow

First, the automation exchanges its client credentials for an API access token:

curl -s -d "client_id=$TS_CLIENT_ID" -d "client_secret=$TS_CLIENT_SECRET" \
  https://api.tailscale.com/api/v2/oauth/token

The response is JSON with an access_token field. With that token, the automation calls the keys API to create a one-off, ephemeral, pre-tagged auth key. Then it passes that key to enrollment:

sudo tailscale up --auth-key="$TS_MINTED_KEY" --advertise-tags=tag:ci

Each job gets its own key, used once, expiring fast. Nothing long-lived ever touches a runner. If someone dumps the runner’s environment, they find a key that already did its one job.

Keep the secret in one place

The OAuth secret is powerful, so it lives in exactly one place: your secret manager. Not copied into each pipeline. Scope its tags narrowly, and rotate the client if the secret is ever exposed. Rotation is one action in the console, and nothing else needs to change.

Design the lab flow

Sketch an enrollment flow for CI runners that creates one ephemeral tagged node per job and removes access when the job ends. You need the OAuth client, one API call to mint a key, one tailscale up, and nothing else.

With ephemeral keys, removal is free. The node evaporates once it goes offline. The audit story improves too, because every enrollment traces back to one client and one job, instead of one shared key everybody had.

Lesson completed