swap-dns
Move an environment's DNS, and its certificates' DNS-01 validation, off Cloudflare (to a name server of our own over RFC 2136) or to another DNS provider. Use when the user wants to leave Cloudflare,
Files1
View on GitHubSKILL.md.claude/skills/swap-dns/SKILL.md
GitHubSwap the DNS provider
- Interface:
dnsininfra/tofu/envs/k3s/variables.tf(provider, and the provider's settings). Each provider is a module that takes the same records (local.recordsinenvs/k3s/main.tf: the zone, site hosts, origins, the preview host, the mail records) and outputsrecordsin one shape:modules/cloudflare,modules/rfc2136. - The cluster learns it from OpenTofu's annotations on its Argo CD Secret
(
dns-provider,trusted-hops,origin-pulls, and the provider's own: RFC 2136'sdns-nameserver,dns-tsig-key-name,dns-tsig-algorithm), which the platform's add-ons read throughclusterParameters(deploy/platform/addons): cert-manager's solver (tls.dns01indeploy/platform/config), external-dns'sprovider.name(deploy/platform/values/external-dns.yaml), and what the gateway trusts (gateway.trustedHops,gateway.originPulls). - Today: Cloudflare (
dns.provider = "cloudflare", the default), with its proxy in front of the site. RFC 2136 is built in:dns = { provider = "rfc2136", rfc2136 = { server, key_name } }andTF_VAR_dns_tsig_secret.
Move to RFC 2136 (a name server of our own)
- A name server for the zone that accepts dynamic updates signed with a TSIG key
(BIND
allow-update { key ...; }, Knot, PowerDNS), reachable from where OpenTofu runs and from the cluster on port 53. Delegate the zone to it at the registrar. - In the environment's tfvars:
dnsas above; dropcloudflare_account_idandmanaged_waf. ExportTF_VAR_dns_tsig_secret. - SOPS secrets in
deploy/platform/secrets/<env>/(rotate-secrets skill):rfc2136-tsigincert-manager(keysecret), andexternal-dns-rfc2136inexternal-dns(keyshost,zone,tsig-keyname,tsig-secret,tsig-secret-alg). Remove the Cloudflare token's. tofu apply: the records move, the annotations change, and Argo CD re-renders the issuer, external-dns and the gateway (which now trusts no proxy and asks for no client certificate). Previews' and the mail host's records are unchanged in kind.- The captcha was Cloudflare's Turnstile widget (
tofu output turnstile): keep the widget on Cloudflare's account, or turn the captcha off (unsetTURNSTILE_*).
Another provider
- A module
infra/tofu/modules/<provider>with the same inputs asmodules/rfc2136and arecordsoutput of the same shape, with atests/*.tftest.hclagainstmock_provider. Add it toenvs/k3s/main.tfwithcountonvar.dns.provider, its settings todns, and its provider toversions.tf. - cert-manager's solver for it in
deploy/platform/config/templates/issuer.yaml(and a helm-unittest case), and external-dns's credentials in its values, each optional. - Annotations for anything the cluster needs that isn't secret; secrets go in SOPS.
Tests
bun run infra:check (the env root's tests run each provider), bun run charts:check
(the issuer for each provider), bun test scripts/appsets.test.ts (every cluster fact an
add-on reads is one OpenTofu writes). A real zone is tried only on a real cluster: the
first certificate after a switch is the proof (kubectl get certificate -A).
Finish
- The verify skill.
- Ask the
security-revieweragent to review the change: it moves who can change the zone's records and who the gateway trusts for the client's address. - Update the DNS row in the README's "Scaling path" table if what's "Now" changed.