Giter Club home page Giter Club logo

terraform-google-cloud-armor's Introduction

Cloud Armor Terraform Module

This module makes it easy to setup Cloud Armor global Security Policy with Security rules. You can attach the global Security Policy policy to backend services exposed by the following load balancer types:

  • Global external Application Load Balancer (HTTP/HTTPS)
  • Classic Application Load Balancer (HTTP/HTTPS)
  • Global external proxy Network Load Balancer (TCP/SSL)
  • Classic proxy Network Load Balancer (TCP/SSL)

There are five type of rules you can create in each policy:

  1. Pre-Configured Rules: These are based on pre-configured waf rules.
  2. Security Rules: Allow or Deny traffic from list of IP addresses or IP adress ranges.
  3. Custom Rules: You can create your own rules using Common Expression Language (CEL).
  4. Threat Intelligence Rules: Add Rules based on threat intelligence. Managed protection plus subscription is needed to use this feature.
  5. Automatically deploy Adaptive Protection Suggested Rules; When enable module will create a rule for automatically deploying the suggested rules that Adaptive Protection generates.

NOTE: For external passthrough Network Load Balancers, protocol forwarding and VMs with public IP addresses create network Edge Security policy using advanced network DDoS protection and network edge security policy sub-modules.

Compatibility

This module is meant for use with Terraform 1.3+ and tested using Terraform 1.3+. If you find incompatibilities using Terraform >=1.3, please open an issue.

Version

Current version is 2.X. Upgrade guides:

Module Format

module security_policy {
  source = "GoogleCloudPlatform/cloud-armor/google"

  project_id                           = "my-project-id"
  name                                 = "my-test-ca-policy"
  description                          = "Test Cloud Armor security policy with preconfigured rules, security rules and custom rules"
  default_rule_action                  = "deny(403)"
  type                                 = "CLOUD_ARMOR"
  layer_7_ddos_defense_enable          = true
  layer_7_ddos_defense_rule_visibility = "STANDARD"
  recaptcha_redirect_site_key          = google_recaptcha_enterprise_key.primary.name
  json_parsing                         = "STANDARD"
  log_level                            = "VERBOSE"

  pre_configured_rules                 = {}
  security_rules                       = {}
  custom_rules                         = {}
  threat_intelligence_rules            = {}
  adaptive_protection_auto_deploy      = {}
}

Rule details and Sample Code for each type of rule is available here

Usage

There are examples included in the examples folder but simple usage is as follows:

module "security_policy" {
  source = "GoogleCloudPlatform/cloud-armor/google"
  version = "~> 2.2"

  project_id                           = var.project_id
  name                                 = "my-test-security-policy"
  description                          = "Test Security Policy"
  recaptcha_redirect_site_key          = google_recaptcha_enterprise_key.primary.name
  default_rule_action                  = "allow"
  type                                 = "CLOUD_ARMOR"
  layer_7_ddos_defense_enable          = true
  layer_7_ddos_defense_rule_visibility = "STANDARD"

  # Pre-configured WAF Rules

  pre_configured_rules = {

    "sqli_sensitivity_level_4" = {
      action          = "deny(502)"
      priority        = 1
      target_rule_set = "sqli-v33-stable"

      sensitivity_level = 4
      description       = "sqli-v33-stable Sensitivity Level 4 and 2 preconfigured_waf_config_exclusions"
    }

    "xss-stable_level_2_with_exclude" = {
      action                  = "deny(502)"
      priority                = 2
      description             = "XSS Sensitivity Level 2 with excluded rules"
      preview                 = true
      target_rule_set         = "xss-v33-stable"
      sensitivity_level       = 2
      exclude_target_rule_ids = ["owasp-crs-v030301-id941380-xss", "owasp-crs-v030301-id941280-xss"]
    }

    "php-stable_level_0_with_include" = {
      action                  = "deny(502)"
      priority                = 3
      description             = "PHP Sensitivity Level 0 with included rules"
      target_rule_set         = "php-v33-stable"
      include_target_rule_ids = ["owasp-crs-v030301-id933190-php", "owasp-crs-v030301-id933111-php"]
    }

  }

  # Action against specific IP addresses or IP adress ranges

  security_rules = {

    "deny_project_bad_actor1" = {
      action        = "deny(502)"
      priority      = 11
      description   = "Deny Malicious IP address from project bad_actor1"
      src_ip_ranges = ["190.217.68.211/32", "45.116.227.68/32", "103.43.141.122", "123.11.215.36", "123.11.215.37", ]
      preview       = true
    }

    "rate_ban_project_actor3" = {
      action        = "rate_based_ban"
      priority      = 14
      description   = "Rate based ban for address from project actor3 only if they cross banned threshold"
      src_ip_ranges = ["190.217.68.213", "45.116.227.70", ]
      rate_limit_options = {
        exceed_action                        = "deny(502)"
        rate_limit_http_request_count        = 10
        rate_limit_http_request_interval_sec = 60
        ban_duration_sec                     = 600
        ban_http_request_count               = 1000
        ban_http_request_interval_sec        = 300
        enforce_on_key                       = "ALL"
      }
    }
  }

  # Custom Rules using CEL

  custom_rules = {

    deny_specific_regions = {
      action      = "deny(502)"
      priority    = 21
      description = "Deny specific Regions"
      expression  = <<-EOT
        '[AU,BE]'.contains(origin.region_code)
      EOT
    }

    deny_specific_ip = {
      action      = "deny(502)"
      priority    = 22
      description = "Deny specific IP address in US Region"
      expression  = <<-EOT
        origin.region_code == "US" && inIpRange(origin.ip, '47.185.201.159/32')
      EOT
    }

    allow_path_token_header = {
      action      = "allow"
      priority    = 25
      description = "Allow path and token match with addition of header"

      expression = <<-EOT
        request.path.matches('/login.html') && token.recaptcha_session.score < 0.2
      EOT

      header_action = [
        {
          header_name  = "reCAPTCHA-Warning"
          header_value = "high"
        },
        {
          header_name  = "X-Resource"
          header_value = "test"
        }
      ]

    }
  }

  # Threat Intelligence Rules

  threat_intelligence_rules = {

    deny_malicious_ips = {
      action      = "deny(502)"
      priority    = 200
      description = "Deny IP addresses known to attack web applications"
      preview     = false
      feed        = "iplist-known-malicious-ips"
      exclude_ip  = "['47.100.100.100', '47.189.12.139']"
    }
  }

}

resource "google_compute_backend_service" "backend_service" {
  provider = google-beta

  ## Attach Cloud Armor policy to the backend service
  security_policy = module.cloud_armor.policy.self_link

  project = var.project_id

  name        = "glb-ca-web-backend-svc-a"
  port_name   = "http"
  protocol    = "HTTP"
  timeout_sec = 10

  backend {
    group           = google_compute_instance_group.ca_vm_1_ig.self_link
    max_utilization = 0.5
  }

  health_checks         = [google_compute_http_health_check.default.id]
  load_balancing_scheme = "EXTERNAL"
}

