ADR-081: Drill OpenTofu Workspace and Tailscale ACL Ownership¶
- Status: Accepted
- Date: 2026-05-08
- Authors: Podcast Scraper Team
- Related RFCs: RFC-082
Context & Problem Statement¶
Disaster-recovery drills need a throwaway Hetzner footprint and distinct tailnet identities
without risking applies against production OpenTofu state or resources. The tailnet-wide
tailscale_acl object must not be contended by two OpenTofu states, or plans will fight in CI
and at apply time.
Decision¶
- Separate OpenTofu workspace named
drillfor all drill-only Hetzner resources, with encrypted state ininfra/terraform/terraform.tfstate.enc.drill(see ADR-080). - Hetzner API token for drill is scoped to the drill project only (
HCLOUD_TOKEN_DRILLin Actions), never reused for prod applies. - Exactly one workspace owns
tailscale_acl: the default / prod OpenTofu workspace. Thedrillworkspace setsmanage_tailscale_acl = falseso drill state does not manage the tailnet ACL resource; ACL changes still land through prodinfra-apply.ymlandtailscale/policy.hujson.
Rationale¶
- Blast-radius isolation — a mistaken
tofu applyindrillcannot delete prod servers because they are not in that state file. - Single writer for ACL — avoids two-state drift on the same Tailscale API object.
- Repeatable drills — destroy workspace
drilland re-apply without touching prod state.
Alternatives Considered¶
- Second git repo for drill — Rejected; duplicates provider versions, modules, and review workflow without adding isolation beyond a workspace + token split.
- Same workspace, different tfvars — Rejected; one state file mixing prod and drill resources raises destroy and plan scope errors.
- Drill manages its own tailnet / ACL — Rejected for this project; one operator tailnet with
tags (
tag:dr-drill,tag:prod) is the chosen model in RFC-082.
Consequences¶
- Positive: GitHub workflows can plan/apply/destroy
drillindependently (seedrill-infra-*anddrill-exercise.yml). - Negative: Operators must remember ACL edits flow through prod infra apply, then drill jobs consume the updated policy.
Implementation Notes¶
- Paths:
infra/terraform/(workspacedrill,terraform.drill.ci.tfvars, drill tfvars example),tailscale/policy.hujson - Docs: DR_DRILL_RUNBOOK.md,
infra/README.md(repo root)