##############################################################################
# https://admin.cfx.to and https://admin.dev.cfx.to, WARP only.
#
# Each name is a proxied record to this tunnel, owned by admin's SST stage
# (packages/admin-dashboard/sst.config.ts) with its certificate records. The
# tunnel's ingress (`tunnel_ingress`) sends the request on to the dashboard's
# CloudFront distribution. The connector's request leaves by its NAT EIP, the
# only address admin's web ACL admits (packages/waf), so this path is the one
# way in.
#
# Access gates the path on the Gateway posture check: a device enrolled in this
# account with its traffic through Gateway. Checked on every request, unlike a
# sign-in-time check. Cognito still signs the operator in behind it.
#
# WARP identity is the normal path: with allow_authenticate_via_warp, a device
# enrolled and signed in to this Zero Trust org passes all four apps with no
# browser Access login, so `cfx` and agent sessions need no `cfx <env> access`
# every 24 h. That command is the fallback. The posture `require` still applies
# to every request. The account's WARP session duration, which Cloudflare
# requires first, is managed in zero_trust_organization.tf; change it there,
# not in the dashboard.
#
# Cloudflare's edge decrypts the request and adds CF-Connecting-IP and the
# visitor location headers; cloudflared passes them to CloudFront, which
# forwards them to the server function. session-client.ts trusts them because
# the viewer is one of the NAT EIPs.
#
# The cfx CLI's write hosts, api.admin.cfx.to and api.admin.dev.cfx.to, get the
# same Access policy. packages/admin-api's stack owns their records, and the
# tunnel sends them to its API Gateway.
##############################################################################

locals {
  admin_dashboard_hosts = [
    "admin.cfx.to",
    "admin.dev.cfx.to",
    "api.admin.cfx.to",
    "api.admin.dev.cfx.to",
  ]
}

# Passes for a device enrolled in this account whose traffic is filtered by
# Gateway. The account's Gateway proxy (TCP and UDP) is on, which it requires.
resource "cloudflare_zero_trust_device_posture_rule" "gateway" {
  account_id  = local.cloudflare_account_id
  name        = "Gateway"
  type        = "gateway"
  description = "The device's traffic goes through this account's Gateway."
}

resource "cloudflare_zero_trust_access_policy" "admin_dashboard" {
  account_id       = local.cloudflare_account_id
  name             = "admin dashboard: cfx.to staff on Gateway"
  decision         = "allow"
  session_duration = "24h"

  include = [{
    email_domain = { domain = "cfx.to" }
  }]

  require = [{
    device_posture = {
      integration_uid = cloudflare_zero_trust_device_posture_rule.gateway.id
    }
  }]
}

resource "cloudflare_zero_trust_access_application" "admin_dashboard" {
  for_each = toset(local.admin_dashboard_hosts)

  account_id       = local.cloudflare_account_id
  name             = "Admin dashboard (${each.value})"
  type             = "self_hosted"
  domain           = each.value
  session_duration = "24h"

  # Cloudflare refuses this until the account's WARP session duration is set.
  allow_authenticate_via_warp = true
  depends_on                  = [cloudflare_zero_trust_organization.this]

  destinations = [{
    type = "public"
    uri  = each.value
  }]

  policies = [{
    id         = cloudflare_zero_trust_access_policy.admin_dashboard.id
    precedence = 1
  }]
}
