resource "aws_wafv2_web_acl_association" "gateway" {
  resource_arn = aws_alb.alb.arn
  web_acl_arn  = data.terraform_remote_state.mop_core.outputs.waf_web_acl_arn
}

resource "aws_wafregional_ipset" "ipset" {
  name = "north_korea"

  ip_set_descriptor {
    type  = "IPV4"
    value = "175.45.176.0/22"
  }
}

resource "aws_wafregional_geo_match_set" "geo_match_set" {
  name = "geo_match_set"

  geo_match_constraint {
    type  = "Country"
    value = "IR"
  }

  geo_match_constraint {
    type  = "Country"
    value = "SY"
  }

  geo_match_constraint {
    type  = "Country"
    value = "CU"
  }
  geo_match_constraint {
    type  = "Country"
    value = "KP"
  }

  geo_match_constraint {
    type  = "Country"
    value = "SD"
  }
}


resource "aws_wafregional_ipset" "manual_block_ipset" {
  name = "${local.deploy_env_name}_manual_block_IPSet"
}

#The sql_injection_match_tuples are where how and what will will be searched for sql injection attempts
# i.e. /v1/rest/?search="; SELECT * FROM USERS" would get picked up because it will be url_decoded from a query string. 
resource "aws_wafregional_sql_injection_match_set" "sql_injection_match_set" {
  name = "${local.deploy_env_name}_sql_injection_match_set"

  sql_injection_match_tuple {
    text_transformation = "URL_DECODE"

    field_to_match {
      type = "QUERY_STRING"
    }
  }

  sql_injection_match_tuple {
    text_transformation = "HTML_ENTITY_DECODE"
    field_to_match {
      type = "QUERY_STRING"
    }
  }

  sql_injection_match_tuple {
    text_transformation = "URL_DECODE"
    field_to_match {
      type = "BODY"
    }
  }

  sql_injection_match_tuple {
    text_transformation = "HTML_ENTITY_DECODE"
    field_to_match {
      type = "BODY"
    }
  }

  sql_injection_match_tuple {
    text_transformation = "URL_DECODE"
    field_to_match {
      type = "URI"
    }
  }
}

#xss_match_tuples are similar to the sql_injection_match_tuples above. The same logic applies. 
resource "aws_wafregional_xss_match_set" "xss_match_set" {
  name = "${local.deploy_env_name}_xss_match_set"

  xss_match_tuple {
    text_transformation = "URL_DECODE"
    field_to_match {
      type = "QUERY_STRING"
    }
  }

  xss_match_tuple {
    text_transformation = "HTML_ENTITY_DECODE"
    field_to_match {
      type = "QUERY_STRING"
    }
  }

  xss_match_tuple {
    text_transformation = "URL_DECODE"
    field_to_match {
      type = "BODY"
    }
  }

  xss_match_tuple {
    text_transformation = "HTML_ENTITY_DECODE"
    field_to_match {
      type = "BODY"
    }
  }

  xss_match_tuple {
    text_transformation = "URL_DECODE"
    field_to_match {
      type = "URI"
    }
  }

  xss_match_tuple {
    text_transformation = "NONE"
    field_to_match {
      type = "QUERY_STRING"
    }
  }
}

#If the payload size is greater than 8192 bytes then we'll block it.
resource "aws_wafregional_size_constraint_set" "size_constraint_set" {
  name = "${local.deploy_env_name}_size_match_set"

  size_constraints {
    text_transformation = "NONE"
    comparison_operator = "GT"
    size                = "8192"

    field_to_match {
      type = "BODY"
    }
  }
}

#request rate = rate_limit/5 minutes, 3000 requests/300s ~= 10 requests per second. If we hit that then we'll block them.
resource "aws_wafregional_rate_based_rule" "ipratelimit" {
  name        = "${local.deploy_env_name}-global-ip-rate-limit"
  metric_name = "wafAppGlobalIpRateLimit"
  rate_key    = "IP"
  rate_limit  = 3000
}

resource "aws_wafregional_rule" "manual_block_ipset_rule" {
  name        = "${local.deploy_env_name}_manual_block_IPSet_rule"
  metric_name = "ManualBlockWAFRule"

  predicate {
    type    = "IPMatch"
    data_id = aws_wafregional_ipset.manual_block_ipset.id
    negated = false
  }
}

