data "aws_wafv2_rule_group" "gsirt_ip_block_rule_group" {
  count = var.gsirt_ip_block_rule_group_enabled ? 1 : 0
  name  = var.custom_gsirt_ip_block_rule_group_name != "" ? var.custom_gsirt_ip_block_rule_group_name : "${var.environment}-gsirt-ioc-rule-group"
  scope = var.acl_scope
}

resource "aws_wafv2_web_acl" "countonlyacl" {
  # checkov:skip=CKV_AWS_192:WAF rule set `AWSManagedRulesKnownBadInputsRuleSet`, which prevents message lookup in Log4j2, is enabled by default in the module. This check fails because of the `dynamic` statement.
  # checkov:skip=CKV2_AWS_31:Metrics and samples collection is enabled by default. This check fails because of the `dynamic` statement.

  name        = "${var.environment}-${var.service_name}-waf-count-only"
  description = "A web_acl in ${var.environment} which allows but keeps count of bad requests for ${var.service_name}"
  scope       = var.acl_scope
  count       = var.count_waf_enabled ? 1 : 0

  default_action {
    allow {}
  }

  # GSIRT IP block rule should be added to all web ACLs, including count-only
  dynamic "rule" {
    for_each = var.gsirt_ip_block_rule_group_enabled ? [""] : []

    content {
      name     = "gsirt-ip-block-rule"
      priority = var.gsirt_ip_block_rule_group_priority

      override_action {
        none {}
      }

      statement {
        rule_group_reference_statement {
          arn = data.aws_wafv2_rule_group.gsirt_ip_block_rule_group[0].arn
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = var.count_only_rule_cloudwatch_metrics_enabled
        metric_name                = "${local.count_only_rule_metric_name}-gsirt-ip-block-rule"
        sampled_requests_enabled   = var.count_only_rule_sampled_requests_enabled
      }
    }
  }

  dynamic "rule" {
    for_each = [for r in var.count_only_rules : {
      name                                     = r.name
      managed_rule_group_statement_name        = r.managed_rule_group_statement_name
      managed_rule_group_statement_vendor_name = r.managed_rule_group_statement_vendor_name
      priority                                 = r.priority
      metric_name                              = lookup(r, "metric_name", null)
    }]

    content {
      name     = rule.value.name
      priority = rule.value.priority

      override_action {
        count {}
      }

      statement {
        managed_rule_group_statement {
          name        = rule.value.managed_rule_group_statement_name
          vendor_name = rule.value.managed_rule_group_statement_vendor_name
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = var.count_only_rule_cloudwatch_metrics_enabled
        metric_name                = rule.value.metric_name != null ? rule.value.metric_name : local.count_only_rule_metric_name
        sampled_requests_enabled   = var.count_only_rule_sampled_requests_enabled
      }
    }
  }

  dynamic "rule" {
    for_each = [for r in var.custom_rules : {
      name           = r.name
      priority       = r.priority
      rule_group_arn = r.rule_group_arn
      metric_name    = lookup(r, "metric_name", null)
    }]

    content {
      name     = rule.value.name
      priority = rule.value.priority

      override_action {
        count {}
      }

      statement {
        rule_group_reference_statement {
          arn = rule.value.rule_group_arn
        }
      }

      visibility_config {
        cloudwatch_metrics_enabled = var.count_only_rule_cloudwatch_metrics_enabled
        metric_name                = rule.value.metric_name != null ? rule.value.metric_name : local.count_only_rule_metric_name
        sampled_requests_enabled   = var.count_only_rule_sampled_requests_enabled
      }
    }
  }

  tags = local.tags

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = local.count_only_rule_metric_name
    sampled_requests_enabled   = true
  }
}


resource "aws_wafv2_web_acl" "blockwebacl" {
  # checkov:skip=CKV_AWS_192:WAF rule set `AWSManagedRulesKnownBadInputsRuleSet`, which prevents message lookup in Log4j2, is enabled by default in the module. This check fails because of the `dynamic` statement.
  # checkov:skip=CKV2_AWS_31:Metrics and samples collection is enabled by default. This check fails because of the `dynamic` statement.

  name        = "${var.environment}-${var.service_name}-waf-block"
  description = "A web_acl in ${var.environment} which blocks bad requests for ${var.service_name}"
  scope       = var.acl_scope
  count       = var.block_waf_enabled ? 1 : 0

  default_action {
    allow {}
  }

  dynamic "rule" {
    for_each = var.gsirt_ip_block_rule_group_enabled ? [""] : []

    content {
      name     = "gsirt-ip-block-rule"
      priority = var.gsirt_ip_block_rule_group_priority

      override_action {
        none {}
      }

      statement {
        rule_group_reference_statement {
          arn = data.aws_wafv2_rule_group.gsirt_ip_block_rule_group[0].arn
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = var.block_rule_cloudwatch_metrics_enabled
        metric_name                = "${local.count_only_rule_metric_name}-gsirt-ip-block-rule"
        sampled_requests_enabled   = var.block_rule_sampled_requests_enabled
      }
    }
  }

  # Geo IP block rule (block)
  dynamic "rule" {
    for_each = length(var.geoip_blocked_countries) > 0 ? [1] : []
    content {
      name     = "geoip-block"
      priority = var.geoip_block_rule_group_priority

      action {
        block {}
      }

      statement {
        geo_match_statement {
          country_codes = var.geoip_blocked_countries
        }
      }

      visibility_config {
        cloudwatch_metrics_enabled = var.block_rule_cloudwatch_metrics_enabled
        metric_name                = "${local.block_rule_metric_name}-geoip-block-rule"
        sampled_requests_enabled   = var.block_rule_sampled_requests_enabled
      }
    }
  }

  dynamic "rule" {
    for_each = [for r in var.block_rules : {
      name                                     = r.name
      managed_rule_group_statement_name        = r.managed_rule_group_statement_name
      managed_rule_group_statement_vendor_name = r.managed_rule_group_statement_vendor_name
      priority                                 = r.priority
      metric_name                              = lookup(r, "metric_name", null)
    }]

    content {
      name     = rule.value.name
      priority = rule.value.priority

      override_action {
        none {}
      }

      statement {
        managed_rule_group_statement {
          name        = rule.value.managed_rule_group_statement_name
          vendor_name = rule.value.managed_rule_group_statement_vendor_name

          dynamic "rule_action_override" {
            for_each = var.excluded_rules
            content {
              name = rule_action_override.value
              action_to_use {
                count {}
              }
            }
          }
        }
      }
      visibility_config {
        cloudwatch_metrics_enabled = var.block_rule_cloudwatch_metrics_enabled
        metric_name                = rule.value.metric_name != null ? rule.value.metric_name : local.block_rule_metric_name
        sampled_requests_enabled   = var.block_rule_sampled_requests_enabled
      }
    }
  }

  dynamic "rule" {
    for_each = [for r in var.custom_rules : {
      name           = r.name
      priority       = r.priority
      rule_group_arn = r.rule_group_arn
      metric_name    = lookup(r, "metric_name", null)
    }]

    content {
      name     = rule.value.name
      priority = rule.value.priority

      override_action {
        none {}
      }

      statement {
        rule_group_reference_statement {
          arn = rule.value.rule_group_arn
        }
      }

      visibility_config {
        cloudwatch_metrics_enabled = var.block_rule_cloudwatch_metrics_enabled
        metric_name                = rule.value.metric_name != null ? rule.value.metric_name : local.block_rule_metric_name
        sampled_requests_enabled   = var.block_rule_sampled_requests_enabled
      }
    }
  }

  tags = local.tags

  visibility_config {
    cloudwatch_metrics_enabled = true
    metric_name                = local.block_rule_metric_name
    sampled_requests_enabled   = true
  }
}

locals {
  resource_arns_for_logging = var.logging_config_enabled ? concat(aws_wafv2_web_acl.countonlyacl.*.arn, aws_wafv2_web_acl.blockwebacl.*.arn) : []
}

resource "aws_wafv2_web_acl_logging_configuration" "waf" {
  count                   = length(local.resource_arns_for_logging)
  log_destination_configs = concat([var.logging_config_default_destination], var.logging_config_additional_destinations)
  resource_arn            = local.resource_arns_for_logging[count.index]

  dynamic "redacted_fields" {
    for_each = var.logging_config_redacted_headers
    content {
      single_header {
        name = redacted_fields.value
      }
    }
  }
}
