[infra] Auto-create Cloudflare DNS records from ingress_factory

## Context

Deploying new services required manually adding hostnames to
cloudflare_proxied_names/cloudflare_non_proxied_names in config.tfvars —
a separate file from the service stack. This was frequently forgotten,
leaving services unreachable externally.

## This change:

- Add `dns_type` parameter to `ingress_factory` and `reverse_proxy/factory`
  modules. Setting `dns_type = "proxied"` or `"non-proxied"` auto-creates
  the Cloudflare DNS record (CNAME to tunnel or A/AAAA to public IP).
- Simplify cloudflared tunnel from 100 per-hostname rules to wildcard
  `*.viktorbarzin.me → Traefik`. Traefik still handles host-based routing.
- Add global Cloudflare provider via terragrunt.hcl (separate
  cloudflare_provider.tf with Vault-sourced API key).
- Migrate 118 hostnames from centralized config.tfvars to per-service
  dns_type. 17 hostnames remain centrally managed (Helm ingresses,
  special cases).
- Update docs, AGENTS.md, CLAUDE.md, dns.md runbook.

```
BEFORE                          AFTER
config.tfvars (manual list)     stacks/<svc>/main.tf
        |                         module "ingress" {
        v                           dns_type = "proxied"
stacks/cloudflared/               }
  for_each = list                     |
  cloudflare_record               auto-creates
  tunnel per-hostname             cloudflare_record + annotation
```

## What is NOT in this change:

- Uptime Kuma monitor migration (still reads from config.tfvars)
- 17 remaining centrally-managed hostnames (Helm, special cases)
- Removal of allow_overwrite (keep until migration confirmed stable)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Viktor Barzin 2026-04-16 13:45:04 +00:00
parent 95d2a6abf8
commit b1d152be1f
94 changed files with 471 additions and 34 deletions

View file

@ -58,15 +58,20 @@ resource "cloudflare_zero_trust_tunnel_cloudflared_config" "sof" {
warp_routing {
enabled = true
}
dynamic "ingress_rule" {
for_each = toset(var.cloudflare_proxied_names)
content {
hostname = ingress_rule.value == "viktorbarzin.me" ? ingress_rule.value : "${ingress_rule.value}.viktorbarzin.me"
path = "/"
service = "https://10.0.20.200:443"
origin_request {
no_tls_verify = true
}
# Wildcard rule routes all subdomains through tunnel to Traefik.
# Traefik handles host-based routing via K8s Ingress resources.
ingress_rule {
hostname = "*.viktorbarzin.me"
service = "https://10.0.20.200:443"
origin_request {
no_tls_verify = true
}
}
ingress_rule {
hostname = "viktorbarzin.me"
service = "https://10.0.20.200:443"
origin_request {
no_tls_verify = true
}
}
ingress_rule {