From 116af75889071cb865d42df86131fa56f3e35927 Mon Sep 17 00:00:00 2001 From: Bryan Robitaille Date: Thu, 21 Nov 2024 13:48:08 -0500 Subject: [PATCH] chore: Seperate WAF uri checks contexts between API and App (#896) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Clément JANIN --- aws/load_balancer/waf.tf | 131 +++++++++++++++++++++++++++++++++------ docker-compose.yml | 1 - 2 files changed, 112 insertions(+), 20 deletions(-) diff --git a/aws/load_balancer/waf.tf b/aws/load_balancer/waf.tf index fefad0fa5..2cda6e1da 100644 --- a/aws/load_balancer/waf.tf +++ b/aws/load_balancer/waf.tf @@ -299,24 +299,52 @@ resource "aws_wafv2_web_acl" "forms_acl" { statement { not_statement { statement { - regex_pattern_set_reference_statement { - arn = aws_wafv2_regex_pattern_set.valid_app_uri_paths.arn - field_to_match { - uri_path {} - } - text_transformation { - priority = 1 - type = "COMPRESS_WHITE_SPACE" + and_statement { + statement { + or_statement { + dynamic "statement" { + for_each = var.domains + content { + byte_match_statement { + positional_constraint = "EXACTLY" + field_to_match { + single_header { + name = "host" + } + } + search_string = statement.value + text_transformation { + priority = 1 + type = "LOWERCASE" + } + } + } + } + } + } - text_transformation { - priority = 2 - type = "LOWERCASE" + statement { + regex_pattern_set_reference_statement { + arn = aws_wafv2_regex_pattern_set.valid_app_uri_paths.arn + field_to_match { + uri_path {} + } + text_transformation { + priority = 1 + type = "COMPRESS_WHITE_SPACE" + } + text_transformation { + priority = 2 + type = "LOWERCASE" + } + } } } } } } + visibility_config { cloudwatch_metrics_enabled = true metric_name = "AllowOnlyAppUrls" @@ -324,6 +352,62 @@ resource "aws_wafv2_web_acl" "forms_acl" { } } + rule { + name = "AllowOnlyApiUrls" + priority = 65 + + action { + block {} + } + + statement { + not_statement { + statement { + and_statement { + statement { + byte_match_statement { + positional_constraint = "EXACTLY" + field_to_match { + single_header { + name = "host" + } + } + search_string = var.domain_api + text_transformation { + priority = 1 + type = "LOWERCASE" + } + } + } + statement { + regex_pattern_set_reference_statement { + arn = aws_wafv2_regex_pattern_set.valid_api_uri_paths.arn + field_to_match { + uri_path {} + } + text_transformation { + priority = 1 + type = "COMPRESS_WHITE_SPACE" + } + text_transformation { + priority = 2 + type = "LOWERCASE" + } + } + } + } + } + } + } + + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "AllowOnlyApiUrls" + sampled_requests_enabled = false + } + } + rule { name = local.cognito_login_outside_canada_rule_name priority = 70 @@ -433,35 +517,44 @@ resource "aws_wafv2_web_acl_logging_configuration" "firehose_waf_logs_forms" { resource "aws_wafv2_regex_pattern_set" "valid_app_uri_paths" { name = "valid_app_uri_paths" scope = "REGIONAL" - description = "Regex to match the app and api valid urls" + description = "Regex to match the app valid urls" + # App paths regular_expression { - regex_string = "^\\/(?:en|fr)?\\/?(?:(admin|id|api|auth|signup|profile|forms|unsupported-browser|terms-of-use|contact|support|404)(?:\\/[\\w-]+)?)(?:\\/.*)?$" + regex_string = "^\\/(?:en|fr)?\\/?(?:(admin|form-builder|forms|id|auth|profile|support|contact|unlock-publishing)(?:\\/[\\w-]+)?)(?:\\/.*)?$" } + # Static Pages regular_expression { - regex_string = "^\\/(?:en|fr)?\\/?(?:(form-builder|sla|unlock-publishing|terms-and-conditions|javascript-disabled)(?:\\/[\\w-]+)?)(?:\\/.*)?$" + regex_string = "^\\/(?:en|fr)?\\/?(?:(sla|terms-and-conditions|terms-of-use|unsupported-browser|javascript-disabled|404)(?:\\/[\\w-]+)?)(?:\\/.*)?$" } + # Files regular_expression { regex_string = "^\\/(?:en|fr)?\\/?(?:(static|_next|img|favicon\\.ico)(?:\\/[\\w-]+)*)(?:\\/.*)?$" } - # API paths - regular_expression { - regex_string = "^\\/(?:v1)?\\/?(?:(docs|status))(?:\\/)?$" - } - # This is a temporary rule to allow search engines tools to access ownership verification files regular_expression { regex_string = "^\\/?(BingSiteAuth\\.xml|googlef34bd8c094c26cb0\\.html)$" } + # Language selector page regular_expression { regex_string = "^\\/(?:en|fr)?\\/?$" } } +resource "aws_wafv2_regex_pattern_set" "valid_api_uri_paths" { + name = "valid_api_uri" + scope = "REGIONAL" + description = "Regex to match the api valid urls" + + regular_expression { + regex_string = "^(?:\\/v1)?\\/forms\\/(?:(\\w{25}))\\/(?:(template|(?:(submission\\/(?:(new|(?:(\\d{2}-\\d{2}-\\w{4})\\/?(?:(confirm\\/\\w{8}-\\w{4}-\\w{4}-\\w{4}-\\w{12}|problem)?))))))))(?:\\/)?$" + } +} + resource "aws_wafv2_regex_pattern_set" "forms_base_url" { name = "forms_base_url" description = "Regex matching the root domain of GCForms" diff --git a/docker-compose.yml b/docker-compose.yml index b1675bc78..624cbff43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: "3.8" volumes: localstack: services: