├── .gitignore ├── LICENSE ├── README.md ├── example ├── global_waf │ ├── global_waf.tf │ ├── provider.tf │ ├── terraform.tfvars │ ├── vars.tf │ └── versions.tf └── regional_waf │ ├── provider.tf │ ├── regional_waf.tf │ ├── terraform.tfvars │ ├── vars.tf │ └── versions.tf ├── global ├── outputs.tf ├── vars.tf ├── waf_condition_ip.tf ├── waf_condition_size.tf ├── waf_condition_sql.tf ├── waf_condition_string_match.tf ├── waf_condition_xss.tf ├── waf_rule.tf └── waf_web_acl.tf └── regional ├── outputs.tf ├── vars.tf ├── versions.tf ├── waf_condition_ip.tf ├── waf_condition_size.tf ├── waf_condition_sql.tf ├── waf_condition_string_match.tf ├── waf_condition_xss.tf ├── waf_rule.tf └── waf_web_acl.tf /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | ### Terraform ### 4 | # Compiled files 5 | *.tfstate 6 | *.tfstate.backup 7 | .terraform 8 | *.zip 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2018 Takayuki Niinuma 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform-waf-owasp 2 | Use AWS WAF at terraform to Mitigate OWASP’s Top 10 Web Application Vulnerabilities 3 | 4 | * Global WAF for CloudFront usage 5 | * Regional WAF for Regional/ALB usage 6 | 7 | For more information: 8 | * AWS Blog - https://aws.amazon.com/about-aws/whats-new/2017/07/use-aws-waf-to-mitigate-owasps-top-10-web-application-vulnerabilities/ 9 | * AWS Whitepaper - https://d0.awsstatic.com/whitepapers/Security/aws-waf-owasp.pdf 10 | -------------------------------------------------------------------------------- /example/global_waf/global_waf.tf: -------------------------------------------------------------------------------- 1 | module "global_waf" { 2 | source = "../../global/." 3 | waf_prefix = var.waf_prefix 4 | blacklisted_ips = var.blacklisted_ips 5 | admin_remote_ipset = var.admin_remote_ipset 6 | } 7 | 8 | # Use module.global_waf.web_acl_id variable to attach it to aws_cloudfront_distribution 9 | # https://www.terraform.io/docs/providers/aws/r/cloudfront_distribution.html#web_acl_id 10 | -------------------------------------------------------------------------------- /example/global_waf/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | profile = var.profile 4 | } 5 | 6 | provider "template" { 7 | } 8 | 9 | -------------------------------------------------------------------------------- /example/global_waf/terraform.tfvars: -------------------------------------------------------------------------------- 1 | region = "ap-northeast-1" 2 | 3 | profile = "dev" 4 | 5 | waf_prefix = "managed" 6 | 7 | blacklisted_ips = [ 8 | { 9 | value = "172.16.0.0/16" 10 | type = "IPV4" 11 | }, 12 | { 13 | value = "192.168.0.0/16" 14 | type = "IPV4" 15 | }, 16 | { 17 | value = "169.254.0.0/16" 18 | type = "IPV4" 19 | }, 20 | { 21 | value = "127.0.0.1/32" 22 | type = "IPV4" 23 | }, 24 | { 25 | value = "10.0.0.0/8" 26 | type = "IPV4" 27 | }, 28 | ] 29 | 30 | admin_remote_ipset = [ 31 | { 32 | value = "127.0.0.1/32" 33 | type = "IPV4" 34 | }, 35 | ] 36 | -------------------------------------------------------------------------------- /example/global_waf/vars.tf: -------------------------------------------------------------------------------- 1 | variable "region" {} 2 | 3 | variable "profile" {} 4 | 5 | variable "waf_prefix" {} 6 | 7 | variable "blacklisted_ips" {} 8 | 9 | variable "admin_remote_ipset" {} 10 | -------------------------------------------------------------------------------- /example/global_waf/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /example/regional_waf/provider.tf: -------------------------------------------------------------------------------- 1 | provider "aws" { 2 | region = var.region 3 | profile = var.profile 4 | } 5 | 6 | provider "template" { 7 | } 8 | 9 | -------------------------------------------------------------------------------- /example/regional_waf/regional_waf.tf: -------------------------------------------------------------------------------- 1 | module "regional_waf" { 2 | source = "../../regional/." 3 | waf_prefix = var.waf_prefix 4 | blacklisted_ips = var.blacklisted_ips 5 | admin_remote_ipset = var.admin_remote_ipset 6 | } 7 | 8 | # Use module.regional_waf.web_acl_id variable to create aws_wafregional_web_acl_association 9 | # https://www.terraform.io/docs/providers/aws/r/wafregional_web_acl_association.html 10 | -------------------------------------------------------------------------------- /example/regional_waf/terraform.tfvars: -------------------------------------------------------------------------------- 1 | region = "ap-northeast-1" 2 | 3 | profile = "dev" 4 | 5 | waf_prefix = "managed" 6 | 7 | blacklisted_ips = [ 8 | { 9 | value = "172.16.0.0/16" 10 | type = "IPV4" 11 | }, 12 | { 13 | value = "192.168.0.0/16" 14 | type = "IPV4" 15 | }, 16 | { 17 | value = "169.254.0.0/16" 18 | type = "IPV4" 19 | }, 20 | { 21 | value = "127.0.0.1/32" 22 | type = "IPV4" 23 | }, 24 | { 25 | value = "10.0.0.0/8" 26 | type = "IPV4" 27 | }, 28 | ] 29 | 30 | admin_remote_ipset = [ 31 | { 32 | value = "127.0.0.1/32" 33 | type = "IPV4" 34 | }, 35 | ] 36 | -------------------------------------------------------------------------------- /example/regional_waf/vars.tf: -------------------------------------------------------------------------------- 1 | variable "region" {} 2 | 3 | variable "profile" {} 4 | 5 | variable "waf_prefix" {} 6 | 7 | variable "blacklisted_ips" {} 8 | 9 | variable "admin_remote_ipset" {} 10 | -------------------------------------------------------------------------------- /example/regional_waf/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /global/outputs.tf: -------------------------------------------------------------------------------- 1 | output "web_acl_id" { 2 | value = aws_waf_web_acl.waf_acl.id 3 | } 4 | 5 | -------------------------------------------------------------------------------- /global/vars.tf: -------------------------------------------------------------------------------- 1 | variable "waf_prefix" { 2 | type = list(string) 3 | } 4 | 5 | variable "blacklisted_ips" { 6 | type = "list" 7 | } 8 | 9 | variable "admin_remote_ipset" { 10 | type = "list" 11 | } 12 | 13 | -------------------------------------------------------------------------------- /global/waf_condition_ip.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_ipset" "admin_remote_ipset" { 2 | name = "${var.waf_prefix}-generic-match-admin-remote-ip" 3 | dynamic "ip_set_descriptors" { 4 | for_each = [for ip_set in var.admin_remote_ipset : { 5 | type = ip_set.type 6 | value = ip_set.value 7 | }] 8 | content { 9 | type = ip_set_descriptors.value.type 10 | value = ip_set_descriptors.value.value 11 | } 12 | } 13 | } 14 | 15 | resource "aws_waf_ipset" "blacklisted_ips" { 16 | name = "${var.waf_prefix}-generic-match-blacklisted-ips" 17 | dynamic "ip_set_descriptors" { 18 | for_each = [for ip_set in var.blacklisted_ips : { 19 | value = ip_set.value 20 | type = ip_set.type 21 | }] 22 | content { 23 | type = ip_set_descriptors.value.type 24 | value = ip_set_descriptors.value.value 25 | } 26 | } 27 | } 28 | 29 | -------------------------------------------------------------------------------- /global/waf_condition_size.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_size_constraint_set" "size_restrictions" { 2 | name = "${var.waf_prefix}-generic-size-restrictions" 3 | 4 | size_constraints { 5 | text_transformation = "NONE" 6 | comparison_operator = "GT" 7 | size = "4096" 8 | 9 | field_to_match { 10 | type = "BODY" 11 | } 12 | } 13 | 14 | size_constraints { 15 | text_transformation = "NONE" 16 | comparison_operator = "GT" 17 | size = "4093" 18 | 19 | field_to_match { 20 | type = "HEADER" 21 | data = "cookie" 22 | } 23 | } 24 | 25 | size_constraints { 26 | text_transformation = "NONE" 27 | comparison_operator = "GT" 28 | size = "1024" 29 | 30 | field_to_match { 31 | type = "QUERY_STRING" 32 | } 33 | } 34 | 35 | size_constraints { 36 | text_transformation = "NONE" 37 | comparison_operator = "GT" 38 | size = "512" 39 | 40 | field_to_match { 41 | type = "URI" 42 | } 43 | } 44 | } 45 | 46 | resource "aws_waf_size_constraint_set" "csrf_token_set" { 47 | name = "${var.waf_prefix}-generic-match-csrf-token" 48 | 49 | size_constraints { 50 | text_transformation = "NONE" 51 | comparison_operator = "EQ" 52 | size = "36" 53 | 54 | field_to_match { 55 | type = "HEADER" 56 | data = "x-csrf-token" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /global/waf_condition_sql.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_sql_injection_match_set" "sql_injection_match_set" { 2 | name = "${var.waf_prefix}-generic-detect-sqli" 3 | 4 | sql_injection_match_tuples { 5 | text_transformation = "HTML_ENTITY_DECODE" 6 | 7 | field_to_match { 8 | type = "BODY" 9 | } 10 | } 11 | 12 | sql_injection_match_tuples { 13 | text_transformation = "URL_DECODE" 14 | 15 | field_to_match { 16 | type = "BODY" 17 | } 18 | } 19 | 20 | sql_injection_match_tuples { 21 | text_transformation = "HTML_ENTITY_DECODE" 22 | 23 | field_to_match { 24 | type = "URI" 25 | } 26 | } 27 | 28 | sql_injection_match_tuples { 29 | text_transformation = "URL_DECODE" 30 | 31 | field_to_match { 32 | type = "URI" 33 | } 34 | } 35 | 36 | sql_injection_match_tuples { 37 | text_transformation = "HTML_ENTITY_DECODE" 38 | 39 | field_to_match { 40 | type = "QUERY_STRING" 41 | } 42 | } 43 | 44 | sql_injection_match_tuples { 45 | text_transformation = "URL_DECODE" 46 | 47 | field_to_match { 48 | type = "QUERY_STRING" 49 | } 50 | } 51 | 52 | sql_injection_match_tuples { 53 | text_transformation = "HTML_ENTITY_DECODE" 54 | 55 | field_to_match { 56 | type = "HEADER" 57 | data = "cookie" 58 | } 59 | } 60 | 61 | sql_injection_match_tuples { 62 | text_transformation = "URL_DECODE" 63 | 64 | field_to_match { 65 | type = "HEADER" 66 | data = "cookie" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /global/waf_condition_string_match.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_byte_match_set" "match_admin_url" { 2 | name = "${var.waf_prefix}-generic-match-admin-url" 3 | 4 | byte_match_tuples { 5 | text_transformation = "URL_DECODE" 6 | target_string = "/admin" 7 | positional_constraint = "STARTS_WITH" 8 | 9 | field_to_match { 10 | type = "URI" 11 | } 12 | } 13 | } 14 | 15 | resource "aws_waf_byte_match_set" "match_auth_tokens" { 16 | name = "${var.waf_prefix}-generic-match-auth-tokens" 17 | 18 | byte_match_tuples { 19 | text_transformation = "URL_DECODE" 20 | target_string = ".TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" 21 | positional_constraint = "ENDS_WITH" 22 | 23 | field_to_match { 24 | type = "HEADER" 25 | data = "authorization" 26 | } 27 | } 28 | 29 | byte_match_tuples { 30 | text_transformation = "URL_DECODE" 31 | target_string = "example-session-id" 32 | positional_constraint = "CONTAINS" 33 | 34 | field_to_match { 35 | type = "HEADER" 36 | data = "cookie" 37 | } 38 | } 39 | } 40 | 41 | resource "aws_waf_byte_match_set" "match_csrf_method" { 42 | name = "${var.waf_prefix}-generic-match-csrf-method" 43 | 44 | byte_match_tuples { 45 | text_transformation = "LOWERCASE" 46 | target_string = "post" 47 | positional_constraint = "EXACTLY" 48 | 49 | field_to_match { 50 | type = "METHOD" 51 | } 52 | } 53 | } 54 | 55 | resource "aws_waf_byte_match_set" "match_php_insecure_uri" { 56 | name = "${var.waf_prefix}-generic-match-php-insecure-uri" 57 | 58 | byte_match_tuples { 59 | text_transformation = "URL_DECODE" 60 | target_string = "php" 61 | positional_constraint = "ENDS_WITH" 62 | 63 | field_to_match { 64 | type = "URI" 65 | } 66 | } 67 | 68 | byte_match_tuples { 69 | text_transformation = "URL_DECODE" 70 | target_string = "/" 71 | positional_constraint = "ENDS_WITH" 72 | 73 | field_to_match { 74 | type = "URI" 75 | } 76 | } 77 | } 78 | 79 | resource "aws_waf_byte_match_set" "match_php_insecure_var_refs" { 80 | name = "${var.waf_prefix}-generic-match-php-insecure-var-refs" 81 | 82 | byte_match_tuples { 83 | text_transformation = "URL_DECODE" 84 | target_string = "_ENV[" 85 | positional_constraint = "CONTAINS" 86 | 87 | field_to_match { 88 | type = "QUERY_STRING" 89 | } 90 | } 91 | 92 | byte_match_tuples { 93 | text_transformation = "URL_DECODE" 94 | target_string = "auto_append_file=" 95 | positional_constraint = "CONTAINS" 96 | 97 | field_to_match { 98 | type = "QUERY_STRING" 99 | } 100 | } 101 | 102 | byte_match_tuples { 103 | text_transformation = "URL_DECODE" 104 | target_string = "disable_functions=" 105 | positional_constraint = "CONTAINS" 106 | 107 | field_to_match { 108 | type = "QUERY_STRING" 109 | } 110 | } 111 | 112 | byte_match_tuples { 113 | text_transformation = "URL_DECODE" 114 | target_string = "auto_prepend_file=" 115 | positional_constraint = "CONTAINS" 116 | 117 | field_to_match { 118 | type = "QUERY_STRING" 119 | } 120 | } 121 | 122 | byte_match_tuples { 123 | text_transformation = "URL_DECODE" 124 | target_string = "safe_mode=" 125 | positional_constraint = "CONTAINS" 126 | 127 | field_to_match { 128 | type = "QUERY_STRING" 129 | } 130 | } 131 | 132 | byte_match_tuples { 133 | text_transformation = "URL_DECODE" 134 | target_string = "_SERVER[" 135 | positional_constraint = "CONTAINS" 136 | 137 | field_to_match { 138 | type = "QUERY_STRING" 139 | } 140 | } 141 | 142 | byte_match_tuples { 143 | text_transformation = "URL_DECODE" 144 | target_string = "allow_url_include=" 145 | positional_constraint = "CONTAINS" 146 | 147 | field_to_match { 148 | type = "QUERY_STRING" 149 | } 150 | } 151 | 152 | byte_match_tuples { 153 | text_transformation = "URL_DECODE" 154 | target_string = "open_basedir=" 155 | positional_constraint = "CONTAINS" 156 | 157 | field_to_match { 158 | type = "QUERY_STRING" 159 | } 160 | } 161 | } 162 | 163 | resource "aws_waf_byte_match_set" "match_rfi_lfi_traversal" { 164 | name = "${var.waf_prefix}-generic-match-rfi-lfi-traversal" 165 | 166 | byte_match_tuples { 167 | text_transformation = "HTML_ENTITY_DECODE" 168 | target_string = "://" 169 | positional_constraint = "CONTAINS" 170 | 171 | field_to_match { 172 | type = "QUERY_STRING" 173 | } 174 | } 175 | 176 | byte_match_tuples { 177 | text_transformation = "HTML_ENTITY_DECODE" 178 | target_string = "../" 179 | positional_constraint = "CONTAINS" 180 | 181 | field_to_match { 182 | type = "QUERY_STRING" 183 | } 184 | } 185 | 186 | byte_match_tuples { 187 | text_transformation = "URL_DECODE" 188 | target_string = "://" 189 | positional_constraint = "CONTAINS" 190 | 191 | field_to_match { 192 | type = "QUERY_STRING" 193 | } 194 | } 195 | 196 | byte_match_tuples { 197 | text_transformation = "URL_DECODE" 198 | target_string = "../" 199 | positional_constraint = "CONTAINS" 200 | 201 | field_to_match { 202 | type = "QUERY_STRING" 203 | } 204 | } 205 | 206 | byte_match_tuples { 207 | text_transformation = "HTML_ENTITY_DECODE" 208 | target_string = "://" 209 | positional_constraint = "CONTAINS" 210 | 211 | field_to_match { 212 | type = "URI" 213 | } 214 | } 215 | 216 | byte_match_tuples { 217 | text_transformation = "HTML_ENTITY_DECODE" 218 | target_string = "../" 219 | positional_constraint = "CONTAINS" 220 | 221 | field_to_match { 222 | type = "URI" 223 | } 224 | } 225 | 226 | byte_match_tuples { 227 | text_transformation = "URL_DECODE" 228 | target_string = "://" 229 | positional_constraint = "CONTAINS" 230 | 231 | field_to_match { 232 | type = "URI" 233 | } 234 | } 235 | 236 | byte_match_tuples { 237 | text_transformation = "URL_DECODE" 238 | target_string = "../" 239 | positional_constraint = "CONTAINS" 240 | 241 | field_to_match { 242 | type = "URI" 243 | } 244 | } 245 | } 246 | 247 | resource "aws_waf_byte_match_set" "match_ssi" { 248 | name = "${var.waf_prefix}-generic-match-ssi" 249 | 250 | byte_match_tuples { 251 | text_transformation = "LOWERCASE" 252 | target_string = ".cfg" 253 | positional_constraint = "ENDS_WITH" 254 | 255 | field_to_match { 256 | type = "URI" 257 | } 258 | } 259 | 260 | byte_match_tuples { 261 | text_transformation = "LOWERCASE" 262 | target_string = ".backup" 263 | positional_constraint = "ENDS_WITH" 264 | 265 | field_to_match { 266 | type = "URI" 267 | } 268 | } 269 | 270 | byte_match_tuples { 271 | text_transformation = "LOWERCASE" 272 | target_string = ".ini" 273 | positional_constraint = "ENDS_WITH" 274 | 275 | field_to_match { 276 | type = "URI" 277 | } 278 | } 279 | 280 | byte_match_tuples { 281 | text_transformation = "LOWERCASE" 282 | target_string = ".conf" 283 | positional_constraint = "ENDS_WITH" 284 | 285 | field_to_match { 286 | type = "URI" 287 | } 288 | } 289 | 290 | byte_match_tuples { 291 | text_transformation = "LOWERCASE" 292 | target_string = ".log" 293 | positional_constraint = "ENDS_WITH" 294 | 295 | field_to_match { 296 | type = "URI" 297 | } 298 | } 299 | 300 | byte_match_tuples { 301 | text_transformation = "LOWERCASE" 302 | target_string = ".bak" 303 | positional_constraint = "ENDS_WITH" 304 | 305 | field_to_match { 306 | type = "URI" 307 | } 308 | } 309 | 310 | byte_match_tuples { 311 | text_transformation = "LOWERCASE" 312 | target_string = ".config" 313 | positional_constraint = "ENDS_WITH" 314 | 315 | field_to_match { 316 | type = "URI" 317 | } 318 | } 319 | 320 | byte_match_tuples { 321 | text_transformation = "URL_DECODE" 322 | target_string = "/includes" 323 | positional_constraint = "STARTS_WITH" 324 | 325 | field_to_match { 326 | type = "URI" 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /global/waf_condition_xss.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_xss_match_set" "xss_match_set" { 2 | name = "${var.waf_prefix}-generic-detect-xss" 3 | 4 | xss_match_tuples { 5 | text_transformation = "HTML_ENTITY_DECODE" 6 | 7 | field_to_match { 8 | type = "BODY" 9 | } 10 | } 11 | 12 | xss_match_tuples { 13 | text_transformation = "URL_DECODE" 14 | 15 | field_to_match { 16 | type = "BODY" 17 | } 18 | } 19 | 20 | xss_match_tuples { 21 | text_transformation = "HTML_ENTITY_DECODE" 22 | 23 | field_to_match { 24 | type = "URI" 25 | } 26 | } 27 | 28 | xss_match_tuples { 29 | text_transformation = "URL_DECODE" 30 | 31 | field_to_match { 32 | type = "URI" 33 | } 34 | } 35 | 36 | xss_match_tuples { 37 | text_transformation = "HTML_ENTITY_DECODE" 38 | 39 | field_to_match { 40 | type = "QUERY_STRING" 41 | } 42 | } 43 | 44 | xss_match_tuples { 45 | text_transformation = "URL_DECODE" 46 | 47 | field_to_match { 48 | type = "QUERY_STRING" 49 | } 50 | } 51 | 52 | xss_match_tuples { 53 | text_transformation = "HTML_ENTITY_DECODE" 54 | 55 | field_to_match { 56 | type = "HEADER" 57 | data = "cookie" 58 | } 59 | } 60 | 61 | xss_match_tuples { 62 | text_transformation = "URL_DECODE" 63 | 64 | field_to_match { 65 | type = "HEADER" 66 | data = "cookie" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /global/waf_rule.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_rule" "detect_admin_access" { 2 | name = "${var.waf_prefix}-generic-detect-admin-access" 3 | metric_name = "${var.waf_prefix}genericdetectadminaccess" 4 | 5 | predicates { 6 | data_id = aws_waf_ipset.admin_remote_ipset.id 7 | negated = true 8 | type = "IPMatch" 9 | } 10 | 11 | predicates { 12 | data_id = aws_waf_byte_match_set.match_admin_url.id 13 | negated = false 14 | type = "ByteMatch" 15 | } 16 | } 17 | 18 | resource "aws_waf_rule" "detect_bad_auth_tokens" { 19 | name = "${var.waf_prefix}-generic-detect-bad-auth-tokens" 20 | metric_name = "${var.waf_prefix}genericdetectbadauthtokens" 21 | 22 | predicates { 23 | data_id = aws_waf_byte_match_set.match_auth_tokens.id 24 | negated = false 25 | type = "ByteMatch" 26 | } 27 | } 28 | 29 | resource "aws_waf_rule" "detect_blacklisted_ips" { 30 | name = "${var.waf_prefix}-generic-detect-blacklisted-ips" 31 | metric_name = "${var.waf_prefix}genericdetectblacklistedips" 32 | 33 | predicates { 34 | data_id = aws_waf_ipset.blacklisted_ips.id 35 | negated = false 36 | type = "IPMatch" 37 | } 38 | } 39 | 40 | resource "aws_waf_rule" "detect_php_insecure" { 41 | name = "${var.waf_prefix}-generic-detect-php-insecure" 42 | metric_name = "${var.waf_prefix}genericdetectphpinsecure" 43 | 44 | predicates { 45 | data_id = aws_waf_byte_match_set.match_php_insecure_uri.id 46 | negated = false 47 | type = "ByteMatch" 48 | } 49 | 50 | predicates { 51 | data_id = aws_waf_byte_match_set.match_php_insecure_var_refs.id 52 | negated = false 53 | type = "ByteMatch" 54 | } 55 | } 56 | 57 | resource "aws_waf_rule" "detect_rfi_lfi_traversal" { 58 | name = "${var.waf_prefix}-generic-detect-rfi-lfi-traversal" 59 | metric_name = "${var.waf_prefix}genericdetectrfilfitraversal" 60 | 61 | predicates { 62 | data_id = aws_waf_byte_match_set.match_rfi_lfi_traversal.id 63 | negated = false 64 | type = "ByteMatch" 65 | } 66 | } 67 | 68 | resource "aws_waf_rule" "detect_ssi" { 69 | name = "${var.waf_prefix}-generic-detect-ssi" 70 | metric_name = "${var.waf_prefix}genericdetectssi" 71 | 72 | predicates { 73 | data_id = aws_waf_byte_match_set.match_ssi.id 74 | negated = false 75 | type = "ByteMatch" 76 | } 77 | } 78 | 79 | resource "aws_waf_rule" "enforce_csrf" { 80 | name = "${var.waf_prefix}-generic-enforce-csrf" 81 | metric_name = "${var.waf_prefix}genericenforcecsrf" 82 | 83 | predicates { 84 | data_id = aws_waf_byte_match_set.match_csrf_method.id 85 | negated = false 86 | type = "ByteMatch" 87 | } 88 | 89 | predicates { 90 | data_id = aws_waf_size_constraint_set.csrf_token_set.id 91 | negated = true 92 | type = "SizeConstraint" 93 | } 94 | } 95 | 96 | resource "aws_waf_rule" "mitigate_sqli" { 97 | name = "${var.waf_prefix}-generic-mitigate-sqli" 98 | metric_name = "${var.waf_prefix}genericmitigatesqli" 99 | 100 | predicates { 101 | data_id = aws_waf_sql_injection_match_set.sql_injection_match_set.id 102 | negated = false 103 | type = "SqlInjectionMatch" 104 | } 105 | } 106 | 107 | resource "aws_waf_rule" "mitigate_xss" { 108 | name = "${var.waf_prefix}-generic-mitigate-xss" 109 | metric_name = "${var.waf_prefix}genericmitigatexss" 110 | 111 | predicates { 112 | data_id = aws_waf_xss_match_set.xss_match_set.id 113 | negated = false 114 | type = "XssMatch" 115 | } 116 | } 117 | 118 | resource "aws_waf_rule" "restrict_sizes" { 119 | name = "${var.waf_prefix}-generic-restrict-sizes" 120 | metric_name = "${var.waf_prefix}genericrestrictsizes" 121 | 122 | predicates { 123 | data_id = aws_waf_size_constraint_set.size_restrictions.id 124 | negated = false 125 | type = "SizeConstraint" 126 | } 127 | } 128 | 129 | -------------------------------------------------------------------------------- /global/waf_web_acl.tf: -------------------------------------------------------------------------------- 1 | resource "aws_waf_web_acl" "waf_acl" { 2 | name = "${var.waf_prefix}-generic-owasp-acl" 3 | metric_name = "${var.waf_prefix}genericowaspacl" 4 | 5 | default_action { 6 | type = "ALLOW" 7 | } 8 | 9 | rules { 10 | action { 11 | type = "BLOCK" 12 | } 13 | 14 | priority = 1 15 | rule_id = aws_waf_rule.restrict_sizes.id 16 | type = "REGULAR" 17 | } 18 | 19 | rules { 20 | action { 21 | type = "BLOCK" 22 | } 23 | 24 | priority = 2 25 | rule_id = aws_waf_rule.detect_blacklisted_ips.id 26 | type = "REGULAR" 27 | } 28 | 29 | rules { 30 | action { 31 | type = "BLOCK" 32 | } 33 | 34 | priority = 3 35 | rule_id = aws_waf_rule.detect_bad_auth_tokens.id 36 | type = "REGULAR" 37 | } 38 | 39 | rules { 40 | action { 41 | type = "BLOCK" 42 | } 43 | 44 | priority = 4 45 | rule_id = aws_waf_rule.mitigate_sqli.id 46 | type = "REGULAR" 47 | } 48 | 49 | rules { 50 | action { 51 | type = "BLOCK" 52 | } 53 | 54 | priority = 5 55 | rule_id = aws_waf_rule.mitigate_xss.id 56 | type = "REGULAR" 57 | } 58 | 59 | rules { 60 | action { 61 | type = "BLOCK" 62 | } 63 | 64 | priority = 6 65 | rule_id = aws_waf_rule.detect_rfi_lfi_traversal.id 66 | type = "REGULAR" 67 | } 68 | 69 | rules { 70 | action { 71 | type = "BLOCK" 72 | } 73 | 74 | priority = 7 75 | rule_id = aws_waf_rule.detect_php_insecure.id 76 | type = "REGULAR" 77 | } 78 | 79 | rules { 80 | action { 81 | type = "BLOCK" 82 | } 83 | 84 | priority = 8 85 | rule_id = aws_waf_rule.enforce_csrf.id 86 | type = "REGULAR" 87 | } 88 | 89 | rules { 90 | action { 91 | type = "BLOCK" 92 | } 93 | 94 | priority = 9 95 | rule_id = aws_waf_rule.detect_ssi.id 96 | type = "REGULAR" 97 | } 98 | 99 | rules { 100 | action { 101 | type = "BLOCK" 102 | } 103 | 104 | priority = 10 105 | rule_id = aws_waf_rule.detect_admin_access.id 106 | type = "REGULAR" 107 | } 108 | } 109 | 110 | -------------------------------------------------------------------------------- /regional/outputs.tf: -------------------------------------------------------------------------------- 1 | output "web_acl_id" { 2 | value = aws_wafregional_web_acl.wafregional_acl.id 3 | } 4 | 5 | -------------------------------------------------------------------------------- /regional/vars.tf: -------------------------------------------------------------------------------- 1 | variable "waf_prefix" {} 2 | 3 | variable "blacklisted_ips" { 4 | type = "list" 5 | } 6 | 7 | variable "admin_remote_ipset" { 8 | type = "list" 9 | } 10 | -------------------------------------------------------------------------------- /regional/versions.tf: -------------------------------------------------------------------------------- 1 | 2 | terraform { 3 | required_version = ">= 0.12" 4 | } 5 | -------------------------------------------------------------------------------- /regional/waf_condition_ip.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_ipset" "admin_remote_ipset" { 2 | name = "${var.waf_prefix}-generic-match-admin-remote-ip" 3 | 4 | dynamic "ip_set_descriptor" { 5 | for_each = [for ip_set in var.admin_remote_ipset : { 6 | type = ip_set.type 7 | value = ip_set.value 8 | }] 9 | content { 10 | type = ip_set_descriptor.value.type 11 | value = ip_set_descriptor.value.value 12 | } 13 | } 14 | } 15 | 16 | resource "aws_wafregional_ipset" "blacklisted_ips" { 17 | name = "${var.waf_prefix}-generic-match-blacklisted-ips" 18 | dynamic "ip_set_descriptor" { 19 | for_each = [for ip_set in var.blacklisted_ips : { 20 | type = ip_set.type 21 | value = ip_set.value 22 | }] 23 | content { 24 | type = ip_set_descriptor.value.type 25 | value = ip_set_descriptor.value.value 26 | } 27 | } 28 | } 29 | 30 | -------------------------------------------------------------------------------- /regional/waf_condition_size.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_size_constraint_set" "size_restrictions" { 2 | name = "${var.waf_prefix}-generic-size-restrictions" 3 | 4 | size_constraints { 5 | text_transformation = "NONE" 6 | comparison_operator = "GT" 7 | size = "4096" 8 | 9 | field_to_match { 10 | type = "BODY" 11 | } 12 | } 13 | 14 | size_constraints { 15 | text_transformation = "NONE" 16 | comparison_operator = "GT" 17 | size = "4093" 18 | 19 | field_to_match { 20 | type = "HEADER" 21 | data = "cookie" 22 | } 23 | } 24 | 25 | size_constraints { 26 | text_transformation = "NONE" 27 | comparison_operator = "GT" 28 | size = "1024" 29 | 30 | field_to_match { 31 | type = "QUERY_STRING" 32 | } 33 | } 34 | 35 | size_constraints { 36 | text_transformation = "NONE" 37 | comparison_operator = "GT" 38 | size = "512" 39 | 40 | field_to_match { 41 | type = "URI" 42 | } 43 | } 44 | } 45 | 46 | resource "aws_wafregional_size_constraint_set" "csrf_token_set" { 47 | name = "${var.waf_prefix}-generic-match-csrf-token" 48 | 49 | size_constraints { 50 | text_transformation = "NONE" 51 | comparison_operator = "EQ" 52 | size = "36" 53 | 54 | field_to_match { 55 | type = "HEADER" 56 | data = "x-csrf-token" 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /regional/waf_condition_sql.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_sql_injection_match_set" "sql_injection_match_set" { 2 | name = "${var.waf_prefix}-generic-detect-sqli" 3 | 4 | sql_injection_match_tuple { 5 | text_transformation = "HTML_ENTITY_DECODE" 6 | 7 | field_to_match { 8 | type = "BODY" 9 | } 10 | } 11 | 12 | sql_injection_match_tuple { 13 | text_transformation = "URL_DECODE" 14 | 15 | field_to_match { 16 | type = "BODY" 17 | } 18 | } 19 | 20 | sql_injection_match_tuple { 21 | text_transformation = "HTML_ENTITY_DECODE" 22 | 23 | field_to_match { 24 | type = "URI" 25 | } 26 | } 27 | 28 | sql_injection_match_tuple { 29 | text_transformation = "URL_DECODE" 30 | 31 | field_to_match { 32 | type = "URI" 33 | } 34 | } 35 | 36 | sql_injection_match_tuple { 37 | text_transformation = "HTML_ENTITY_DECODE" 38 | 39 | field_to_match { 40 | type = "QUERY_STRING" 41 | } 42 | } 43 | 44 | sql_injection_match_tuple { 45 | text_transformation = "URL_DECODE" 46 | 47 | field_to_match { 48 | type = "QUERY_STRING" 49 | } 50 | } 51 | 52 | sql_injection_match_tuple { 53 | text_transformation = "HTML_ENTITY_DECODE" 54 | 55 | field_to_match { 56 | type = "HEADER" 57 | data = "cookie" 58 | } 59 | } 60 | 61 | sql_injection_match_tuple { 62 | text_transformation = "URL_DECODE" 63 | 64 | field_to_match { 65 | type = "HEADER" 66 | data = "cookie" 67 | } 68 | } 69 | 70 | sql_injection_match_tuple { 71 | text_transformation = "HTML_ENTITY_DECODE" 72 | 73 | field_to_match { 74 | data = "authorization" 75 | type = "HEADER" 76 | } 77 | } 78 | 79 | sql_injection_match_tuple { 80 | text_transformation = "URL_DECODE" 81 | 82 | field_to_match { 83 | data = "authorization" 84 | type = "HEADER" 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /regional/waf_condition_string_match.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_byte_match_set" "match_admin_url" { 2 | name = "${var.waf_prefix}-generic-match-admin-url" 3 | 4 | byte_match_tuples { 5 | text_transformation = "URL_DECODE" 6 | target_string = "/admin" 7 | positional_constraint = "STARTS_WITH" 8 | 9 | field_to_match { 10 | type = "URI" 11 | } 12 | } 13 | } 14 | 15 | resource "aws_wafregional_byte_match_set" "match_auth_tokens" { 16 | name = "${var.waf_prefix}-generic-match-auth-tokens" 17 | 18 | byte_match_tuples { 19 | text_transformation = "URL_DECODE" 20 | target_string = ".TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ" 21 | positional_constraint = "ENDS_WITH" 22 | 23 | field_to_match { 24 | type = "HEADER" 25 | data = "authorization" 26 | } 27 | } 28 | 29 | byte_match_tuples { 30 | text_transformation = "URL_DECODE" 31 | target_string = "example-session-id" 32 | positional_constraint = "CONTAINS" 33 | 34 | field_to_match { 35 | type = "HEADER" 36 | data = "cookie" 37 | } 38 | } 39 | } 40 | 41 | resource "aws_wafregional_byte_match_set" "match_csrf_method" { 42 | name = "${var.waf_prefix}-generic-match-csrf-method" 43 | 44 | byte_match_tuples { 45 | text_transformation = "LOWERCASE" 46 | target_string = "post" 47 | positional_constraint = "EXACTLY" 48 | 49 | field_to_match { 50 | type = "METHOD" 51 | } 52 | } 53 | } 54 | 55 | resource "aws_wafregional_byte_match_set" "match_php_insecure_uri" { 56 | name = "${var.waf_prefix}-generic-match-php-insecure-uri" 57 | 58 | byte_match_tuples { 59 | text_transformation = "URL_DECODE" 60 | target_string = "php" 61 | positional_constraint = "ENDS_WITH" 62 | 63 | field_to_match { 64 | type = "URI" 65 | } 66 | } 67 | 68 | byte_match_tuples { 69 | text_transformation = "URL_DECODE" 70 | target_string = "/" 71 | positional_constraint = "ENDS_WITH" 72 | 73 | field_to_match { 74 | type = "URI" 75 | } 76 | } 77 | } 78 | 79 | resource "aws_wafregional_byte_match_set" "match_php_insecure_var_refs" { 80 | name = "${var.waf_prefix}-generic-match-php-insecure-var-refs" 81 | 82 | byte_match_tuples { 83 | text_transformation = "URL_DECODE" 84 | target_string = "_ENV[" 85 | positional_constraint = "CONTAINS" 86 | 87 | field_to_match { 88 | type = "QUERY_STRING" 89 | } 90 | } 91 | 92 | byte_match_tuples { 93 | text_transformation = "URL_DECODE" 94 | target_string = "auto_append_file=" 95 | positional_constraint = "CONTAINS" 96 | 97 | field_to_match { 98 | type = "QUERY_STRING" 99 | } 100 | } 101 | 102 | byte_match_tuples { 103 | text_transformation = "URL_DECODE" 104 | target_string = "disable_functions=" 105 | positional_constraint = "CONTAINS" 106 | 107 | field_to_match { 108 | type = "QUERY_STRING" 109 | } 110 | } 111 | 112 | byte_match_tuples { 113 | text_transformation = "URL_DECODE" 114 | target_string = "auto_prepend_file=" 115 | positional_constraint = "CONTAINS" 116 | 117 | field_to_match { 118 | type = "QUERY_STRING" 119 | } 120 | } 121 | 122 | byte_match_tuples { 123 | text_transformation = "URL_DECODE" 124 | target_string = "safe_mode=" 125 | positional_constraint = "CONTAINS" 126 | 127 | field_to_match { 128 | type = "QUERY_STRING" 129 | } 130 | } 131 | 132 | byte_match_tuples { 133 | text_transformation = "URL_DECODE" 134 | target_string = "_SERVER[" 135 | positional_constraint = "CONTAINS" 136 | 137 | field_to_match { 138 | type = "QUERY_STRING" 139 | } 140 | } 141 | 142 | byte_match_tuples { 143 | text_transformation = "URL_DECODE" 144 | target_string = "allow_url_include=" 145 | positional_constraint = "CONTAINS" 146 | 147 | field_to_match { 148 | type = "QUERY_STRING" 149 | } 150 | } 151 | 152 | byte_match_tuples { 153 | text_transformation = "URL_DECODE" 154 | target_string = "open_basedir=" 155 | positional_constraint = "CONTAINS" 156 | 157 | field_to_match { 158 | type = "QUERY_STRING" 159 | } 160 | } 161 | } 162 | 163 | resource "aws_wafregional_byte_match_set" "match_rfi_lfi_traversal" { 164 | name = "${var.waf_prefix}-generic-match-rfi-lfi-traversal" 165 | 166 | byte_match_tuples { 167 | text_transformation = "HTML_ENTITY_DECODE" 168 | target_string = "://" 169 | positional_constraint = "CONTAINS" 170 | 171 | field_to_match { 172 | type = "QUERY_STRING" 173 | } 174 | } 175 | 176 | byte_match_tuples { 177 | text_transformation = "HTML_ENTITY_DECODE" 178 | target_string = "../" 179 | positional_constraint = "CONTAINS" 180 | 181 | field_to_match { 182 | type = "QUERY_STRING" 183 | } 184 | } 185 | 186 | byte_match_tuples { 187 | text_transformation = "URL_DECODE" 188 | target_string = "://" 189 | positional_constraint = "CONTAINS" 190 | 191 | field_to_match { 192 | type = "QUERY_STRING" 193 | } 194 | } 195 | 196 | byte_match_tuples { 197 | text_transformation = "URL_DECODE" 198 | target_string = "../" 199 | positional_constraint = "CONTAINS" 200 | 201 | field_to_match { 202 | type = "QUERY_STRING" 203 | } 204 | } 205 | 206 | byte_match_tuples { 207 | text_transformation = "HTML_ENTITY_DECODE" 208 | target_string = "://" 209 | positional_constraint = "CONTAINS" 210 | 211 | field_to_match { 212 | type = "URI" 213 | } 214 | } 215 | 216 | byte_match_tuples { 217 | text_transformation = "HTML_ENTITY_DECODE" 218 | target_string = "../" 219 | positional_constraint = "CONTAINS" 220 | 221 | field_to_match { 222 | type = "URI" 223 | } 224 | } 225 | 226 | byte_match_tuples { 227 | text_transformation = "URL_DECODE" 228 | target_string = "://" 229 | positional_constraint = "CONTAINS" 230 | 231 | field_to_match { 232 | type = "URI" 233 | } 234 | } 235 | 236 | byte_match_tuples { 237 | text_transformation = "URL_DECODE" 238 | target_string = "../" 239 | positional_constraint = "CONTAINS" 240 | 241 | field_to_match { 242 | type = "URI" 243 | } 244 | } 245 | } 246 | 247 | resource "aws_wafregional_byte_match_set" "match_ssi" { 248 | name = "${var.waf_prefix}-generic-match-ssi" 249 | 250 | byte_match_tuples { 251 | text_transformation = "LOWERCASE" 252 | target_string = ".cfg" 253 | positional_constraint = "ENDS_WITH" 254 | 255 | field_to_match { 256 | type = "URI" 257 | } 258 | } 259 | 260 | byte_match_tuples { 261 | text_transformation = "LOWERCASE" 262 | target_string = ".backup" 263 | positional_constraint = "ENDS_WITH" 264 | 265 | field_to_match { 266 | type = "URI" 267 | } 268 | } 269 | 270 | byte_match_tuples { 271 | text_transformation = "LOWERCASE" 272 | target_string = ".ini" 273 | positional_constraint = "ENDS_WITH" 274 | 275 | field_to_match { 276 | type = "URI" 277 | } 278 | } 279 | 280 | byte_match_tuples { 281 | text_transformation = "LOWERCASE" 282 | target_string = ".conf" 283 | positional_constraint = "ENDS_WITH" 284 | 285 | field_to_match { 286 | type = "URI" 287 | } 288 | } 289 | 290 | byte_match_tuples { 291 | text_transformation = "LOWERCASE" 292 | target_string = ".log" 293 | positional_constraint = "ENDS_WITH" 294 | 295 | field_to_match { 296 | type = "URI" 297 | } 298 | } 299 | 300 | byte_match_tuples { 301 | text_transformation = "LOWERCASE" 302 | target_string = ".bak" 303 | positional_constraint = "ENDS_WITH" 304 | 305 | field_to_match { 306 | type = "URI" 307 | } 308 | } 309 | 310 | byte_match_tuples { 311 | text_transformation = "LOWERCASE" 312 | target_string = ".config" 313 | positional_constraint = "ENDS_WITH" 314 | 315 | field_to_match { 316 | type = "URI" 317 | } 318 | } 319 | 320 | byte_match_tuples { 321 | text_transformation = "URL_DECODE" 322 | target_string = "/includes" 323 | positional_constraint = "STARTS_WITH" 324 | 325 | field_to_match { 326 | type = "URI" 327 | } 328 | } 329 | } 330 | -------------------------------------------------------------------------------- /regional/waf_condition_xss.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_xss_match_set" "xss_match_set" { 2 | name = "${var.waf_prefix}-generic-detect-xss" 3 | 4 | xss_match_tuple { 5 | text_transformation = "HTML_ENTITY_DECODE" 6 | 7 | field_to_match { 8 | type = "BODY" 9 | } 10 | } 11 | 12 | xss_match_tuple { 13 | text_transformation = "URL_DECODE" 14 | 15 | field_to_match { 16 | type = "BODY" 17 | } 18 | } 19 | 20 | xss_match_tuple { 21 | text_transformation = "HTML_ENTITY_DECODE" 22 | 23 | field_to_match { 24 | type = "URI" 25 | } 26 | } 27 | 28 | xss_match_tuple { 29 | text_transformation = "URL_DECODE" 30 | 31 | field_to_match { 32 | type = "URI" 33 | } 34 | } 35 | 36 | xss_match_tuple { 37 | text_transformation = "HTML_ENTITY_DECODE" 38 | 39 | field_to_match { 40 | type = "QUERY_STRING" 41 | } 42 | } 43 | 44 | xss_match_tuple { 45 | text_transformation = "URL_DECODE" 46 | 47 | field_to_match { 48 | type = "QUERY_STRING" 49 | } 50 | } 51 | 52 | xss_match_tuple { 53 | text_transformation = "HTML_ENTITY_DECODE" 54 | 55 | field_to_match { 56 | type = "HEADER" 57 | data = "cookie" 58 | } 59 | } 60 | 61 | xss_match_tuple { 62 | text_transformation = "URL_DECODE" 63 | 64 | field_to_match { 65 | type = "HEADER" 66 | data = "cookie" 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /regional/waf_rule.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_rule" "detect_admin_access" { 2 | name = "${var.waf_prefix}-generic-detect-admin-access" 3 | metric_name = "${var.waf_prefix}genericdetectadminaccess" 4 | 5 | predicate { 6 | data_id = aws_wafregional_ipset.admin_remote_ipset.id 7 | negated = true 8 | type = "IPMatch" 9 | } 10 | 11 | predicate { 12 | data_id = aws_wafregional_byte_match_set.match_admin_url.id 13 | negated = false 14 | type = "ByteMatch" 15 | } 16 | } 17 | 18 | resource "aws_wafregional_rule" "detect_bad_auth_tokens" { 19 | name = "${var.waf_prefix}-generic-detect-bad-auth-tokens" 20 | metric_name = "${var.waf_prefix}genericdetectbadauthtokens" 21 | 22 | predicate { 23 | data_id = aws_wafregional_byte_match_set.match_auth_tokens.id 24 | negated = false 25 | type = "ByteMatch" 26 | } 27 | } 28 | 29 | resource "aws_wafregional_rule" "detect_blacklisted_ips" { 30 | name = "${var.waf_prefix}-generic-detect-blacklisted-ips" 31 | metric_name = "${var.waf_prefix}genericdetectblacklistedips" 32 | 33 | predicate { 34 | data_id = aws_wafregional_ipset.blacklisted_ips.id 35 | negated = false 36 | type = "IPMatch" 37 | } 38 | } 39 | 40 | resource "aws_wafregional_rule" "detect_php_insecure" { 41 | name = "${var.waf_prefix}-generic-detect-php-insecure" 42 | metric_name = "${var.waf_prefix}genericdetectphpinsecure" 43 | 44 | predicate { 45 | data_id = aws_wafregional_byte_match_set.match_php_insecure_uri.id 46 | negated = false 47 | type = "ByteMatch" 48 | } 49 | 50 | predicate { 51 | data_id = aws_wafregional_byte_match_set.match_php_insecure_var_refs.id 52 | negated = false 53 | type = "ByteMatch" 54 | } 55 | } 56 | 57 | resource "aws_wafregional_rule" "detect_rfi_lfi_traversal" { 58 | name = "${var.waf_prefix}-generic-detect-rfi-lfi-traversal" 59 | metric_name = "${var.waf_prefix}genericdetectrfilfitraversal" 60 | 61 | predicate { 62 | data_id = aws_wafregional_byte_match_set.match_rfi_lfi_traversal.id 63 | negated = false 64 | type = "ByteMatch" 65 | } 66 | } 67 | 68 | resource "aws_wafregional_rule" "detect_ssi" { 69 | name = "${var.waf_prefix}-generic-detect-ssi" 70 | metric_name = "${var.waf_prefix}genericdetectssi" 71 | 72 | predicate { 73 | data_id = aws_wafregional_byte_match_set.match_ssi.id 74 | negated = false 75 | type = "ByteMatch" 76 | } 77 | } 78 | 79 | resource "aws_wafregional_rule" "enforce_csrf" { 80 | name = "${var.waf_prefix}-generic-enforce-csrf" 81 | metric_name = "${var.waf_prefix}genericenforcecsrf" 82 | 83 | predicate { 84 | data_id = aws_wafregional_byte_match_set.match_csrf_method.id 85 | negated = false 86 | type = "ByteMatch" 87 | } 88 | 89 | predicate { 90 | data_id = aws_wafregional_size_constraint_set.csrf_token_set.id 91 | negated = true 92 | type = "SizeConstraint" 93 | } 94 | } 95 | 96 | resource "aws_wafregional_rule" "mitigate_sqli" { 97 | name = "${var.waf_prefix}-generic-mitigate-sqli" 98 | metric_name = "${var.waf_prefix}genericmitigatesqli" 99 | 100 | predicate { 101 | data_id = aws_wafregional_sql_injection_match_set.sql_injection_match_set.id 102 | negated = false 103 | type = "SqlInjectionMatch" 104 | } 105 | } 106 | 107 | resource "aws_wafregional_rule" "mitigate_xss" { 108 | name = "${var.waf_prefix}-generic-mitigate-xss" 109 | metric_name = "${var.waf_prefix}genericmitigatexss" 110 | 111 | predicate { 112 | data_id = aws_wafregional_xss_match_set.xss_match_set.id 113 | negated = false 114 | type = "XssMatch" 115 | } 116 | } 117 | 118 | resource "aws_wafregional_rule" "restrict_sizes" { 119 | name = "${var.waf_prefix}-generic-restrict-sizes" 120 | metric_name = "${var.waf_prefix}genericrestrictsizes" 121 | 122 | predicate { 123 | data_id = aws_wafregional_size_constraint_set.size_restrictions.id 124 | negated = false 125 | type = "SizeConstraint" 126 | } 127 | } 128 | 129 | -------------------------------------------------------------------------------- /regional/waf_web_acl.tf: -------------------------------------------------------------------------------- 1 | resource "aws_wafregional_web_acl" "wafregional_acl" { 2 | name = "${var.waf_prefix}-generic-owasp-acl" 3 | metric_name = "${var.waf_prefix}genericowaspacl" 4 | 5 | default_action { 6 | type = "ALLOW" 7 | } 8 | 9 | rule { 10 | action { 11 | type = "BLOCK" 12 | } 13 | 14 | priority = 1 15 | rule_id = aws_wafregional_rule.restrict_sizes.id 16 | type = "REGULAR" 17 | } 18 | 19 | rule { 20 | action { 21 | type = "BLOCK" 22 | } 23 | 24 | priority = 2 25 | rule_id = aws_wafregional_rule.detect_blacklisted_ips.id 26 | type = "REGULAR" 27 | } 28 | 29 | rule { 30 | action { 31 | type = "BLOCK" 32 | } 33 | 34 | priority = 3 35 | rule_id = aws_wafregional_rule.detect_bad_auth_tokens.id 36 | type = "REGULAR" 37 | } 38 | 39 | rule { 40 | action { 41 | type = "BLOCK" 42 | } 43 | 44 | priority = 4 45 | rule_id = aws_wafregional_rule.mitigate_sqli.id 46 | type = "REGULAR" 47 | } 48 | 49 | rule { 50 | action { 51 | type = "BLOCK" 52 | } 53 | 54 | priority = 5 55 | rule_id = aws_wafregional_rule.mitigate_xss.id 56 | type = "REGULAR" 57 | } 58 | 59 | rule { 60 | action { 61 | type = "BLOCK" 62 | } 63 | 64 | priority = 6 65 | rule_id = aws_wafregional_rule.detect_rfi_lfi_traversal.id 66 | type = "REGULAR" 67 | } 68 | 69 | rule { 70 | action { 71 | type = "BLOCK" 72 | } 73 | 74 | priority = 7 75 | rule_id = aws_wafregional_rule.detect_php_insecure.id 76 | type = "REGULAR" 77 | } 78 | 79 | rule { 80 | action { 81 | type = "BLOCK" 82 | } 83 | 84 | priority = 8 85 | rule_id = aws_wafregional_rule.enforce_csrf.id 86 | type = "REGULAR" 87 | } 88 | 89 | rule { 90 | action { 91 | type = "BLOCK" 92 | } 93 | 94 | priority = 9 95 | rule_id = aws_wafregional_rule.detect_ssi.id 96 | type = "REGULAR" 97 | } 98 | 99 | rule { 100 | action { 101 | type = "BLOCK" 102 | } 103 | 104 | priority = 10 105 | rule_id = aws_wafregional_rule.detect_admin_access.id 106 | type = "REGULAR" 107 | } 108 | } 109 | 110 | --------------------------------------------------------------------------------