Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

When redacted_fields variable property single_header list has more than one header item #84

Open
kevinneufeld opened this issue Jun 10, 2024 · 1 comment
Labels
bug 🐛 An issue with the system

Comments

@kevinneufeld
Copy link

Describe the Bug

When single_header property has more than one header in the list, Terraform PLAN fails with Error: Too many single_header blocks

 Error: Too many single_header blocks

   on ../../main.tf line 85, in resource "aws_wafv2_web_acl_logging_configuration" "default":
   85:         content {

No more than 1 "single_header" blocks are allowed

Expected Behavior

Since redacted_fields can only accept one block of each property type ( method, uri_path, query_string and single_header), the expectation is for multiple redacted_fields for each single_header

# When `redacted_fields` is:
redacted_fields = {
  default = {
     single_header = [
       "accept-encoding",
       "accept-language"
     ]
  }
}

# The plan should be something like this:
# module.waf.aws_wafv2_web_acl_logging_configuration.default[0] will be created
  + resource "aws_wafv2_web_acl_logging_configuration" "default" {
      + id                      = (known after apply)
      + log_destination_configs = (known after apply)
      + resource_arn            = (known after apply)

      + redacted_fields {
          + single_header {
              + name = "accept-encoding"
            }
        }
      + redacted_fields {
          + single_header {
              + name = "accept-language"
            }
        }
    }
  ...truncated output

Steps to Reproduce

# examples/complete/main.tf
provider "aws" {
  region = var.region
}

resource "aws_cloudwatch_log_group" "default" {
  # https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl_logging_configuration#log_destination_configs
  # data firehose, log group, or bucket name must be prefixed with `aws-waf-logs-`
  name = format("aws-waf-logs-%s", module.this.id)
  tags = module.this.tags
}


module "waf" {
  source = "../.."

  visibility_config = {
    cloudwatch_metrics_enabled = false
    metric_name                = "rules-example-metric"
    sampled_requests_enabled   = false
  }

  log_destination_configs = [aws_cloudwatch_log_group.default.arn]
  redacted_fields = {
    default = {
     single_header = [
       "accept-encoding",
       "accept-language"
     ]
    }
  }

  # https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-list.html
  managed_rule_group_statement_rules = [
    {
      name     = "AWS-AWSManagedRulesAdminProtectionRuleSet"
      priority = 1

      statement = {
        name        = "AWSManagedRulesAdminProtectionRuleSet"
        vendor_name = "AWS"
      }

      visibility_config = {
        cloudwatch_metrics_enabled = true
        sampled_requests_enabled   = true
        metric_name                = "AWS-AWSManagedRulesAdminProtectionRuleSet"
      }
    },
    {
      name     = "AWS-AWSManagedRulesAmazonIpReputationList"
      priority = 2

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

      visibility_config = {
        cloudwatch_metrics_enabled = true
        sampled_requests_enabled   = true
        metric_name                = "AWS-AWSManagedRulesAmazonIpReputationList"
      }
    },
    {
      name     = "AWS-AWSManagedRulesCommonRuleSet"
      priority = 3

      statement = {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"
      }

      visibility_config = {
        cloudwatch_metrics_enabled = true
        sampled_requests_enabled   = true
        metric_name                = "AWS-AWSManagedRulesCommonRuleSet"
      }
    },
    {
      name     = "AWS-AWSManagedRulesKnownBadInputsRuleSet"
      priority = 4

      statement = {
        name        = "AWSManagedRulesKnownBadInputsRuleSet"
        vendor_name = "AWS"
      }

      visibility_config = {
        cloudwatch_metrics_enabled = true
        sampled_requests_enabled   = true
        metric_name                = "AWS-AWSManagedRulesKnownBadInputsRuleSet"
      }
    },
    # https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-bot.html
    {
      name     = "AWS-AWSManagedRulesBotControlRuleSet"
      priority = 5

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

        rule_action_override = {
          CategoryHttpLibrary = {
            action = "block"
            custom_response = {
              response_code = "404"
              response_header = {
                name  = "example-1"
                value = "example-1"
              }
            }
          }
          SignalNonBrowserUserAgent = {
            action = "count"
            custom_request_handling = {
              insert_header = {
                name  = "example-2"
                value = "example-2"
              }
            }
          }
        }

        managed_rule_group_configs = [
          {
            aws_managed_rules_bot_control_rule_set = {
              inspection_level = "COMMON"
            }
          }
        ]
      }

      visibility_config = {
        cloudwatch_metrics_enabled = true
        sampled_requests_enabled   = true
        metric_name                = "AWS-AWSManagedRulesBotControlRuleSet"
      }
    }
  ]

  byte_match_statement_rules = []
  rate_based_statement_rules = []
  size_constraint_statement_rules = []
  xss_match_statement_rules = []
  sqli_match_statement_rules = []
  geo_match_statement_rules = []
  geo_allowlist_statement_rules = []
  regex_match_statement_rules = []
  ip_set_reference_statement_rules = []

  context = module.this.context
}

Screenshots

No response

Environment

No response

Additional Context

One possible (BREAKING) fix would be to change the redacted_fields from a map object to just an object and separate the dynamic blocks.

# variables Line#997: https://github.com/cloudposse/terraform-aws-waf/blob/main/variables.tf#L977
variable "redacted_fields" {
  type = object({
    method        = optional(bool, false)
    uri_path      = optional(bool, false)
    query_string  = optional(bool, false)
    single_header = optional(list(string), [])
  })

  default  = {}
  nullable = false
}

# main.tf Line#22: https://github.com/cloudposse/terraform-aws-waf/blob/main/main.tf#L22
resource "aws_wafv2_web_acl_logging_configuration" "default" {
  count = local.enabled && length(var.log_destination_configs) > 0 ? 1 : 0

  resource_arn            = one(aws_wafv2_web_acl.default[*].arn)
  log_destination_configs = var.log_destination_configs

  # Method
  dynamic "redacted_fields" {
    for_each = var.redacted_fields.method ? [true] : []
    content {
      method {}
    }
  }
  # Query String
  dynamic "redacted_fields" {
    for_each = var.redacted_fields.query_string ? [true] : []
    content {
      query_string {}
    }
  }
  # Uri Path
  dynamic "redacted_fields" {
    for_each = var.redacted_fields.uri_path ? [true] : []
    content {
      uri_path {}
    }
  }
  # Single Header
  dynamic "redacted_fields" {
    for_each = toset(var.redacted_fields.single_header)
    content {
      single_header {
        name = redacted_fields.value
      }
    }
  }
... truncated - the rest of the code is not included.
@kevinneufeld kevinneufeld added the bug 🐛 An issue with the system label Jun 10, 2024
@kevinneufeld kevinneufeld changed the title When redacted_fields variable property single_header list has no than one header item When redacted_fields variable property single_header list has more than one header item Jun 10, 2024
@addepar-tg
Copy link

We are also hitting this error with multiple values in the list. While we're able to filter out these headers during log ingestion, it would be great to be able to prevent these from logging to our S3 bucket as well. 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug 🐛 An issue with the system
Projects
None yet
Development

No branches or pull requests

2 participants