Inputs

Name Description Type Default Required
adaptive_protection_auto_deploy Configuration for Automatically deploy Cloud Armor Adaptive Protection suggested rules. priority and action fields are required if enable is set to true. Requires layer_7_ddos_defense_enable set to true.
object({
enable = bool
priority = optional(number, null)
action = optional(string, null)
preview = optional(bool, false)
description = optional(string, "Adaptive Protection auto-deploy")
load_threshold = optional(number)
confidence_threshold = optional(number)
impacted_baseline_threshold = optional(number)
expiration_sec = optional(number)
redirect_type = optional(string)
redirect_target = optional(string)

rate_limit_options = optional(object({
enforce_on_key = optional(string)
enforce_on_key_name = optional(string)

enforce_on_key_configs = optional(list(object({
enforce_on_key_name = optional(string)
enforce_on_key_type = optional(string)
})))

exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}), {})
})
{
"enable": false
}
no
custom_rules Custome security rules
map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
expression = string
redirect_type = optional(string, null)
redirect_target = optional(string, null)
rate_limit_options = optional(object({
enforce_on_key = optional(string)
enforce_on_key_name = optional(string)
enforce_on_key_configs = optional(list(object({
enforce_on_key_name = optional(string)
enforce_on_key_type = optional(string)
})))
exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}),
{})
header_action = optional(list(object({
header_name = optional(string)
header_value = optional(string)
})), [])

preconfigured_waf_config_exclusion = optional(object({
target_rule_set = string
target_rule_ids = optional(list(string), [])
request_header = optional(list(object({
operator = string
value = optional(string)
})))
request_cookie = optional(list(object({
operator = string
value = optional(string)
})))
request_uri = optional(list(object({
operator = string
value = optional(string)
})))
request_query_param = optional(list(object({
operator = string
value = optional(string)
})))
}), { target_rule_set = null }) # Obsolete. Use preconfigured_waf_config_exclusions

preconfigured_waf_config_exclusions = optional(map(object({
target_rule_set = string
target_rule_ids = optional(list(string), [])
request_header = optional(list(object({
operator = string
value = optional(string)
})))
request_cookie = optional(list(object({
operator = string
value = optional(string)
})))
request_uri = optional(list(object({
operator = string
value = optional(string)
})))
request_query_param = optional(list(object({
operator = string
value = optional(string)
})))
})), null)

}))
{} no
default_rule_action default rule that allows/denies all traffic with the lowest priority (2,147,483,647). string "allow" no
description An optional description of this security policy. Max size is 2048. string null no
json_custom_config_content_types A list of custom Content-Type header values to apply the JSON parsing. Only applicable when json_parsing is set to STANDARD. Not supported for CLOUD_ARMOR_EDGE policy type. list(string) [] no
json_parsing Whether or not to JSON parse the payload body. Possible values are DISABLED and STANDARD. Not supported for CLOUD_ARMOR_EDGE policy type. string "DISABLED" no
layer_7_ddos_defense_enable (Optional) If set to true, enables Cloud Armor Adaptive Protection for L7 DDoS detection. Cloud Armor Adaptive Protection is only supported in Global Security Policies of type CLOUD_ARMOR. Set this variable true for Adaptive Protection Auto Deploy. bool false no
layer_7_ddos_defense_rule_visibility (Optional) Rule visibility can be one of the following: STANDARD - opaque rules. PREMIUM - transparent rules. This field is only supported in Global Security Policies of type CLOUD_ARMOR. string "STANDARD" no
log_level Log level to use. Possible values are NORMAL and VERBOSE. Not supported for CLOUD_ARMOR_EDGE policy type. string "NORMAL" no
name Name of the security policy. string n/a yes
pre_configured_rules Map of pre-configured rules with Sensitivity levels. preconfigured_waf_config_exclusion is obsolete and available for backward compatibility. Use preconfigured_waf_config_exclusions which allows multiple exclusions
map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
redirect_type = optional(string, null)
redirect_target = optional(string, null)
target_rule_set = string
sensitivity_level = optional(number, 4)
include_target_rule_ids = optional(list(string), [])
exclude_target_rule_ids = optional(list(string), [])
rate_limit_options = optional(object({
enforce_on_key = optional(string)
enforce_on_key_name = optional(string)
enforce_on_key_configs = optional(list(object({
enforce_on_key_name = optional(string)
enforce_on_key_type = optional(string)
})))
exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}), {})

header_action = optional(list(object({
header_name = optional(string)
header_value = optional(string)
})), [])

preconfigured_waf_config_exclusion = optional(object({
target_rule_set = string
target_rule_ids = optional(list(string), [])
request_header = optional(list(object({
operator = string
value = optional(string)
})))
request_cookie = optional(list(object({
operator = string
value = optional(string)
})))
request_uri = optional(list(object({
operator = string
value = optional(string)
})))
request_query_param = optional(list(object({
operator = string
value = optional(string)
})))
}), { target_rule_set = null }) # Obsolete. Use preconfigured_waf_config_exclusions

preconfigured_waf_config_exclusions = optional(map(object({
target_rule_set = string
target_rule_ids = optional(list(string), [])
request_header = optional(list(object({
operator = string
value = optional(string)
})))
request_cookie = optional(list(object({
operator = string
value = optional(string)
})))
request_uri = optional(list(object({
operator = string
value = optional(string)
})))
request_query_param = optional(list(object({
operator = string
value = optional(string)
})))
})), null)

}))
{} no
project_id The project in which the resource belongs. string n/a yes
recaptcha_redirect_site_key reCAPTCHA site key to be used for all the rules using the redirect action with the redirect type of GOOGLE_RECAPTCHA. string null no
security_rules Map of Security rules with list of IP addresses to block or unblock.
map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
redirect_type = optional(string, null)
redirect_target = optional(string, null)
src_ip_ranges = list(string)
rate_limit_options = optional(object({
enforce_on_key = optional(string)
enforce_on_key_name = optional(string)
enforce_on_key_configs = optional(list(object({
enforce_on_key_name = optional(string)
enforce_on_key_type = optional(string)
})))
exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}),
{})
header_action = optional(list(object({
header_name = optional(string)
header_value = optional(string)
})), [])
}))
{} no
threat_intelligence_rules Map of Threat Intelligence Feed rules
map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
feed = string
exclude_ip = optional(string)
rate_limit_options = optional(object({
enforce_on_key = optional(string)
enforce_on_key_name = optional(string)
enforce_on_key_configs = optional(list(object({
enforce_on_key_name = optional(string)
enforce_on_key_type = optional(string)
})))
exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}),
{})
header_action = optional(list(object({
header_name = optional(string)
header_value = optional(string)
})), [])
}))
{} no
type Type indicates the intended use of the security policy. Possible values are CLOUD_ARMOR and CLOUD_ARMOR_EDGE. string "CLOUD_ARMOR" no
user_ip_request_headers An optional list of case-insensitive request header names to use for resolving the callers client IP address. list(string) [] no

Outputs

Name Description
policy Security policy created

