tailscale-wiflisted
Install: claude install-skill JRichlen/claude-plugins
# Tailscale Workload Identity Federation (WIF) for GitHub Actions
## Invariant
WIF auth is **secretless**. Only the **public** `oauth-client-id` and `audience`
are stored — and they belong in repo **variables**, never secrets. The job that
authenticates to Tailscale always carries `permissions: id-token: write`, and it
passes **exactly one** auth mode. No long-lived Tailscale credential (a REST API
key, an OAuth client secret) is ever stored to enable a run: each run mints a
fresh GitHub OIDC token, and a Tailscale Trust Credential exchanges it for a
short-lived (~1h) API token or an ephemeral auth key that expires on its own.
If a change would put a Tailscale secret back into the workflow, drop
`id-token: write`, or pass two auth modes at once, it breaks this plugin's whole
reason to exist. The cheap eval (`evals/cheap/checks.sh`) defends the marker
facts below.
## Why WIF
Stored Tailscale credentials are the thing you are removing:
- **REST API keys** expire in **90 days or less** — someone has to rotate them,
and a leaked key is valid until it expires.
- **OAuth client secrets** are long-lived bearer secrets — a leak is worse.
WIF (a GA Tailscale feature) replaces both. Trust flows the other way: instead of
handing Tailscale a stored secret, each workflow run proves its identity with a
GitHub-signed **OIDC token**, and Tailscale's **Trust Credential** (configured in
the admin console) decides whether to trust that identity and, if so, mints a
short-lived token. Be