# Cloudflare side of the edge. # # The tunnel itself is remotely managed today: its token lives in # k8s/apps/cloudflared and the public hostnames are configured in the Zero # Trust dashboard. Terraform can own the DNS records without owning the tunnel, # which is the safe half: a record change is reversible, a tunnel config rewrite # removes every hostname the plan does not list. locals { # CNAME target of every remotely-managed tunnel. tunnel_target = "${var.tunnel_id}.cfargotunnel.com" } resource "cloudflare_dns_record" "tunnel" { for_each = toset(var.cloudflare_tunnel_hostnames) zone_id = var.cloudflare_zone_id name = each.value type = "CNAME" content = local.tunnel_target proxied = var.cloudflare_dns_proxied ttl = var.cloudflare_dns_ttl comment = "cloudflared tunnel; managed by terraform/edge" # A proxied CNAME must point at the tunnel target. A CNAME to any other # hostname breaks the tunnel mapping. lifecycle { precondition { condition = var.cloudflare_dns_proxied error_message = "Tunnel CNAMEs must be proxied; an unproxied record bypasses the tunnel." } } } # Optional: take the tunnel configuration into Terraform. Off by default. # Applying it REPLACES the whole ingress list. Import first: # terraform import cloudflare_zero_trust_tunnel_cloudflared_config.this \ # / resource "cloudflare_zero_trust_tunnel_cloudflared_config" "this" { count = var.manage_tunnel_config ? 1 : 0 account_id = var.cloudflare_account_id tunnel_id = var.tunnel_id config = { ingress = concat( [for host, service in var.tunnel_ingress : { hostname = host, service = service }], [{ service = "http_status:404" }], ) } }