Rules

Pre-Configured Rules, Security Rules, Custom Rules and Threat Intelligence Rules are maps of rules. Each rule is a map which provides details about the rule. Here is an example of pre_configured_rules:

  "my_rule" = {
    action                             = "deny(502)"
    priority                             = 1
    description                          = "SQL Sensitivity Level 4"
    preview                              = false
    redirect_type                        = null
    redirect_target                      = null
    target_rule_set                      = "sqli-v33-stable"
    sensitivity_level                    = 4
    include_target_rule_ids              = []
    exclude_target_rule_ids              = []
    header_action                        = []
    rate_limit_options                   = {}
    preconfigured_waf_config_exclusions  = {}
  }

action, priority, description, preview, rate_limit_options, header_action, redirect_type and redirect_target are common in all the rule types. Some of then are optional and some have default value see Input.

Rate limit

rate_limit_options is needed for the rules where action is set to throttle or rate_based_ban. rate_limit_options is a map of strings with following key pairs. You can find more details about rate limit here.

rate_limit_options = {
  exceed_action                        = "deny(502)"
  rate_limit_http_request_count        = 10
  rate_limit_http_request_interval_sec = 60    # must be one of 60, 120, 180, 240, 300, 600, 900, 1200, 1800, 2700, 3600 seconds
  ban_duration_sec                     = 600   # needed only if action is rate_based_ban
  ban_http_request_count               = 1000  # needed only if action is rate_based_ban
  ban_http_request_interval_sec        = 300   # must be one of 60, 120, 180, 240, 300, 600, 900, 1200, 1800, 2700, 3600 seconds. needed only if action is rate_based_ban
  enforce_on_key                       = "ALL" # All is default value. If null is passed terraform will use ALL as the value. Will be set to "" when `enforce_on_key_configs` is not null

  enforce_on_key_configs = [
    {
      enforce_on_key_type = "HTTP_PATH"
    },
    {
      enforce_on_key_type = "HTTP_COOKIE"
      enforce_on_key_name = "site_id"
    }
  ]
}

Preconfigured WAF Config

‼️ NOTE: preconfigured_waf_config_exclusion in pre_configured_rules and custom_rules is obsolete and available for backward compatibility only. Use pre_configured_rules.preconfigured_waf_config_exclusions which allows multiple exclusions. They are mutually exclusive.

preconfigured_waf_config_exclusions is needed for custom application that might contain content in request fields (like headers, cookies, query parameters, or URIs) that matches signatures in preconfigured WAF rules, but which you know is legitimate. In this case, you can reduce false positives by excluding those request fields from inspection by associating a list of exclusions for request fields with the security policy rule. You can pass request_header, request_uri, request_cookie and request_query_param. It is available in Pre-Configured Rules. You can find more details about preconfigured_waf_config here

preconfigured_waf_config_exclusions = {

  exclusion_1 = {
    target_rule_set = "sqli-v33-stable"
    target_rule_ids = ["owasp-crs-v030301-id942120-sqli", "owasp-crs-v030301-id942130-sqli"]
    request_cookie = [
      {
        operator = "STARTS_WITH"
        value    = "abc"
      }
    ]
    request_header = [
      {
        operator = "STARTS_WITH"
        value    = "xyz"
      },
      {
        operator = "STARTS_WITH"
        value    = "uvw"
      }
    ]
  }

  exclusion_2 = {
    target_rule_set = "sqli-v33-stable"
    target_rule_ids = ["owasp-crs-v030301-id942150-sqli", "owasp-crs-v030301-id942180-sqli"]
    request_header = [
      {
        operator = "STARTS_WITH"
        value    = "lmn"
      },
      {
        operator = "ENDS_WITH"
        value    = "opq"
      }
    ]
    request_uri = [
      {
        operator = "CONTAINS"
        value    = "https://hashicorp.com"
      },
      {
        operator = "CONTAINS"
        value    = "https://xyz.com"
      },
    ]
  }

}

pre_configured_rules

List of preconfigured rules are available here. Following is the key value pairs for setting up pre configured rules. include_target_rule_ids and exclude_target_rule_ids are mutually exclusive. If include_target_rule_ids is provided, sensitivity_level is automatically set to 0 by the module as it is a requirement for opt in rule signature. exclude_target_rule_ids is ignored when include_target_rule_ids is provided.

Format:

  "sqli_sensitivity_level_4" = {
    action                               = "deny(502)"
    priority                             = 1
    description                          = "SQL Sensitivity Level 4"
    preview                              = false
    redirect_type                        = null
    redirect_target                      = null
    target_rule_set                      = "sqli-v33-stable"
    sensitivity_level                    = 4
    include_target_rule_ids              = []
    exclude_target_rule_ids              = []
    rate_limit_options                   = {}
    header_action                        = []
    preconfigured_waf_config_exclusions  = {}
  }

Sample:

pre_configured_rules = {

  "php-stable_level_1_with_include" = {
    action                  = "deny(502)"
    priority                = 3
    description             = "PHP Sensitivity Level 1 with included rules"
    target_rule_set         = "xss-v33-stable"
    sensitivity_level       = 0
    include_target_rule_ids = ["owasp-crs-v030301-id933190-php", "owasp-crs-v030301-id933111-php"]
  }

  "sqli_sensitivity_level_4" = {
    action            = "deny(502)"
    priority          = 1
    target_rule_set   = "sqli-v33-stable"
    sensitivity_level = 4

    preconfigured_waf_config_exclusions = {

      exclusion_1 = {
        target_rule_set = "sqli-v33-stable"
        target_rule_ids = ["owasp-crs-v030301-id942120-sqli", "owasp-crs-v030301-id942130-sqli"]
        request_cookie = [
          {
            operator = "STARTS_WITH"
            value    = "abc"
          }
        ]
        request_header = [
          {
            operator = "STARTS_WITH"
            value    = "xyz"
          },
          {
            operator = "STARTS_WITH"
            value    = "uvw"
          }
        ]
      }

      exclusion_2 = {
        target_rule_set = "sqli-v33-stable"
        target_rule_ids = ["owasp-crs-v030301-id942150-sqli", "owasp-crs-v030301-id942180-sqli"]
        request_header = [
          {
            operator = "STARTS_WITH"
            value    = "lmn"
          },
          {
            operator = "ENDS_WITH"
            value    = "opq"
          }
        ]
        request_uri = [
          {
            operator = "CONTAINS"
            value    = "https://hashicorp.com"
          },
          {
            operator = "CONTAINS"
            value    = "https://xyz.com"
          },
        ]
      }

    }

  }

}

security_rules:

Set of IP addresses or ranges (IPV4 or IPV6) in CIDR notation to match against inbound traffic. There is a limit of 10 IP ranges per rule.

Format:

Each rule is key value pair where key is a unique name of the rule and value is the action associated with it.

"block_bad_actor_ip" = {
  action             = "deny(502)"
  priority           = 11
  description        = "Deny Malicious IP address"
  src_ip_ranges      = ["A..B.C.D", "W.X.Y.Z",]
  preview            = false
  redirect_type      = null
  redirect_target    = null
  rate_limit_options = {}
  header_action      = []
}

Sample:

security_rules = {

  "deny_project_bad_actor" = {
    action             = "deny(502)"
    priority           = 11
    description        = "Deny Malicious IP address from project bad_actor"
    src_ip_ranges      = ["190.217.68.211/32", "45.116.227.68/32", "103.43.141.122", "123.11.215.36", ]
  }

  "throttle_project_droptwenty" = {
    action        = "throttle"
    priority      = 15
    description   = "Throttle IP addresses from project droptwenty"
    src_ip_ranges = ["190.217.68.214", "45.116.227.71", ]

    rate_limit_options = {
      exceed_action                        = "deny(502)"
      rate_limit_http_request_count        = 10
      rate_limit_http_request_interval_sec = 60
      enforce_on_key_configs = [
        {
          enforce_on_key_type = "HTTP_PATH"
        },
        {
          enforce_on_key_type = "HTTP_COOKIE"
          enforce_on_key_name = "site_id"
        }
      ]
    }

  }

}

custom_rules:

Add Custom Rules using Common Expression Language (CEL)

Format:

Each rule is key value pair where key is a unique name of the rule and value is the action associated with it.

allow_specific_regions = {
  action             = "allow"
  priority           = 21
  description        = "Allow specific Regions"
  preview            = false
  expression         = <<-EOT
    '[US,AU,BE]'.contains(origin.region_code)
  EOT
  redirect_type      = null
  redirect_target    = null
  rate_limit_options = {}
  header_action      = []
}

Sample:

custom_rules = {

  allow_specific_regions = {
    action             = "allow"
    priority           = 21
    description        = "Allow specific Regions"
    preview            = true
    expression         = <<-EOT
      '[US,AU,BE]'.contains(origin.region_code)
    EOT
  }

  allow_path_token_header = {
    action      = "allow"
    priority    = 25
    description = "Allow path and token match with addition of header"

    expression = <<-EOT
      request.path.matches('/login.html') && token.recaptcha_session.score < 0.2
    EOT

    header_action = [
      {
        header_name  = "reCAPTCHA-Warning"
        header_value = "high"
      },
      {
        header_name  = "X-Resource"
        header_value = "test"
      }
    ]

  }

}

threat_intelligence_rules:

Add Rules based on threat intelligence. Managed protection plus subscription is needed to use this feature.

Format:

Each rule is key value pair where key is a unique name of the rule and value is the action associated with it. NOTE: exclude_ip is a string with IP addresse(s) in single quotes and enclused within a sqare bracket (You can find detail here).

threat_intelligence_rules = {
  deny_crawlers_ip = {
    action             = "deny(502)"
    priority           = 31
    description        = "Deny IP addresses of search engine crawlers"
    preview            = false
    feed               = "iplist-search-engines-crawlers"
    exclude_ip         = null
    rate_limit_options = {}
    header_action      = []
  }
}

Sample:

threat_intelligence_rules = {

  deny_malicious_ips = {
    action      = "deny(502)"
    priority    = 31
    description = "Deny IP addresses known to attack web applications"
    preview     = true
    feed        = "iplist-known-malicious-ips"
    exclude_ip  = "['47.100.100.100', '47.189.12.139']"
  }

  deny_tor_exit_ips = {
    action      = "deny(502)"
    priority    = 31
    description = "Deny Tor exit nodes IP addresses"
    preview     = true
    feed        = "iplist-tor-exit-nodes"
  }

}

adaptive_protection_auto_deploy:

Add a rule to Automatically deploy Adaptive Protection suggested rules. Managed protection plus subscription is needed to use this feature. By default this feature is disabled. If enable is set to true you need to provide priority and action for this module to deploy auto deploy rule. Module will create a rule with expression evaluateAdaptiveProtectionAutoDeploy().

Format:

It is an object with key value pair.

adaptive_protection_auto_deploy = {
  enable                      = true
  action                      = "deny(502)"
  priority                    = 31
  description                 = "Automatically deploy Adaptive Protection suggested rules"
  preview                     = false
  load_threshold              = 0.1
  confidence_threshold        = 0.5
  impacted_baseline_threshold = 0.01
  expiration_sec              = 7200
  redirect_type               = null
  redirect_target             = null
  rate_limit_options          = {}
}

Sample 1 (Deny):

adaptive_protection_auto_deploy = {
  enable   = true
  priority = 100000
  action   = "deny(403)"
}

Sample 2 (redirect):

adaptive_protection_auto_deploy = {
  enable         = true
  priority       = 100000
  action         = "redirect"
  redirect_type  = "GOOGLE_RECAPTCHA"
}

Sample 3 (throttle):

adaptive_protection_auto_deploy = {
  enable   = true
  priority = 100000
  action   = "throttle"

  rate_limit_options = {
    exceed_action                        = "deny(502)"
    rate_limit_http_request_count        = 500
    rate_limit_http_request_interval_sec = 120
    enforce_on_key                       = "IP"
  }
}

Requirements

These sections describe requirements for using this module.

Software

The following dependencies must be available:

  • [Terraform][terraform] v1.3+
  • [Terraform Provider for GCP][terraform-provider-gcp] plugin v4.79+

Service Account

A service account with the following permission must be used to provision the resources of this module:

  • compute.networkEdgeSecurityServices.create
  • compute.networkEdgeSecurityServices.update
  • compute.networkEdgeSecurityServices.get
  • compute.networkEdgeSecurityServices.delete
  • compute.networkEdgeSecurityServices.list
  • compute.securityPolicies.create
  • compute.securityPolicies.delete
  • compute.securityPolicies.get
  • compute.securityPolicies.list
  • compute.securityPolicies.use
  • compute.securityPolicies.update
  • recaptchaenterprise.keys.list
  • recaptchaenterprise.keys.get

Following roles contain above mentioned permissions. You can either assing one of the following role or create custom roles with above permissions.

  • Compute Organization Security Policy Admin: roles/compute.orgSecurityPolicyAdmin
  • Compute Security Admin: roles/compute.securityAdmin
  • reCAPTCHA Enterprise Admin: roles/recaptchaenterprise.admin

Enable API's

In order to operate with the Service Account you must activate the following API on the project where the Service Account was created:

  • Compute Engine API - compute.googleapis.com

Contributing

Refer to the contribution guidelines for information on contributing to this module.

terraform-google-cloud-armor's People

Contributors

apeabody avatar bharathkkb avatar cleming avatar cloud-foundation-bot avatar dependabot[bot] avatar imrannayer avatar pablogamboa avatar release-please[bot] avatar renovate-bot avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

terraform-google-cloud-armor's Issues

removing security_rules tries to delete the policy and fails

What I'm expecting to happened - Delete a specific rule from the rules in the policy, similar to how we can add/remove from the UI.

What happens - seems like terraform tries to delete and recreate the whole policy and fails.

After removing security_rules section, we're getting the following error when applying the changes:
Error: Error waiting for Deleting SecurityPolicy: The security_policy resource '...' is already being used by '...'

