Skip to content

Commit

Permalink
Update security firewall with new rules & user agent exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
mbklein committed Jan 2, 2024
1 parent 72a1832 commit 4c9c2c8
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 42 deletions.
32 changes: 16 additions & 16 deletions firewall/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

198 changes: 172 additions & 26 deletions firewall/security_firewall.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ locals {
excluded_rules = {
AWSManagedRulesCommonRuleSet = ["CrossSiteScripting_BODY", "GenericRFI_BODY", "SizeRestrictions_BODY"]
AWSManagedRulesKnownBadInputsRuleSet = []
AWSManagedRulesBotControlRuleSet = []
}
}

resource "aws_cloudwatch_log_group" "security_firewall_log" {
name = "aws-waf-logs-${local.namespace}-load-balancer-firewall"
retention_in_days = 7
tags = local.tags
}

resource "aws_wafv2_web_acl" "security_firewall" {
name = "${local.namespace}-load-balancer-firewall"
Expand All @@ -23,39 +29,48 @@ resource "aws_wafv2_web_acl" "security_firewall" {
}

rule {
name = "AmazonIPReputationList"
name = "${local.namespace}-allowed-user-agents"
priority = 0

override_action {
dynamic "none" {
for_each = toset(local.count_only ? [] : [1])
content {}
}

dynamic "count" {
for_each = toset(local.count_only ? [1] : [])
content {}
}
action {
allow {}
}

statement {
managed_rule_group_statement {
name = "AWSManagedRulesAmazonIpReputationList"
vendor_name = "AWS"
or_statement {
dynamic "statement" {
for_each = toset(var.allowed_user_agents)
iterator = user_agent
content {
byte_match_statement {
positional_constraint = "EXACTLY"
search_string = user_agent.key
field_to_match {
single_header {
name = "user-agent"
}
}
text_transformation {
priority = 0
type = "NONE"
}
}
}
}
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${local.namespace}-load-balancer-firewall-aws-reputation"
metric_name = "${local.namespace}-allow-honeybadger"
sampled_requests_enabled = true
}
}

# Reputation Lists
# Exempt the Meadow API from any rate limits defined later
rule {
name = "stack-p-allow-meadow-api"
name = "${local.namespace}-allow-meadow-api"
priority = 1

action {
Expand Down Expand Up @@ -101,16 +116,88 @@ resource "aws_wafv2_web_acl" "security_firewall" {

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "stack-p-allow-meadow-api"
metric_name = "${local.namespace}-allow-meadow-api"
sampled_requests_enabled = true
}
}

# Block aggressive requests originating in Ireland
rule {
name = "stack-p-aggressive-ie"
name = "AmazonIPReputationList"
priority = 2

override_action {
dynamic "none" {
for_each = toset(local.count_only ? [] : [1])
content {}
}

dynamic "count" {
for_each = toset(local.count_only ? [1] : [])
content {}
}
}

statement {
managed_rule_group_statement {
name = "AWSManagedRulesAmazonIpReputationList"
vendor_name = "AWS"
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${local.namespace}-load-balancer-firewall-aws-reputation"
sampled_requests_enabled = true
}
}

rule {
name = "AWSManagedRulesBotControlRuleSet"
priority = 3

override_action {
dynamic "none" {
for_each = toset(local.count_only ? [] : [1])
content {}
}

dynamic "count" {
for_each = toset(local.count_only ? [1] : [])
content {}
}
}

statement {
managed_rule_group_statement {
name = "AWSManagedRulesBotControlRuleSet"
vendor_name = "AWS"

dynamic "rule_action_override" {
for_each = toset(local.excluded_rules["AWSManagedRulesBotControlRuleSet"])
iterator = rule
content {
action_to_use {
count {}
}

name = rule.key
}
}
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${local.namespace}-load-balancer-firewall-aws-bot-control"
sampled_requests_enabled = true
}
}

# Block aggressive requests originating in Ireland
rule {
name = "${local.namespace}-aggressive-ie"
priority = 4

action {
block {
custom_response {
Expand All @@ -135,15 +222,15 @@ resource "aws_wafv2_web_acl" "security_firewall" {

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "stack-p-aggressive-ie"
metric_name = "${local.namespace}-aggressive-ie"
sampled_requests_enabled = true
}
}

# Block requests from a single IP exceeding 750 requests per 5 minute period
rule {
name = "stack-p-rate-limiter"
priority = 3
name = "${local.namespace}-rate-limiter"
priority = 5

action {
block {
Expand All @@ -157,20 +244,20 @@ resource "aws_wafv2_web_acl" "security_firewall" {
statement {
rate_based_statement {
aggregate_key_type = "IP"
limit = 750
limit = 300
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "stack-p-rate-limiter"
metric_name = "${local.namespace}-rate-limiter"
sampled_requests_enabled = true
}
}

rule {
name = "AWSManagedRulesCommonRuleSet"
priority = 4
priority = 6

override_action {
dynamic "none" {
Expand Down Expand Up @@ -212,7 +299,7 @@ resource "aws_wafv2_web_acl" "security_firewall" {

rule {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 5
priority = 7

override_action {
dynamic "none" {
Expand Down Expand Up @@ -248,13 +335,72 @@ resource "aws_wafv2_web_acl" "security_firewall" {
}
}

rule {
name = "${local.namespace}-high-traffic-ips"
priority = 8

action {
dynamic "block" {
for_each = toset(local.count_only ? [] : [1])
content {}
}

dynamic "count" {
for_each = toset(local.count_only ? [1] : [])
content {}
}
}

statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.high_traffic_ip_set[0].arn
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${local.namespace}-load-balancer-high-traffic-ips"
sampled_requests_enabled = true
}
}

visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "${local.namespace}-load-balancer-firewall"
sampled_requests_enabled = true
}
}

resource "aws_wafv2_ip_set" "high_traffic_ip_set" {
count = var.firewall_type == "SECURITY" ? 1 : 0
name = "high-traffic-ips"
description = "High Traffic IPs"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = var.high_traffic_ips
tags = local.tags
}

resource "aws_wafv2_web_acl_logging_configuration" "security_firewall" {
log_destination_configs = [aws_cloudwatch_log_group.security_firewall_log.arn]
resource_arn = aws_wafv2_web_acl.security_firewall.arn

logging_filter {
default_behavior = "KEEP"

filter {
requirement = "MEETS_ANY"
behavior = "DROP"

condition {
action_condition {
action = "ALLOW"
}
}
}
}
}

resource "aws_wafv2_web_acl_association" "security_firewall" {
for_each = var.firewall_type == "SECURITY" ? var.resources : {}
resource_arn = each.value
Expand Down
10 changes: 10 additions & 0 deletions firewall/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ variable "firewall_type" {
default = ""
}

variable "allowed_user_agents" {
type = list
default = []
}

variable "high_traffic_ips" {
type = list
default = []
}

variable "nul_ips" {
type = list
default = []
Expand Down

0 comments on commit 4c9c2c8

Please sign in to comment.