#These rules associate the match_sets  above
resource "aws_wafregional_rule" "size_match_rule" {
  name        = "${local.deploy_env_name}_size_match_rule"
  metric_name = "SizeMatchWAFRule"

  predicate {
    type    = "SizeConstraint"
    data_id = aws_wafregional_size_constraint_set.size_constraint_set.id
    negated = false
  }
}

resource "aws_wafregional_rule" "xss_match_rule" {
  name        = "${local.deploy_env_name}_xss_match_rule"
  metric_name = "XssMatchWAFRule"

  predicate {
    type    = "XssMatch"
    data_id = aws_wafregional_xss_match_set.xss_match_set.id
    negated = false
  }
}

resource "aws_wafregional_rule" "sql_injection_match_rule" {
  name        = "${local.deploy_env_name}_sql_injection_match_rule"
  metric_name = "SqlInjectionMatchWAFRule"

  predicate {
    type    = "SqlInjectionMatch"
    data_id = aws_wafregional_sql_injection_match_set.sql_injection_match_set.id
    negated = false
  }
}

resource "aws_wafregional_rule" "geo_wafrule" {
  depends_on  = [aws_wafregional_geo_match_set.geo_match_set]
  name        = "GeoWafOfac"
  metric_name = "GeoWafOfac"

  predicate {
    data_id = aws_wafregional_geo_match_set.geo_match_set.id
    negated = false
    type    = "GeoMatch"
  }
}

resource "aws_wafregional_rule" "ip_wafrule" {
  depends_on  = [aws_wafregional_ipset.ipset]
  name        = "IpWafOfac"
  metric_name = "IpWafOfac"

  predicate {
    data_id = aws_wafregional_ipset.ipset.id
    negated = false
    type    = "IPMatch"
  }
}

resource "aws_wafregional_web_acl" "aws_web_acl" {
  depends_on  = [aws_wafregional_ipset.ipset, aws_wafregional_rule.ip_wafrule, aws_wafregional_geo_match_set.geo_match_set, aws_wafregional_rule.geo_wafrule]
  name        = "GlobalWebACL"
  metric_name = "GlobalWebACL"

  default_action {
    type = "ALLOW"
  }

  #The rules below associate the waf rules.
  rule {
    action {
      type = "BLOCK"
    }

    priority = 1
    rule_id  = aws_wafregional_rule.ip_wafrule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "BLOCK"
    }

    priority = 2
    rule_id  = aws_wafregional_rule.geo_wafrule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "BLOCK"
    }

    priority = 3
    rule_id  = aws_wafregional_rule.manual_block_ipset_rule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "BLOCK"
    }

    priority = 4
    rule_id  = aws_wafregional_rule.sql_injection_match_rule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "BLOCK"
    }

    priority = 5
    rule_id  = aws_wafregional_rule.xss_match_rule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "COUNT"
    }

    priority = 6
    rule_id  = aws_wafregional_rule.size_match_rule.id
    type     = "REGULAR"
  }

  rule {
    action {
      type = "BLOCK"
    }

    priority = 7
    rule_id  = aws_wafregional_rule.regex_blocks.id
    type     = "REGULAR"
  }
}

/*
resource "aws_wafregional_web_acl_association" "aws_wafregional_web_acl_association" {
  resource_arn = aws_alb.alb.arn
  web_acl_id   = aws_wafregional_web_acl.aws_web_acl.id
}
*/

resource "aws_wafregional_rule" "regex_blocks" {
  name        = "RegexBlocks"
  metric_name = "RegexBlocks"

  predicate {
    data_id = aws_wafregional_regex_match_set.regex_blocks.id
    negated = false
    type    = "RegexMatch"
  }

}

resource "aws_wafregional_regex_match_set" "regex_blocks" {
  name = "RegexBlocks"

  regex_match_tuple {
    field_to_match {
      type = "URI"
    }

    regex_pattern_set_id = aws_wafregional_regex_pattern_set.regex_blocks.id
    text_transformation  = "NONE"
  }
}

resource "aws_wafregional_regex_pattern_set" "regex_blocks" {
  name                  = "BlockUrisContainingPhp"
  regex_pattern_strings = ["dotAdmin", "php", ".php", "phpstorm", ".*\\.aspx", "wp-content", ".*\\.env", ".*\\.exe", "heapdump"]
}


#############################
# Failover ACL Association
##############################
/*
resource "aws_wafregional_web_acl_association" "aws_wafregional_web_acl_association_failover" {

  // provider = aws.failover_region

  resource_arn = aws_alb.alb_failover.arn
  web_acl_id   = aws_wafregional_web_acl.aws_web_acl.id
}
*/

