No description
  • Just 41.8%
  • HCL 30%
  • JavaScript 14.5%
  • Shell 13.7%
Find a file
Ryan Grippeling 5fb396d5b6
All checks were successful
[Workflow] Apply / Apply (push) Has been skipped
[Workflow] Apply / DNS Push (push) Successful in 22s
[Workflow] On Source Change / Static Analysis (push) Successful in 22s
[Workflow] On Source Change / DNS Preview (push) Successful in 19s
[Workflow] On Source Change / Plan (push) Successful in 33s
fix(renovate): de checkout-major mag weer, de aanname is weerlegd
"actions/checkout v6 is broken on non-GitHub runners" stond hier als losse kopie
van een estate-brede regel die nooit gemeten was. De canary in homelab-cluster
(run 1710) draait checkout v5.1.0, v6 en v7 en setup-node v4.4.0, v5 en v7 op de
echte Forgejo-runner: alles groen, en geen no-ops.

Niet op automerge. Eén canary-job is niet de pipeline van deze repo, en een
DNS-apply is geen wijziging die je een bot ongezien wilt laten landen.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-18 13:39:40 +02:00
.forgejo/workflows feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
dns feat(dns): de zone twente.dev verhuist naar zijn eigen repo 2026-09-17 06:59:00 +02:00
docs feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
scripts fix(tools): de pin-helper struikelde over de slash in de dnscontrol-sleutel 2026-09-05 15:04:55 +02:00
.editorconfig chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
.gitignore feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
.terraform.lock.hcl chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
account_r2.tf feat(zones): twente.dev, de mailrecords van webgrip.nl en de Counterscale-bucket als resources 2026-09-05 06:24:58 +02:00
AGENTS.md feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
backend.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
catalog-info.yml chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
CLAUDE.md chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
CODEOWNERS chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
encryption.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
justfile feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
LICENSE chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
mise.lock feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
mise.toml feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
mkdocs.yml chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
outputs.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
providers.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
README.md feat(dns): de zone twente.dev verhuist naar zijn eigen repo 2026-09-17 06:59:00 +02:00
removed.tf feat(dns): DNSControl voor de records en de redirect, OpenTofu voor de rest 2026-09-05 09:38:13 +02:00
renovate.json fix(renovate): de checkout-major mag weer, de aanname is weerlegd 2026-09-18 13:39:40 +02:00
variables.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
versions.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00
zones.tf chore(repo): skeleton voor de Cloudflare-zones en accountresources in OpenTofu 2026-09-05 05:25:59 +02:00

cloudflare

The Cloudflare account and zone resources Webgrip's sites sit on, as code, applied from Forgejo Actions. Two tools, one boundary:

  • DNSControl owns the DNS records and the redirect rules: dns/dnsconfig.js, one readable line per record, no state file. It diffs the file against the live zone.
  • OpenTofu owns the account and zone objects DNSControl cannot express: the R2 bucket, and later DNSSEC toggles, zone settings and Zero Trust Access. Root module in this directory, state in R2, encrypted.
  • Workers, their routes, bindings and custom domains stay in each site's wrangler.toml.

The decision and its boundary are twente.dev ADR 0018. Nothing in this repository is edited in the Cloudflare dashboard: a dashboard edit shows up in the nightly drift run and is reverted by the next push or apply.

What is managed here, and by whom

Resource Owner
twente.dev: every DNS record, CAA included DNSControl in twente.dev ops/dns/dnsconfig.js, moved out of this repo on 2026-09-17; the zone object itself stays here as the cloudflare_zone data source
twente.dev: Worker routes twente.dev/* and mta-sts.twente.dev/* twente.dev wrangler.toml
webgrip.nl: MX, SPF, DKIM (google and the email selector under mail.webgrip.nl), DMARC, the Brevo send. set, the verification TXT records DNSControl, dns/dnsconfig.js
webgrip.nl: the www -> apex 301 DNSControl, CF_SINGLE_REDIRECT in dns/dnsconfig.js, path and query preserved; the legacy Page Rule that answered until 2026-09-05 (bare apex, path and query dropped) is deleted by hand, since Page Rules refuse account-owned tokens
webgrip.nl: apex A legacy hand-made record, IGNORE("@", "A"), untouched on purpose
webgrip.nl: www A and every k8s.* TXT external-dns in homelab-cluster, IGNORE("www", "A") and IGNORE("k8s.*", "TXT")
webgrip.nl: staging.k8s A and *.staging.k8s CNAME dead DigitalOcean records, declared once for a zero-diff start and removed in the next commit
Both zones: DNSSEC toggles, zone settings OpenTofu, not yet declared
webgrip.dev: everything, including counterscale.webgrip.dev external-dns, cert-manager and wrangler's custom_domain; iteration 2
R2 bucket counterscale-daily-rollups OpenTofu, account_r2.tf
R2 bucket tofu-state, the R2 token for it, the forgejo-ci-tofu API token hand-made bootstrap exception, docs/bootstrap.md
Email Routing objects, the Web Analytics site unmanaged

How a change lands

  1. Edit dns/dnsconfig.js or the HCL on a branch and push. [Workflow] On Source Change runs dnscontrol check and dnscontrol preview, and tofu fmt, tofu validate and tofu plan; both previews are in the job summaries.
  2. Fast-forward main. [Workflow] Apply runs two gated jobs: DNS Push previews again, refuses a deletion unless the commit body carries DNS-Allow-Delete: <record name> per deleted record, then pushes; Apply plans with a lock, refuses a destroy unless the commit body carries Tofu-Allow-Destroy: <resource address>, refuses imports and an empty state, then applies. Both end with a check of the mail records on a public resolver.
  3. [Scheduled] Cloudflare Drift runs both previews against main every morning at 05:30 UTC and fails on any diff.

DNS_PUSH and TOFU_APPLY are repository variables; each job runs only while its variable is on.

DNSControl never touches a record it does not declare unless the record's name is declared too, and IGNORE() protects the names other writers own. A record you want to stop managing without deleting it becomes an IGNORE() line. In the HCL, resource names follow <zone>_<label>_<type>, and removed {} blocks forget a resource without destroying it.

Local credentials

mise install
export BAO_ADDR=<the OpenBao address, see homelab-cluster>
eval "$(just creds)"
just check
just dns-preview
just plan

just creds prints export lines for the five values from OpenBao secret/cloudflare/tofu plus CLOUDFLARE_ACCOUNT_ID from secret/cloudflare/deploy. Nothing is written to disk; dns/creds.json holds only environment variable names.

Variable Used as Source
CLOUDFLARE_TOFU_TOKEN CLOUDFLARE_API_TOKEN for DNSControl and the provider account-owned token forgejo-ci-tofu: Zone Read and DNS Write on twente.dev and webgrip.nl, Dynamic URL Redirects Write on webgrip.nl, Workers R2 Storage Write
CLOUDFLARE_ACCOUNT_ID TF_VAR_cloudflare_account_id, the R2 endpoint, DNSControl's accountid org secret, already published
TOFU_STATE_ACCESS_KEY_ID, TOFU_STATE_SECRET_ACCESS_KEY AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY for the s3 backend R2 API token, Object Read and Write on tofu-state only
TOFU_ENCRYPTION_PASSPHRASE TF_VAR_state_passphrase generated at seeding; losing it means re-importing from HCL

In Forgejo the four TOFU_*/CLOUDFLARE_TOFU_* values are repository secrets on this repo, published hourly by the forgejo-actions-secrets CronJob in homelab-cluster, which also verifies the token against Cloudflare. Seeding: just cloudflare-tofu-cred in homelab-cluster.

Runbooks