Tailscale: IaC Management
Level 2 (Topic) — Terraform provider, ACL as code, OAuth client model.
Concept
Tailscale resources are managed as infrastructure-as-code in ephemeral-castle/tailscale/. The Terraform provider manages ACL policy, tailnet settings, and OAuth clients. Auth keys are generated dynamically at runtime rather than stored in state.
Key Files
| File | Role |
|---|---|
main.tf | ACL policy, tailnet settings, OAuth client |
acl.json | Tag ownership and ACL rules (source of truth) |
variables.tf | Input variables (tailnet, API key) |
outputs.tf | Exported outputs |
versions.tf | Provider version constraints |
setup.sh | Initial tailnet setup helper |
ACL as Code
The ACL policy is defined in acl.json and applied via tailscale_acl resource:
resource "tailscale_acl" "tazlab" {
acl = file("${path.module}/acl.json")
}
This is a hard replace-on-create resource — any drift in the JSON file is corrected on the next terraform apply.
OAuth Client Model
The bootstrap OAuth client generates short-lived auth keys at runtime instead of persisting them:
resource "tailscale_oauth_client" "bootstrap" {
description = "tazlab-bootstrap"
scopes = ["auth_keys", "devices"]
tags = ["tag:tazpod"]
}
A second OAuth client is used by the Tailscale Kubernetes Operator for service exposure:
resource "tailscale_oauth_client" "k8s_operator" {
description = "tazlab-k8s-operator"
scopes = ["devices", "auth_keys", "services"]
tags = ["tag:k8s-operator"]
}
The k8s_operator client requires the services scope (bug #19471 in v1.96.x) — without it, the operator’s Tailnet CR validation fails with InvalidOAuth, blocking proxy creation for Ingress/LoadBalancer exposure.
The operator daemon (tazpod-tailscale-up) uses OAuth client credentials from ~/secrets/ to mint 1-hour auth keys on demand. This avoids storing long-lived keys in Terraform state or encrypted vault.
Tailnet Settings
resource "tailscale_tailnet_settings" "tazlab" {
devices_approval_on = false
devices_auto_updates_on = false
devices_key_duration_days = 180
}
See Also
- Detail: Terraform Root Detail
- Detail: OAuth Client Detail
- Reference: acl.json, main.tf
- Hub: Tailscale