Hey everyone! 👋 I've been knee-deep in setting up a smooth onboarding flow for our dev team's Tailscale access, and I wanted to share the automation recipe I cooked up. It connects Slack, a simple backend, and Tailscale's API to handle the whole process from request to configured device. The goal was to eliminate manual ACL edits and direct admin involvement for every single new hire or contractor.
The core idea is simple: a user requests access in a Slack channel via a shortcut or command, that triggers a backend workflow which calls the Tailscale API to create a pre-authorized ephemeral node, and then sends an invite link back to the user (and the admin channel) automatically. Here's the step-by-step breakdown:
**The Stack:**
* **Tailscale:** For the network, using an OAuth client (service account) for API access.
* **Slack:** For the request interface and notifications.
* **Make.com** (you could use Zapier, a custom script, or any middleware): As the orchestrator.
* **A tiny backend** (I used a Flask app on Fly.io): To securely generate the ephemeral device keys.
**The Gotchas & Key Decisions:**
1. **API Authentication:** You need to create an OAuth client in your Tailscale admin panel. This gives you a `TAILSCALE_API_TOKEN`. Guard this like a password!
2. **Device Key Type:** We use **ephemeral keys** (`ephemeral: true`) for onboarding. This is crucial because they expire automatically, which is much safer for one-time invites.
3. **Pre-authorization:** The magic happens by creating the device key **first** with the `POST /api/v2/tailnet/-/keys` endpoint, pre-authorizing it for your tailnet and tags. Then, you craft the invite link manually.
4. **The Invite Link:** It's not a standard "invite". You build it like this: ` https://login.tailscale.com/admin/invite/`. The `` is the `key` property from the API response.
Here's a simplified version of the critical backend code (Python) that creates the pre-authorized key:
```python
import requests
TAILSCALE_API_TOKEN = "your_tskey-api-..."
TAILNET = "your-tailnet.example.com"
def create_ephemeral_device_key(tags=None):
url = f"https://api.tailscale.com/api/v2/tailnet/{TAILNET}/keys"
headers = {"Authorization": f"Bearer {TAILSCALE_API_TOKEN}"}
data = {
"capabilities": {
"devices": {
"create": {
"reusable": False,
"ephemeral": True,
"preauthorized": True,
"tags": tags or ["tag:onboarding"] # Tag it for ACL targeting
}
}
}
}
response = requests.post(url, json=data, headers=headers)
response.raise_for_status()
return response.json() # Contains the 'key' field for the invite link
```
**The Workflow:**
1. User triggers Slack shortcut (`/tailscale-request`).
2. Make.com captures the user's Slack ID and fires a webhook to my backend.
3. Backend calls the Tailscale API (as above), gets the key, builds the `login.tailscale.com/admin/invite/...` URL.
4. Backend returns the invite URL to Make.
5. Make sends a **direct message** to the requester in Slack with the link and simple instructions.
6. Make *also* posts to a private `#tailscale-admin` log channel with who requested and the key details for audit.
This has cut down our admin overhead significantly and ensures new team members can get access within minutes, not hours. The main pitfalls were around ACLsβremember, the tags you assign during key creation must be defined and permitted in your Tailscale ACL policy!
Has anyone else built similar onboarding automations? I'd love to compare notes, especially on handling device expiration notifications or integrating with HR systems.
-- Ian
Integration Ian