This means we need to remove the policy from being used by other resources each time we change a specific rules.

Got 400 error when adding a rule to a list of custom rules using this module

Still happening with latest version 2.0.1.

How to reproduce the error:

      - rule {
          - action      = "rate_based_ban" -> null
          - description = "rate-limit/ban test" -> null
          - preview     = false -> null
          - priority    = 40008 -> null

          - match {
              - expr {
                  - expression = <<-EOT
                        request.path.matches('(?i)^/some-path/')
                    EOT -> null
                }
            }

          - rate_limit_options {
              - ban_duration_sec = 600 -> null
              - conform_action   = "allow" -> null
              - exceed_action    = "deny(403)" -> null

              - ban_threshold {
                  - count        = 100 -> null
                  - interval_sec = 600 -> null
                }

              - enforce_on_key_configs {
                  - enforce_on_key_type = "IP" -> null
                }

              - rate_limit_threshold {
                  - count        = 50 -> null
                  - interval_sec = 600 -> null
                }
            }
        }
      + rule {
          + action      = "deny(403)"
          + description = "Deny test"
          + preview     = false
          + priority    = 40008

          + match {
              + expr {
                  + expression = <<-EOT
                        request.path.matches('(?i)^//[^/]+/\\.\\.;/css')
                    EOT
                }
            }
        }
