From f19f89cb7effefd793a4634c82a01ff5f65e970d Mon Sep 17 00:00:00 2001 From: maxim Date: Wed, 7 Jul 2021 10:52:42 +0600 Subject: [PATCH 1/5] Add terraform module to create AWS WAFv2 rule-group that cover OWASP TOP 10 security issues --- .../aws-wafv2-top-10-owasp-rules/README.md | 61 + .../aws-wafv2-top-10-owasp-rules/main.tf | 1005 +++++++++++++++++ .../aws-wafv2-top-10-owasp-rules/outputs.tf | 3 + .../aws-wafv2-top-10-owasp-rules/variables.tf | 56 + 4 files changed, 1125 insertions(+) create mode 100644 terraform/modules/aws-wafv2-top-10-owasp-rules/README.md create mode 100644 terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf create mode 100644 terraform/modules/aws-wafv2-top-10-owasp-rules/outputs.tf create mode 100644 terraform/modules/aws-wafv2-top-10-owasp-rules/variables.tf diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md new file mode 100644 index 00000000..82bf9fee --- /dev/null +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md @@ -0,0 +1,61 @@ +There are 2 implementations of AWS WAF: AWS WAF Classic and AWS WAFv2. AWS recommends using AWS WAFv2 for new installations. +This terraform module creates AWS WAFv2 rule-group with rules that cover *OWASP TOP 10 security issues* (https://d0.awsstatic.com/whitepapers/Security/aws-waf-owasp.pdf). + +Example of using this module: +```bash +module "wafv2_owasp_top_10_rules" { + source = "../modules/aws-wafv2-top-10-owasp-rules" + + name = "${var.name}-${local.env}" + + waf_scope = "CLOUDFRONT" + + max_expected_uri_size = "512" + max_expected_query_string_size = "1024" + max_expected_body_size = "4096" + max_expected_cookie_size = "4093" + + csrf_expected_header = "x-csrf-token" + csrf_expected_size = "36" + + cloudwatch_metrics_enabled = true + blacklisted_cidrs = ["10.0.0.0/8", "192.168.0.0/16", "169.254.0.0/16", "172.16.0.0/16", "127.0.0.1/32"] +} + +resource "aws_wafv2_web_acl" "this" { + name = "${var.name}-${local.env}-webacl" + scope = "CLOUDFRONT" + + default_action { + allow {} + } + + rule { + name = "owasp_top10_rules" + priority = 1 + + override_action { + none {} + } + + statement { + rule_group_reference_statement { + arn = module.wafv2_owasp_top_10_rules.rule_group_arn + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "owasp-top10-security-issues" + sampled_requests_enabled = true + } + } + + visibility_config { + cloudwatch_metrics_enabled = true + metric_name = "${var.name}-${local.env}-webacl" + sampled_requests_enabled = false + } +} + +``` diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf new file mode 100644 index 00000000..1fface6f --- /dev/null +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf @@ -0,0 +1,1005 @@ +resource "aws_wafv2_ip_set" "owasp_10_detect_blacklisted_ips" { + name = "${var.name}-owasp-10-detect-blacklisted-ips" + scope = var.waf_scope + ip_address_version = "IPV4" + addresses = var.blacklisted_cidrs +} + +resource "aws_wafv2_rule_group" "owasp_top10_rules" { + name = "${var.name}-owasp-top10-security-issues" + scope = var.waf_scope + capacity = 580 + + rule { + ## OWASP Top 10 A1 + ### Mitigate SQL Injection Attacks + ### Matches attempted SQLi patterns in the URI, QUERY_STRING, BODY, COOKIES + name = "owasp-01-detect-sql-injection" + priority = 1 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + sqli_match_statement { + field_to_match { + uri_path {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + sqli_match_statement { + field_to_match { + query_string {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + sqli_match_statement { + field_to_match { + body {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + sqli_match_statement { + field_to_match { + single_header { + name = "authorization" + } + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + sqli_match_statement { + field_to_match { + single_header { + name = "cookie" + } + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-01-detect-sql-injection" + sampled_requests_enabled = false + } + + } + + rule { + ## OWASP Top 10 A2 + ### Blacklist bad/hijacked JWT tokens or session IDs + ### Matches the specific values in the cookie or Authorization header for JWT it is sufficient to check the signature + name = "owasp-02-match-auth-token" + priority = 2 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + byte_match_statement { + field_to_match { + single_header { + name = "cookie" + } + } + + search_string = "example-session-id" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + } + } + + statement { + byte_match_statement { + field_to_match { + single_header { + name = "authorization" + } + } + + search_string = ".TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + } + } + + } + } + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-02-match-auth-token" + sampled_requests_enabled = false + } + } + + rule { + ## OWASP Top 10 A3 + ### Mitigate Cross Site Scripting Attacks + ### Matches attempted XSS patterns in the URI, QUERY_STRING, BODY, COOKIES + name = "owasp-03-detect-xss" + priority = 3 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + xss_match_statement { + field_to_match { + uri_path {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + xss_match_statement { + field_to_match { + query_string {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + xss_match_statement { + field_to_match { + body {} + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + statement { + xss_match_statement { + field_to_match { + single_header { + name = "cookie" + } + } + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + } + } + + } + } + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-03-detect-xss" + sampled_requests_enabled = false + } + } + + rule { + ## OWASP Top 10 A4 + ### Path Traversal, LFI, RFI + ### Matches request patterns designed to traverse filesystem paths, and include local or remote files + name = "owasp-04-match-rfi-lfi-traversal" + priority = 4 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = "../" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "../" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = "://" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "://" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "HTML_ENTITY_DECODE" + } + + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-04-match-rfi-lfi-traversal" + sampled_requests_enabled = false + } + } + + rule { + # OWASP Top 10 A5 + # PHP Specific Security Misconfigurations + # Matches request patterns designed to exploit insecure PHP/CGI configuration + name = "owasp-05-match-php-insecure-uri" + priority = 5 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "_SERVER[" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "_ENV[" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "_ENV[" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "auto_prepend_file=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "auto_append_file=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "allow_url_include=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "disable_functions=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "open_basedir=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + query_string {} + } + + search_string = "safe_mode=" + positional_constraint = "CONTAINS" + + text_transformation { + priority = 1 + type = "URL_DECODE" + } + + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-05-match-php-insecure-uri" + sampled_requests_enabled = false + } + } + + rule { + ## OWASP Top 10 A7 + ### Mitigate abnormal requests via size restrictions + ### Enforce consistent request hygene, limit size of key elements + name = "owasp-07-size-restrictions" + priority = 6 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + size_constraint_statement { + field_to_match { + uri_path {} + } + + comparison_operator = "GT" + size = var.max_expected_uri_size + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + statement { + size_constraint_statement { + field_to_match { + query_string {} + } + + comparison_operator = "GT" + size = var.max_expected_query_string_size + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + statement { + size_constraint_statement { + field_to_match { + body {} + } + + comparison_operator = "GT" + size = var.max_expected_body_size + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + statement { + size_constraint_statement { + field_to_match { + single_header { + name = "cookie" + } + } + + comparison_operator = "GT" + size = var.max_expected_cookie_size + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-07-size-restrictions" + sampled_requests_enabled = false + } + } + + rule { + ## OWASP Top 10 A8 + ### CSRF token enforcement example + ### Enforce the presence of CSRF token in request header + name = "owasp-08-csrf-token-size" + priority = 7 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + and_statement { + statement { + byte_match_statement { + field_to_match { + method {} + } + + search_string = "post" + positional_constraint = "EXACTLY" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + size_constraint_statement { + field_to_match { + single_header { + name = var.csrf_expected_header + } + } + + comparison_operator = "EQ" + size = var.csrf_expected_size + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-08-csrf-token-size" + sampled_requests_enabled = false + } + } + + rule { + ## OWASP Top 10 A9 + ### Server-side includes & libraries in webroot + ### Matches request patterns for webroot objects that shouldn't be directly accessible + name = "owasp-09-match-ssi" + priority = 8 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + or_statement { + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".cfg" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".conf" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".config" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".ini" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".log" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".bak" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + statement { + byte_match_statement { + field_to_match { + uri_path {} + } + + search_string = ".backup" + positional_constraint = "ENDS_WITH" + + text_transformation { + priority = 1 + type = "LOWERCASE" + } + + } + } + + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-09-match-ssi" + sampled_requests_enabled = false + } + } + + rule { + ## 10. ## Gs IP addresses that should not be allowed to access content + name = "owasp-10-detect-blacklisted-ips" + priority = 9 + + action { + dynamic "count" { + for_each = var.wafv2_rule_action == "count" ? [1] : [] + content {} + } + + dynamic "block" { + for_each = var.wafv2_rule_action == "block" ? [1] : [] + content {} + } + + dynamic "allow" { + for_each = var.wafv2_rule_action == "allow" ? [1] : [] + content {} + } + } + + statement { + ip_set_reference_statement { + arn = aws_wafv2_ip_set.owasp_10_detect_blacklisted_ips.arn + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-10-detect-blacklisted-ips" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled + metric_name = "owasp-top10-security-issues" + sampled_requests_enabled = false + } +} diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/outputs.tf b/terraform/modules/aws-wafv2-top-10-owasp-rules/outputs.tf new file mode 100644 index 00000000..55de619e --- /dev/null +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/outputs.tf @@ -0,0 +1,3 @@ +output "rule_group_arn" { + value = aws_wafv2_rule_group.owasp_top10_rules.arn +} diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/variables.tf b/terraform/modules/aws-wafv2-top-10-owasp-rules/variables.tf new file mode 100644 index 00000000..45b420c0 --- /dev/null +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/variables.tf @@ -0,0 +1,56 @@ +variable "wafv2_rule_action" { + default = "block" +} + +variable "waf_scope" { + default = "CLOUDFRONT" +} + +variable "name" { + default = "test" +} + +variable "max_expected_uri_size" { + type = string + description = "Maximum number of bytes allowed in the URI component of the HTTP request. Generally the maximum possible value is determined by the server operating system (maps to file system paths), the web server software, or other middleware components. Choose a value that accomodates the largest URI segment you use in practice in your web application." + default = "512" +} + +variable "max_expected_query_string_size" { + type = string + description = "Maximum number of bytes allowed in the query string component of the HTTP request. Normally the of query string parameters following the ? in a URL is much larger than the URI , but still bounded by the of the parameters your web application uses and their values." + default = "1024" +} + +variable "max_expected_body_size" { + type = string + description = "Maximum number of bytes allowed in the body of the request. If you do not plan to allow large uploads, set it to the largest payload value that makes sense for your web application. Accepting unnecessarily large values can cause performance issues, if large payloads are used as an attack vector against your web application." + default = "4096" +} + +variable "max_expected_cookie_size" { + type = string + description = "Maximum number of bytes allowed in the cookie header. The maximum size should be less than 4096, the size is determined by the amount of information your web application stores in cookies. If you only pass a session token via cookies, set the size to no larger than the serialized size of the session token and cookie metadata." + default = "4093" +} + +variable "csrf_expected_header" { + type = string + description = "The custom HTTP request header, where the CSRF token value is expected to be encountered" + default = "x-csrf-token" +} + +variable "csrf_expected_size" { + type = string + description = "The size in bytes of the CSRF token value. For example if it's a canonically formatted UUIDv4 value the expected size would be 36 bytes/ASCII characters." + default = "36" +} + +variable "blacklisted_cidrs" { + type = list(string) + default = ["10.0.0.0/8", "192.168.0.0/16", "169.254.0.0/16", "172.16.0.0/16", "127.0.0.1/32"] +} +variable "cloudwatch_metrics_enabled" { + type = bool + default = false +} From 153b831bb8ed2315b84b89ce2aa54f27bff11e81 Mon Sep 17 00:00:00 2001 From: maxim Date: Wed, 7 Jul 2021 10:55:56 +0600 Subject: [PATCH 2/5] Update README for aws-wafv2-top-10-owasp-rules terraform module --- terraform/modules/aws-wafv2-top-10-owasp-rules/README.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md index 82bf9fee..9f3dc58d 100644 --- a/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md @@ -22,7 +22,7 @@ module "wafv2_owasp_top_10_rules" { blacklisted_cidrs = ["10.0.0.0/8", "192.168.0.0/16", "169.254.0.0/16", "172.16.0.0/16", "127.0.0.1/32"] } -resource "aws_wafv2_web_acl" "this" { +resource "aws_wafv2_web_acl" "example" { name = "${var.name}-${local.env}-webacl" scope = "CLOUDFRONT" @@ -58,4 +58,9 @@ resource "aws_wafv2_web_acl" "this" { } } +resource "aws_cloudfront_distribution" "example" { + ... + web_acl_id = aws_wafv2_web_acl.example.arn + ... +} ``` From a1b1cecfb46b321b547493ea96aef13a70762736 Mon Sep 17 00:00:00 2001 From: maxim Date: Wed, 7 Jul 2021 13:00:55 +0600 Subject: [PATCH 3/5] use waf_scope in a name --- terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf index 1fface6f..2ca3994e 100644 --- a/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf @@ -1,12 +1,12 @@ resource "aws_wafv2_ip_set" "owasp_10_detect_blacklisted_ips" { - name = "${var.name}-owasp-10-detect-blacklisted-ips" + name = "${var.name}-${var.waf_scope}-owasp-10-detect-blacklisted-ips" scope = var.waf_scope ip_address_version = "IPV4" addresses = var.blacklisted_cidrs } resource "aws_wafv2_rule_group" "owasp_top10_rules" { - name = "${var.name}-owasp-top10-security-issues" + name = "${var.name}-${var.waf_scope}-owasp-top10-security-issues" scope = var.waf_scope capacity = 580 @@ -999,7 +999,7 @@ resource "aws_wafv2_rule_group" "owasp_top10_rules" { visibility_config { cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled - metric_name = "owasp-top10-security-issues" + metric_name = "${var.name}-${var.waf_scope}-owasp-top10-security-issues" sampled_requests_enabled = false } } From 6dcce54ba9ba8c1e15dca742b9062b6e282bdbf0 Mon Sep 17 00:00:00 2001 From: maxim Date: Wed, 7 Jul 2021 13:02:49 +0600 Subject: [PATCH 4/5] use lower function for waf_scope in name --- terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf index 2ca3994e..21f63dc3 100644 --- a/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/main.tf @@ -1,12 +1,12 @@ resource "aws_wafv2_ip_set" "owasp_10_detect_blacklisted_ips" { - name = "${var.name}-${var.waf_scope}-owasp-10-detect-blacklisted-ips" + name = "${var.name}-${lower(var.waf_scope)}-owasp-10-detect-blacklisted-ips" scope = var.waf_scope ip_address_version = "IPV4" addresses = var.blacklisted_cidrs } resource "aws_wafv2_rule_group" "owasp_top10_rules" { - name = "${var.name}-${var.waf_scope}-owasp-top10-security-issues" + name = "${var.name}-${lower(var.waf_scope)}-owasp-top10-security-issues" scope = var.waf_scope capacity = 580 @@ -999,7 +999,7 @@ resource "aws_wafv2_rule_group" "owasp_top10_rules" { visibility_config { cloudwatch_metrics_enabled = var.cloudwatch_metrics_enabled - metric_name = "${var.name}-${var.waf_scope}-owasp-top10-security-issues" + metric_name = "${var.name}-${lower(var.waf_scope)}-owasp-top10-security-issues" sampled_requests_enabled = false } } From fb574100de8da9651bcebc521219d270b187bd9d Mon Sep 17 00:00:00 2001 From: maxim Date: Wed, 7 Jul 2021 13:55:18 +0600 Subject: [PATCH 5/5] add some notes about using waf + cloudfront --- terraform/modules/aws-wafv2-top-10-owasp-rules/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md index 9f3dc58d..b52ccbc3 100644 --- a/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md +++ b/terraform/modules/aws-wafv2-top-10-owasp-rules/README.md @@ -1,6 +1,8 @@ There are 2 implementations of AWS WAF: AWS WAF Classic and AWS WAFv2. AWS recommends using AWS WAFv2 for new installations. This terraform module creates AWS WAFv2 rule-group with rules that cover *OWASP TOP 10 security issues* (https://d0.awsstatic.com/whitepapers/Security/aws-waf-owasp.pdf). +For a CloudFront distribution, AWS WAF is available globally, but you must use the Region US East (N. Virginia) for all of your work. You must create your web ACL using the Region US East (N. Virginia). You must also use this Region to create any other resources that you use in your web ACL, like rule groups, IP sets, and regex pattern sets. + Example of using this module: ```bash module "wafv2_owasp_top_10_rules" {