locals {
  rs_waf_custom_rules = jsondecode(file("${path.module}/../../../../etc/deploy-job-scripts/o11y-azure-region-control/basic/waf/custom-rs.json"))
  ds_waf_custom_rules = jsondecode(file("${path.module}/../../../../etc/deploy-job-scripts/o11y-azure-region-control/basic/waf/custom-ds.json"))

  # AzureRM requires every WAF policy to keep one managed rule set. O11Y global
  # server traffic to the BYOC regional server is not compatible with the OWASP
  # managed rules, so keep the policy in Prevention mode for custom block rules
  # and disable every Azure-published OWASP 3.2 rule ID one by one.
  # Microsoft documents some PL3/PL4 rules as inactive, but Azure still exposes
  # them as Enabled in the available-rule-set API and portal. Keep them in this
  # override list so the managed rule state is unambiguous.
  o11y_waf_disabled_owasp32_rule_groups = {
    "General" = [
      "200002",
      "200003",
      "200004",
    ]
    "Known-CVEs" = [
      "800100",
      "800110",
      "800111",
      "800112",
      "800113",
      "800114",
      "800115",
    ]
    "REQUEST-911-METHOD-ENFORCEMENT" = [
      "911100",
    ]
    "REQUEST-913-SCANNER-DETECTION" = [
      "913100",
      "913101",
      "913102",
      "913110",
      "913120",
    ]
    "REQUEST-920-PROTOCOL-ENFORCEMENT" = [
      "920100",
      "920120",
      "920121",
      "920160",
      "920170",
      "920171",
      "920180",
      "920190",
      "920200",
      "920201",
      "920202",
      "920210",
      "920220",
      "920230",
      "920240",
      "920250",
      "920260",
      "920270",
      "920271",
      "920272",
      "920273",
      "920274",
      "920280",
      "920290",
      "920300",
      "920310",
      "920311",
      "920320",
      "920330",
      "920340",
      "920341",
      "920350",
      "920420",
      "920430",
      "920440",
      "920450",
      "920460",
      "920470",
      "920480",
    ]
    "REQUEST-921-PROTOCOL-ATTACK" = [
      "921110",
      "921120",
      "921130",
      "921140",
      "921150",
      "921151",
      "921160",
      "921170",
      "921180",
    ]
    "REQUEST-930-APPLICATION-ATTACK-LFI" = [
      "930100",
      "930110",
      "930120",
      "930130",
    ]
    "REQUEST-931-APPLICATION-ATTACK-RFI" = [
      "931100",
      "931110",
      "931120",
      "931130",
    ]
    "REQUEST-932-APPLICATION-ATTACK-RCE" = [
      "932100",
      "932105",
      "932106",
      "932110",
      "932115",
      "932120",
      "932130",
      "932140",
      "932150",
      "932160",
      "932170",
      "932171",
      "932180",
      "932190",
    ]
    "REQUEST-933-APPLICATION-ATTACK-PHP" = [
      "933100",
      "933110",
      "933111",
      "933120",
      "933130",
      "933131",
      "933140",
      "933150",
      "933151",
      "933160",
      "933161",
      "933170",
      "933180",
      "933190",
      "933200",
      "933210",
    ]
    "REQUEST-941-APPLICATION-ATTACK-XSS" = [
      "941100",
      "941101",
      "941110",
      "941120",
      "941130",
      "941140",
      "941150",
      "941160",
      "941170",
      "941180",
      "941190",
      "941200",
      "941210",
      "941220",
      "941230",
      "941240",
      "941250",
      "941260",
      "941270",
      "941280",
      "941290",
      "941300",
      "941310",
      "941320",
      "941330",
      "941340",
      "941350",
      "941360",
    ]
    "REQUEST-942-APPLICATION-ATTACK-SQLI" = [
      "942100",
      "942110",
      "942120",
      "942130",
      "942140",
      "942150",
      "942160",
      "942170",
      "942180",
      "942190",
      "942200",
      "942210",
      "942220",
      "942230",
      "942240",
      "942250",
      "942251",
      "942260",
      "942270",
      "942280",
      "942290",
      "942300",
      "942310",
      "942320",
      "942330",
      "942340",
      "942350",
      "942360",
      "942361",
      "942370",
      "942380",
      "942390",
      "942400",
      "942410",
      "942420",
      "942421",
      "942430",
      "942431",
      "942432",
      "942440",
      "942450",
      "942460",
      "942470",
      "942480",
      "942490",
      "942500",
    ]
    "REQUEST-943-APPLICATION-ATTACK-SESSION-FIXATION" = [
      "943100",
      "943110",
      "943120",
    ]
    "REQUEST-944-APPLICATION-ATTACK-JAVA" = [
      "944100",
      "944110",
      "944120",
      "944130",
      "944200",
      "944210",
      "944240",
      "944250",
    ]
  }
}

resource "azurerm_web_application_firewall_policy" "rs" {
  name                = "${local.o11y_name}-rs-api"
  resource_group_name = local.resource_group
  location            = data.azurerm_resource_group.o11y_aks.location
  tags                = local.tags

  policy_settings {
    enabled                     = true
    mode                        = "Prevention"
    max_request_body_size_in_kb = 512
    request_body_check          = false
    request_body_enforcement    = true
  }

  managed_rules {
    managed_rule_set {
      type    = "OWASP"
      version = "3.2"

      dynamic "rule_group_override" {
        for_each = local.o11y_waf_disabled_owasp32_rule_groups

        content {
          rule_group_name = rule_group_override.key

          dynamic "rule" {
            for_each = toset(rule_group_override.value)

            content {
              id      = rule.value
              enabled = false
            }
          }
        }
      }
    }
  }

  dynamic "custom_rules" {
    for_each = local.rs_waf_custom_rules

    content {
      name      = custom_rules.value.name
      priority  = custom_rules.value.priority
      rule_type = custom_rules.value.ruleType
      action    = custom_rules.value.action

      dynamic "match_conditions" {
        for_each = custom_rules.value.matchConditions

        content {
          operator           = match_conditions.value.operator
          negation_condition = match_conditions.value.negate
          match_values       = match_conditions.value.values
          transforms         = try(match_conditions.value.transforms, [])

          dynamic "match_variables" {
            for_each = match_conditions.value.variables

            content {
              variable_name = match_variables.value.variableName
              selector      = try(match_variables.value.selector, null)
            }
          }
        }
      }
    }
  }
}

resource "azurerm_web_application_firewall_policy" "ds" {
  name                = "${local.o11y_name}-ds-api"
  resource_group_name = local.resource_group
  location            = data.azurerm_resource_group.o11y_aks.location
  tags                = local.tags

  policy_settings {
    enabled = true
    mode    = "Prevention"
  }

  managed_rules {
    managed_rule_set {
      type    = "OWASP"
      version = "3.2"

      dynamic "rule_group_override" {
        for_each = local.o11y_waf_disabled_owasp32_rule_groups

        content {
          rule_group_name = rule_group_override.key

          dynamic "rule" {
            for_each = toset(rule_group_override.value)

            content {
              id      = rule.value
              enabled = false
            }
          }
        }
      }
    }
  }

  dynamic "custom_rules" {
    for_each = local.ds_waf_custom_rules

    content {
      name      = custom_rules.value.name
      priority  = custom_rules.value.priority
      rule_type = custom_rules.value.ruleType
      action    = custom_rules.value.action

      dynamic "match_conditions" {
        for_each = custom_rules.value.matchConditions

        content {
          operator           = match_conditions.value.operator
          negation_condition = match_conditions.value.negate
          match_values       = match_conditions.value.values
          transforms         = try(match_conditions.value.transforms, [])

          dynamic "match_variables" {
            for_each = match_conditions.value.variables

            content {
              variable_name = match_variables.value.variableName
              selector      = try(match_variables.value.selector, null)
            }
          }
        }
      }
    }
  }
}

resource "azurerm_public_ip" "app_gateway" {
  name                = "appgw-pip-${local.o11y_name}"
  location            = data.azurerm_resource_group.o11y_aks.location
  resource_group_name = local.resource_group
  allocation_method   = "Static"
  sku                 = "Standard"
  tags                = local.tags
}

resource "azurerm_application_gateway" "o11y" {
  depends_on = [
    azurerm_web_application_firewall_policy.ds,
  ]

  name                = "appgw-${local.o11y_name}"
  location            = data.azurerm_resource_group.o11y_aks.location
  resource_group_name = local.resource_group
  firewall_policy_id  = azurerm_web_application_firewall_policy.rs.id
  tags                = local.tags

  sku {
    name     = "WAF_v2"
    tier     = "WAF_v2"
    capacity = 2
  }

  gateway_ip_configuration {
    name      = "appGatewayIpConfig"
    subnet_id = azurerm_subnet.app_gateway.id
  }

  frontend_ip_configuration {
    name                 = "public"
    public_ip_address_id = azurerm_public_ip.app_gateway.id
  }

  frontend_port {
    name = "http"
    port = 80
  }

  backend_address_pool {
    name = "default"
  }

  backend_http_settings {
    name                  = "default"
    cookie_based_affinity = "Disabled"
    path                  = "/"
    port                  = 80
    protocol              = "Http"
    request_timeout       = 30
  }

  http_listener {
    name                           = "http"
    frontend_ip_configuration_name = "public"
    frontend_port_name             = "http"
    protocol                       = "Http"
  }

  request_routing_rule {
    name                       = "default"
    rule_type                  = "Basic"
    http_listener_name         = "http"
    backend_address_pool_name  = "default"
    backend_http_settings_name = "default"
    priority                   = 100
  }

  lifecycle {
    ignore_changes = [
      backend_address_pool,
      backend_http_settings,
      frontend_port,
      http_listener,
      probe,
      request_routing_rule,
      redirect_configuration,
      rewrite_rule_set,
      ssl_certificate,
      trusted_root_certificate,
      url_path_map,
    ]
  }
}

resource "azurerm_dns_a_record" "rs" {
  name                = local.rs_record_name
  zone_name           = local.hosted_zone_name
  resource_group_name = var.dns_zone_resource_group_name
  ttl                 = 300
  records             = [azurerm_public_ip.app_gateway.ip_address]
  tags                = local.tags

  depends_on = [null_resource.wait_nginx_write_pls]
}

resource "azurerm_dns_a_record" "ds" {
  name                = local.ds_record_name
  zone_name           = local.hosted_zone_name
  resource_group_name = var.dns_zone_resource_group_name
  ttl                 = 300
  records             = [azurerm_public_ip.app_gateway.ip_address]
  tags                = local.tags

  depends_on = [null_resource.wait_nginx_write_pls]
}