...
│ Error: Error updating SecurityPolicy "public": googleapi: Error 400: Invalid value for field 'resource.rateLimitOptions': ''. Rate limit options must be specified if the action is 'fairshare', 'rate_based_ban' or 'throttle'. It cannot be specified for any other actions, invalid
│
│   with module.security_policies["gumtree-au-prod"].google_compute_security_policy.policy,
│   on .terraform/modules/security_policies/main.tf line 64, in resource "google_compute_security_policy" "policy":
│   64: resource "google_compute_security_policy" "policy" {
│

Note the new rule (deny) replacing the old rule (rate based ban) with the same priority.

advanced_options_config block is not supported for CLOUD_ARMOR_EDGE

This advanced_options_config block is only supported for CLOUD_ARMOR type.

advanced_options_config {
    json_parsing = var.json_parsing
    log_level    = var.log_level
    dynamic "json_custom_config" {
      for_each = var.json_parsing == "STANDARD" && length(var.json_custom_config_content_types) > 0 ? ["json_custom_config"] : []
      content {
        content_types = var.json_custom_config_content_types
      }
    }
  }

I'm getting the following error when I try to use this module to setup a security policy for CLOUD_ARMOR_EDGE
│ Error: Error creating SecurityPolicy: googleapi: Error 400: Invalid value for field 'resource.advancedOptionsConfig': '{ "jsonCustomConfig": { }}'. Advanced options for Cloud Armor are currently only supported for security policies with CLOUD_ARMOR type., invalid

I've try to passed in null values for those variables, but its not skipping that block. It's still trying to provision it.

enforce_on_key_name missing from variables.tf

enforce_on_key_name is defined for the rules

However it is missing from variables.tf under the definitons for rate_limit_options so it is not applied:

Terraform:

  security_rules = {
    "throttle_api_reqs_xapikey" = {
      action        = "throttle"
      priority      = 15
      description   = "Throttle requests on X-API-KEY header"
      src_ip_ranges = ["*"]
      preview       = false
      rate_limit_options = {
        exceed_action                        = local.exceed_action
        rate_limit_http_request_count        = local.rate_limit_http_request_count
        rate_limit_http_request_interval_sec = local.rate_limit_http_request_interval_sec
        enforce_on_key                       = "HTTP_HEADER"
        enforce_on_key_name                  = "X-API-KEY"
      }
    }
}

Output of terraform plan

rule {
          + action      = "throttle"
          + description = "Throttle requests on X-API-KEY header"
          + preview     = false
          + priority    = 15

          + match {
              + versioned_expr = "SRC_IPS_V1"

              + config {
                  + src_ip_ranges = [
                      + "*",
                    ]
                }
            }

          + rate_limit_options {
              + conform_action = "allow"
              + enforce_on_key = "HTTP_HEADER"
              + exceed_action  = "deny(429)"

              + rate_limit_threshold {
                  + count        = 500
                  + interval_sec = 60
                }
            }
        }

Adding this to the variables block is working when cloned locally. Happy to raise a PR for this if needed.

New self_link output

Is it possible to get the self_link reference added as an output?

output "self_link" {
  description = "The URI of the created resource"
  value       = google_compute_security_policy.policy.self_link
}

Unsupported argument error with 1.2.0 release

I would like to
Report that we are experiencing Unsupported Argument errors with the newly released 1.2.0 version, the exact error string is in the below code block.

In order to
Ensure the provider works as intended

Other Information:
Module version: 1.2.0
Provider version: v4.73.2

Cannot find this argument in the provider either: https://github.com/hashicorp/terraform-provider-google/blob/main/google/services/compute/resource_compute_security_policy.go

Error Message:

╷
│ Error: Unsupported argument
│
│   on .terraform/modules/cloud-armor/main.tf line 84, in resource "google_compute_security_policy" "policy":
│   84:       user_ip_request_headers = var.user_ip_request_headers
│
│ An argument named "user_ip_request_headers" is not expected here.
╵

Variable layer_7_ddos_defense_enable is marked as optional but is not

Hello,

I got this error:

│ Error: Operation failed
│ 
│   on .terraform/modules/cloud-armor/main.tf line 458, in resource "google_compute_security_policy" "policy":
│  458:     for_each = var.layer_7_ddos_defense_enable && var.type != "CLOUD_ARMOR_EDGE" ? ["adaptive_protection_config"] : []
│     ├────────────────
│     │ var.layer_7_ddos_defense_enable is null
│     │ var.type is "CLOUD_ARMOR_EDGE"
│ 
│ Error during operation: argument must not be null.

With these variables:

        name        = "second-test"
        type        = "CLOUD_ARMOR_EDGE"

        default_rule_action = "allow"

        layer_7_ddos_defense_enable = null
        recaptcha_redirect_site_key = null

        pre_configured_rules = {}
        security_rules = {}
        threat_intelligence_rules = {}
        custom_rules = {}

The layer_7_ddos_defense_enable variable is marked as optional AND unsuported for CLOUD_ARMOR_EDGE type in the documentation, but does not appear to be actually so.
Same problem with type CLOUD_ARMOR.

Regards,

No support for policy type CLOUD_ARMOR_NETWORK

One of the requirements for enabling advanced DDoS protection is to use the security policy type CLOUD_ARMOR_NETWORK.

When I try to use that type, though, I get the following error from the Google provider, whether I use google or google-beta:

-Error: expected type to be one of [CLOUD_ARMOR CLOUD_ARMOR_EDGE CLOUD_ARMOR_INTERNAL_SERVICE], got CLOUD_ARMOR_NETWORK

  on waf_enforced_security_policy.tf line 3, in resource "google_compute_security_policy" "policy-waf-enforced":
   3:   type = "CLOUD_ARMOR_NETWORK"

How to use threat intelligence feeds

Can you please add an example to show how we can use Threat Intelligence feeds using Terraform?
For example, an equivalent of "evaluateThreatIntelligence('iplist-known-malicious-ips')" @imrannayer

log_level support

Hi, I saw in the README that this module does support log_level modification. However, when I do

module "cloud_armor_policy" {
  source = "GoogleCloudPlatform/cloud-armor/google"

  version    = "0.2.0"
  project_id = var.project_id
  name       = "cloud-armor-policy-${terraform.workspace}"
  log_level  = "VERBOSE"
}

I got

Error: Unsupported argument

  on main.tf line 7, in module "cloud_armor_policy":
   7:   log_level  = "VERBOSE"

An argument named "log_level" is not expected here.

I wonder if I am missing anything here. Thank you!

Add recaptcha_options_config.redirect_site_key

Add Recaptcha recaptcha_options_config.redirect_site_key option to cloud armor module.

resource "google_compute_security_policy" "policy" {
  name        = "my-policy"
  description = "basic security policy"
  type        = "CLOUD_ARMOR"

  recaptcha_options_config {
    redirect_site_key = google_recaptcha_enterprise_key.primary.name
  }
}

No option to turn on GraphQL parsing via TF

Cloud Armor allows GraphQL parsing via the JSON parsing field -
image

but STANDARD_WITH_GRAPHQL doesn't seem to be an option via TF

image

Confirmed as STANDARD_WITH_GRAPHQL not working when in the json_parsing parameter in terraform deployment

redirect_target missing for rules that allow redirect_type = "EXTERNAL_302"

When setting redirect type to "EXTERNAL_302" the following error occurs

│ Error: Invalid index
│
│   on .terraform/modules/security_polcy/main.tf line 206, in resource "google_compute_security_policy" "policy":
│  206:           target = rule.value["redirect_type"] == "EXTERNAL_302" ? rule.value["redirect_target"] : null
│     ├────────────────
│     │ rule.value is object with 7 attributes
│
│ The given key does not identify an element in this collection value.

variables.tf seems to be missing redirect_target for rule values.

Add labels on resource level "google_compute_security_policy"

Hi Team,

We are calling terraform-google-cloud-armor module and resource "google_compute_security_policy", but there are no resource labels available in this resource. We also enforced hard-mandatory sentinel policies which check resource labels are attached to each and every resource.

main.tf

module "security_policy_default" {
  source                               = "git::https://github.com/GoogleCloudPlatform/terraform-google-cloud-armor.git?ref=v2.0.1"
  project_id                           = "project-1"
  name                                 = "sample-default-policy"
  description                          = "Test Cloud Armor security policy with preconfigured rules, security rules and custom rules"
  default_rule_action                  = "deny(403)"
  type                                 = "CLOUD_ARMOR"
  layer_7_ddos_defense_rule_visibility = "STANDARD"
  json_parsing                         = "STANDARD"
}

Auto deploy settings are not being applied.

When setting the adaptive_protection_auto_deploy block, certain settings are not being processed by the module.

For a policy like this:

module "security_policy" {
  source = "GoogleCloudPlatform/cloud-armor/google"
  version = "~> 2.0"
  ...
  layer_7_ddos_defense_enable  = true
  ...
  adaptive_protection_auto_deploy = {
    enable   = true
    priority = 3000
    action   = "deny(403)"
    description                 = "Automatically deploy Adaptive Protection suggested rules"
    preview                     = false
    load_threshold              = 0.8
    confidence_threshold        = 0.5
    impacted_baseline_threshold = 0.01
    expiration_sec              = 3600
  }
}

The fields load_threshold, confidence_threshold, impacted_baseline_threshold & expiration_sec are simply not being processed by the module. I had a look at the source code and can't find a reference for those fields.

They are declared in the variables properly, just not used as far as I can tell.

How to apply to a target backend

Thank you for making this module available. I am using it successfully to set the d armor policy. However, I can't figure out how to apply the policy to a specific target backend using terraform..

Seems like `preconfigured_waf_config` is causing rules to be recreated every time.

This must have occurred in an update as my Cloud Armor config has not changed a lot but now every Terraform apply is causing many rules that have not been changed to be deleted and recreated. When I look at the plan diff the only change I see is the preconfigured_waf_config property which is not set and not an option on these rules.

For example, even with the default rule I get the following in a Terraform apply. The only difference I can see is the rule being destroyed has an empty preconfigured_waf_config setting which isn't even an option when setting the default rule. But this applies to other types of rules as well I just choose the default as an example.

Rule being destroyed:

    - rule ***
        - action      = "allow" -> null
        - description = "Default rule, higher priority overrides it" -> null
        - preview     = false -> null
        - priority    = 2147483647 -> null

        - match ***
            - versioned_expr = "SRC_IPS_V1" -> null

            - config ***
                - src_ip_ranges = [
                    - "*",
                  ] -> null
              ***
          ***

        - preconfigured_waf_config ***
          ***
      ***

Replacement rule being created:

    + rule ***
        + action      = "allow"
        + description = "Default rule, higher priority overrides it"
        + preview     = (known after apply)
        + priority    = 2147483647

        + match ***
            + versioned_expr = "SRC_IPS_V1"

            + config ***
                + src_ip_ranges = [
                    + "*",
                  ]
              ***
          ***
      ***

Google Provider Version: 5.9.0

Does not update preconfigured_waf_config_exclusions when exclusions added

Hi,

WE have encountered a problem when updating/.modifying the preconfigured_waf_config_exclusions in our Cloud Armor configurations.

We have already deployed the new module updates as per new enhancement request raised by @Nathan01110011. Recently, We are facing an issue when updating Cloud armor exclusions configuration via IaC.

When we are trying to update ad rule_ids, request_query_param or request_cookie, Terraform does not identify the updates in the rules and when terraform perform tf plan, it says

No changes. Your infrastructure matches the configuration. Terraform has compared your real infrastructure against your configuration and found no differences, so no changes are needed.

This is a weird behaviour we have seen. it does show custom rules and other rules but anything gets modified within preconfigured_waf_config_exclusions doesnt get picked by tf plan.

Could anyone please share some thoughts here?

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.

Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

gomod
test/integration/go.mod
  • go 1.21
  • go 1.21.9
  • github.com/GoogleCloudPlatform/cloud-foundation-toolkit/infra/blueprint-test v0.14.0
  • github.com/stretchr/testify v1.9.0
regex
Makefile
  • cft/developer-tools 1.20
build/int.cloudbuild.yaml
  • cft/developer-tools 1.20
build/lint.cloudbuild.yaml
  • cft/developer-tools 1.20
terraform
examples/global-backend-security-policy-complete/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/global-backend-security-policy-complete/network.tf
  • terraform-google-modules/cloud-router/google ~> 6.0
  • terraform-google-modules/network/google ~> 9.0
  • terraform-google-modules/network/google ~> 9.0
examples/global-backend-security-policy-enterprise/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/global-backend-security-policy-example/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/global-backend-security-policy-recaptcha/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/global-edge-security-policy/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/regional-adv-ddos-and-edge-security-policy-complete/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/regional-adv-ddos-and-edge-security-policy-complete/network.tf
  • terraform-google-modules/cloud-router/google ~> 6.0
  • terraform-google-modules/network/google ~> 9.0
  • terraform-google-modules/network/google ~> 9.0
examples/regional-advanced-network-ddos-protection-enterprise/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
examples/regional-network-edge-security-policy-enterprise/main.tf
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
  • GoogleCloudPlatform/cloud-armor/google ~> 2.0
modules/advanced-network-ddos-protection/versions.tf
  • google >= 4.80, < 6
  • google-beta >= 4.80, < 6
  • hashicorp/terraform >= 1.3.0
modules/network-edge-security-policy/versions.tf
  • google >= 4.80, < 6
  • google-beta >= 4.80, < 6
  • hashicorp/terraform >= 1.3.0
test/setup/main.tf
  • terraform-google-modules/project-factory/google ~> 14.0
test/setup/versions.tf
  • google >= 3.49
  • google-beta >= 3.49
  • hashicorp/terraform >=0.13.0
versions.tf
  • google >= 4.79, < 6
  • google-beta >= 4.79, < 6
  • hashicorp/terraform >= 1.3.0

  • Check this box to trigger a request for Renovate to run again on this repository

The module doesn't support using TLS_JA3_FINGERPRINT in enforce on key

[NOT A CONTRIBUTION]

It seems the module doesn't support setting TLS_JA3_FINGERPRINT, while the documentation [1] and examples [2] show it's possible.

│ Error: expected rule.60.rate_limit_options.0.enforce_on_key to be one of ["ALL" "IP" "HTTP_HEADER" "XFF_IP" "HTTP_COOKIE" "HTTP_PATH" "SNI" "REGION_CODE" ""], got TLS_JA3_FINGERPRINT
│ Error: expected rule.60.rate_limit_options.0.enforce_on_key_configs.0.enforce_on_key_type to be one of ["ALL" "IP" "HTTP_HEADER" "XFF_IP" "HTTP_COOKIE" "HTTP_PATH" "SNI" "REGION_CODE"], got TLS_JA3_FINGERPRINT

Would it be possible to extend the module to support that as well? Thank you

[1] https://cloud.google.com/armor/docs/rate-limiting-overview#identifying_clients_for_rate_limiting
[2] https://cloud.google.com/armor/docs/configure-rate-limiting#ja3

unexpected EOF while creating google_compute_security_policy

I am trying to create google_compute_security_policy. But terraform apply is not successful with the below error.
google_compute_security_policy.policy: Creating...

│ Error: Error creating SecurityPolicy: unexpected EOF

│ with google_compute_security_policy.policy,
│ on main.tf line 47, in resource "google_compute_security_policy" "policy":
│ 47: resource "google_compute_security_policy" "policy" {

This is my configuration:-

####################--main.tf--##############################
locals {

find all the preconfigured rule with no include or exclude expression
pre_configured_rules_no_cond_expr = { for name, policy in var.pre_configured_rules : name => {
expression = "evaluatePreconfiguredWaf('${policy["target_rule_set"]}', {'sensitivity': ${policy["sensitivity_level"]}})"
} if length(policy["include_target_rule_ids"]) == 0 && length(policy["exclude_target_rule_ids"]) == 0
}

find all the preconfigured rule with include (Opt In rules) expression
pre_configured_rules_include = { for name, policy in var.pre_configured_rules : name => {
target_rule_set = policy.target_rule_set
include_target_rule_ids = replace(join(",", policy.include_target_rule_ids), ",", "','")
sensitivity_level = policy.sensitivity_level
action = policy.action
priority = 0
description = policy.description
preview = policy.preview
redirect_type = policy.redirect_type
rate_limit_options = policy.rate_limit_options
} if length(policy["include_target_rule_ids"]) > 0
}

pre_configured_rules_include_expr = { for name, policy in local.pre_configured_rules_include : name => {
expression = "evaluatePreconfiguredWaf('${policy["target_rule_set"]}', {'sensitivity': 0, 'opt_in_rule_ids': ['${policy.include_target_rule_ids}']})"
}
}

find all the preconfigured rule with Exclude (Opt out rules) expression
pre_configured_rules_exclude = { for name, policy in var.pre_configured_rules : name => {
target_rule_set = policy.target_rule_set
exclude_target_rule_ids = replace(join(",", policy.exclude_target_rule_ids), ",", "','")
sensitivity_level = policy.sensitivity_level
action = policy.action
priority = policy.priority
description = policy.description
preview = policy.preview
redirect_type = policy.redirect_type
rate_limit_options = policy.rate_limit_options
} if length(policy["include_target_rule_ids"]) == 0 && length(policy["exclude_target_rule_ids"]) > 0
}
pre_configured_rules_exclude_expr = { for name, policy in local.pre_configured_rules_exclude : name => {
expression = "evaluatePreconfiguredWaf('${policy["target_rule_set"]}', {'sensitivity':
{policy.exclude_target_rule_ids}']})"
}
}

Combine all the preconfigured rules
pre_configured_rules_expr = merge(local.pre_configured_rules_no_cond_expr, local.pre_configured_rules_include_expr, local.pre_configured_rules_exclude_expr)
}
resource "google_compute_security_policy" "policy" {
name = "my-policy"
project = "######"

dynamic "rule" {
for_each = var.security_rules
content {
action = rule.value["action"]
priority = rule.value["priority"]
preview = rule.value["preview"]
description = rule.value["description"]
match {
versioned_expr = "SRC_IPS_V1"
config {
src_ip_ranges = rule.value["src_ip_ranges"]
}
}

}
}

Preconfigured Rules Sensitivity level
dynamic "rule" {
for_each = var.pre_configured_rules
content {
action = rule.value["action"]
priority = rule.value["priority"]
preview = rule.value["preview"]
description = rule.value["description"]

match {
expr {
expression = local.pre_configured_rules_expr[rule.key].expression
}
}

Redirect option

dynamic "redirect_options" {
for_each = rule.value["action"] == "redirect" ? ["redirect"] : []
content {
type = rule.value["redirect_type"]
target = rule.value["redirect_type"] == "EXTERNAL_302" ? rule.value["redirect_target"] : null
}
}
}
}

}

###################----variables.tf-----###############################

rule 1 =
action: "allow" or "deny"
preview : boolean
priority : ""
source_ip_range: list
description : "text"
variable "rules" {
description = "list of values to assign to rules"
type = list(object({
action = string
preview = string
priority = number
versioned_expr = string
src_ip_ranges = list
expression = string
description = string
}))
}
variable "project" {
type = string
description = "Project name where policy is getting created"
default = ""
}

variable "name" {
type = string
description = "Name of the policy"
default = ""
}
variable "security_rules" {
description = "Map of Security rules with list of IP addresses to block or unblock"
type = map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
src_ip_ranges = list(string)
}))
default = {}
}
variable "pre_configured_rules" {
description = "Map of pre-configured rules Sensitivity levels"
type = map(object({
action = string
priority = number
description = optional(string)
preview = optional(bool, false)
redirect_type = optional(string, null)
redirect_target = optional(string, null)
target_rule_set = string
sensitivity_level = optional(number, 4)
include_target_rule_ids = optional(list(string), [])
exclude_target_rule_ids = optional(list(string), [])
rate_limit_options = optional(object({
enforce_on_key = optional(string)
exceed_action = optional(string)
rate_limit_http_request_count = optional(number)
rate_limit_http_request_interval_sec = optional(number)
ban_duration_sec = optional(number)
ban_http_request_count = optional(number)
ban_http_request_interval_sec = optional(number)
}),
{})
}))
default = {}
}
#########################---terraform.tfvars---###########################
project = ""
name = ""
pre_configured_rules = {

"php-stable_level_1_with_include" = {
action = "deny(502)"
priority = 3
description = "PHP Sensitivity Level 1 with included rules"
target_rule_set = "xss-v33-stable"
sensitivity_level = 0
include_target_rule_ids = ["owasp-crs-v030301-id933190-php", "owasp-crs-v030301-id933111-php"]
}

"rfi_sensitivity_level_4" = {
action = "redirect"
priority = 4
description = "Remote file inclusion 4"
preview = true
redirect_type = "GOOGLE_RECAPTCHA"
target_rule_set = "rfi-v33-stable"
sensitivity_level = 4
}
"sqli_sensitivity_level_4" = {
action = "deny(502)"
priority = 1
target_rule_set = "sqli-v33-stable"
}

"xss-stable_level_2_with_exclude" = {
action = "deny(502)"
priority = 2
description = "XSS Sensitivity Level 2 with excluded rules"
preview = true
target_rule_set = "xss-v33-stable"
sensitivity_level = 2
exclude_target_rule_ids = ["owasp-crs-v030301-id941380-xss", "owasp-crs-v030301-id941280-xss"]
}

"php-stable_level_0_with_include" = {
action = "deny(502)"
priority = 14
description = "PHP Sensitivity Level 0 with included rules"
target_rule_set = "php-v33-stable"
include_target_rule_ids = ["owasp-crs-v030301-id933190-php", "owasp-crs-v030301-id933111-php"]
}
}
security_rules = {
"default_rule" = {
action = "allow"
priority = 2147483647
description = "Default rule"
src_ip_ranges = ["*"]
}
"rule_deny_1" = {
action = "deny(502)"
priority = 10
description = "Deny Malicious IP address from project bad_actor"
src_ip_ranges = ["190.217.68.211", "45.116.227.68", "103.43.141.122", "123.11.215.36", ]
preview = false
}

"rule_allow_1" = {
action = "allow"
priority = 15
description = "Throttle IP addresses from project bad_actor4"
src_ip_ranges = ["190.217.68.214", "45.116.227.71", ]
preview = true
}

"rule_allow_2" = {
action = "allow"
priority = 100
description = "Throttle IP addresses from project bad_actor4"
src_ip_ranges = ["190.217.0.0/24", "45.116.0.0/24", ]
preview = true
}

"rule_allow_3" = {
action = "allow"
priority = 16
description = "Throttle IP addresses from project bad_actor4"
src_ip_ranges = ["190.215.68.214", "45.116.221.71", ]
preview = true
}

"rule_allow_4" = {
action = "allow"
priority = 101
description = "Throttle IP addresses from project bad_actor4"
src_ip_ranges = ["190.216.0.0/24", "45.116.1.0/24", ]
preview = true
}

}

update preconfig waf rules block to support path matches

This preconfig waf rule is being trigger whenever there's certain keywords in the URI. We have try the following to exclude the alert from being trigger using the preconfig waf exclusion parameter:

"methodenforcement-v33-stable_level_1" = {
      action            = "deny(403)"
      preview           = true
      priority          = 6
      description       = "Method enforcement Level 1"
      target_rule_set   = "methodenforcement-v33-stable"
      sensitivity_level = 1
      preconfigured_waf_config_exclusion = {
        target_rule_set = "methodenforcement-v33-stable"
        target_rule_ids = ["owasp-crs-v030301-id911100-methodenforcement"]
        request_uri = [
          {
            operator = "CONTAINS"
            value    = "/keyword/here/"
          },
        ]
      }

Whenever its not working and after talking to Google support rep, they suggest we try something like this

evaluatePreconfiguredWaf('methodenforcement-v33-stable', {'sensitivity': 1}) && !request.path.matches('/keyword/here/')

But from the current module, it doesnt look like we can pass in path matches etc?

Separation of request field exclusion and target IDs needed

I've encountered this issue during a deployment-

Error 400: Invalid value for field 'resource.preconfiguredWafConfig': '*** "exclusions": [*** "targetRuleSet": "sqli-v33-stable", "targetRuleIds": ["owasp-crs-v030301-i...'. The number of request query parameters to exclude for the target sqli-v33-stable:owasp-crs-v030301-id942220-sqli exceeds the limit of 10., invalid

Which is probably a fine limit if I was able to state specific target_rule_ids for each value I want, like below in the GCP console -
image

  • but as it stands it looks like I can only state a list of target_rule_ids and all the exclusions are applied to that list.

In-place update is not working while using enfore_on_key_configs

While adding new or changing below rule, my entire policy is getting recreated instead of in-place update. This is only happening while using enforce_on_key_configs.

throttle_501 = {
action = "throttle"
priority = 502
description = "test-description"
expression = <<-EOT
(request.path.startsWith('/test/')) && (has(request.headers['x-api-key']) && request.headers['x-api-key'] != "") && !(request.path.contains('/test/123/'))
EOT
rate_limit_options = {
exceed_action = "deny(429)"
rate_limit_http_request_count = 1000
rate_limit_http_request_interval_sec = 60
enforce_on_key = ""
enforce_on_key_configs = [
{
enforce_on_key_type = "HTTP_HEADER"
enforce_on_key_name = "x-api-key"
}
]
}
}

add preconfigured_waf_config_exclusion in custom_rules block

Add support for preconfigured_waf_config block in custom_rules variable. This will help in creating pre configured waf rule described in #65 which cannot be created using pre_configured_rules variable.

custom_rules = {

  "methodenforcement-v33-stable_level_1" = {
    action            = "deny(403)"
    priority          = 6
    description       = "Method enforcement Level 1"
    preview           = true
    expression        = "evaluatePreconfiguredWaf('methodenforcement-v33-stable', {'sensitivity': 1}) && !request.path.matches('/keyword/here/')"

    preconfigured_waf_config_exclusion = {
      target_rule_set = "methodenforcement-v33-stable"
      target_rule_ids = ["owasp-crs-v030301-id911100-methodenforcement"]
      request_uri = [
        {
          operator = "CONTAINS"
          value    = "/keyword/here/"
        },
      ]
    }
  }

}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.