Error creating WAFv2 WebACL WAFInvalidParameterException - amazon-web-services

Error: Error creating WAFv2 WebACL: WAFInvalidParameterException: Error reason: You have used none or multiple values for a field that requires exactly one value., field: RULE_ACTION, parameter: RuleAction(block=null, allow=null, count=null)
{
RespMetadata: {
StatusCode: 400,
RequestID: "24106754-b0db-4497-8e19-e72f8908dc19"
},
Field: "RULE_ACTION",
Message_: "Error reason: You have used none or multiple values for a field that requires exactly one value., field: RULE_ACTION, parameter: RuleAction(block=null, allow=null, count=null)",
Parameter: "RuleAction(block=null, allow=null, count=null)",
Reason: "You have used none or multiple values for a field that requires exactly one value."
}
on .terraform/modules/wafv2/main.tf line 18, in resource "aws_wafv2_web_acl" "main":
18: resource "aws_wafv2_web_acl" "main" {
I am having this error while trying to deploy a WAFV2 with terraform any help is appreciated please.
Here is a little portion of the WAFv2 code:
resource "aws_wafv2_web_acl" "main" {
name = var.name
description = "WAFv2 ACL for ${var.name}"
scope = var.scope
default_action {
allow {}
}
visibility_config {
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
metric_name = var.name
}
dynamic "rule" {
for_each = var.managed_rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
dynamic "none" {
for_each = rule.value.override_action == "none" ? [1] : []
content {}
}
I am trying to figure out why the error is still reflecting maybe a problem with my WAFV2?

There may be a number of reasons why this error happens, so without seeing the full Terraform it is a bit hard to tell what is going on.
I've seen this happen where my ACL contained two rules: a rule_group_reference_statement and a rate_based_statement.
My problem was the rule group reference needed an override_action:
override_action {
none {}
}
I didn't realize either that or an action was required, but I found out about that here: https://github.com/hashicorp/terraform-provider-aws/issues/14094#issuecomment-655625254

I was using the Java version of the CDK and the way to get the "none {}" override action is unclear from the documentation. But this works:
.overrideAction(CfnWebACL.OverrideActionProperty.builder()
.none(new HashMap<String, Object>())
.build())

resource "aws_wafv2_ip_set" "ip_whitelist" {
name = "ip-whitelist"
scope = "REGIONAL"
ip_address_version = "IPV4"
addresses = ["100.12.10.20/32"] # your ip
}
resource "aws_wafv2_web_acl" "web_acl" {
name = "waf-rules"
description = "waf rules"
scope = "REGIONAL"
default_action {
allow {}
}
# ipsets
rule {
name = "ip-whitelist"
priority = 0
action {
allow {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.ip_whitelist.arn
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "Whitelist-ip"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "white-list-ip"
sampled_requests_enabled = true
}
dynamic "rule" {
for_each = var.rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = rule.value.managed_rule_group_statement_name
vendor_name = rule.value.managed_rule_group_statement_vendor_name
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = rule.value.metric_name
sampled_requests_enabled = true
}
}
}
}
# variables.tf
variable "rules" {
type = list(any)
default = [
{
name = "AWS-AWSManagedRulesAdminProtectionRuleSet"
priority = 1
managed_rule_group_statement_name = "AWSManagedRulesAdminProtectionRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesPHPRuleSet"
priority = 2
managed_rule_group_statement_name = "AWSManagedRulesPHPRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesLinuxRuleSet"
priority = 3
managed_rule_group_statement_name = "AWSManagedRulesLinuxRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesAmazonIpReputationList"
priority = 4
managed_rule_group_statement_name = "AWSManagedRulesAmazonIpReputationList"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesSQLiRuleSet"
priority = 5
managed_rule_group_statement_name = "AWSManagedRulesSQLiRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesUnixRuleSet"
priority = 6
managed_rule_group_statement_name = "AWSManagedRulesUnixRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesCommonRuleSet"
priority = 7
managed_rule_group_statement_name = "AWSManagedRulesCommonRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
}
]
}

Related

How to create a WAF ACL with more than 1 managed statement

I'm trying to create a WAF ACL using two AWS Managed rules. These should be evaluated in natural order from priority 1 and then 2.
I've got:
resource "aws_wafv2_web_acl" "acl" {
name = "us-blog-production-waf-acl"
scope = "REGIONAL"
default_action {
allow {}
}
rule {
name = "managed-common-rules"
priority = 0
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesCommonRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "us-blog-production-managed-common-rules"
sampled_requests_enabled = true
}
}
rule {
name = "ip-reputation-rules"
priority = 1
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesAmazonIpReputationList"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "us-blog-production-ip-reputation-rules"
sampled_requests_enabled = true
}
}
rule {
name = "acccount-takeover-rules"
priority = 2
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = "AWSManagedRulesATPRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "us-blog-production-account-takeover-rules"
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "us-blog-production-waf"
sampled_requests_enabled = false
}
}
I tried having two rule blocks inside the aws_wafv2_web_acl resource block but wouldn't work either.
The error I'm getting is:
│ {
│ RespMetadata: {
│ StatusCode: 400,
│ RequestID: "77a6b751-49b1-46d0-af20-39a25e578e79"
│ },
│ Field: "MANAGED_RULE_SET_STATEMENT",
│ Message_: "Error reason: A required field is missing from the parameter., field: MANAGED_RULE_SET_STATEMENT, parameter: ManagedRuleSetConfig",
│ Parameter: "ManagedRuleSetConfig",
│ Reason: "A required field is missing from the parameter."
│ }
How should I set it up?
As per my comment, the documentation says you can have multiple rules in the resource, but you have to have one of action or override_action [1]:
One of action or override_action is required when specifying a rule
This is what is missing in your code.
EDIT: The second issue that is happening is probably because there is additional pricing for the ATP managed rule set [2].
[1] https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#rules
[2] https://aws.amazon.com/waf/pricing/#Intelligent_threat_mitigation_from_AWS_WAF

Merge list with map in terraform

I am writing terraform script to automate the provision of acm for domains, the issue that I am facing is how can I merge the domain and subject_alternative_names like it should pick first domain from domain_name and merge it with first block in subject_alternative_name and go on.
Variable.tf
variable "domain_name" {
description = "Configuration for alb settings"
default = [
"domain.com",
"helloworld.com",
"helloworld2.com",
]
}
variable "subject_alternative_names" {
description = "subject_alternative_names"
default = [ {
domain.com = {
"domain.com",
"domain2.com",
"domain3.com",
},
helloworld.com = {
"helloworld1.com",
"helloworld2.com"
},
hiworld.com = {
"hiworld1.com",
"hiworld2.com"
}
}]
}
variable "region" {
description = "name of the region"
default = "us-east-1"
}
variable "validation_method" {
description = "name of the region"
default = "DNS"
}
variable "tags" {
description = "name of the region"
default = "Test"
}
working variable.tf
variable "domain_name" {
description = "Configuration for alb settings"
default = [
"domain.com",
"helloworld.com",
"helloworld2.com",
"helloworld1.com",
"helloworld3.com",
]
}
variable "subject_alternative_names"{
description = "subject_alternative_names"
default = [
"domain.com",
"helloworld.com",
"helloworld2.com",
"helloworld1.com",
"helloworld3.com",
]
}
variable "region" {
description = "name of the region"
default = "us-east-1"
}
variable "validation_method" {
description = "name of the region"
default = "DNS"
}
variable "tags" {
description = "name of the region"
default = "Test"
}
main.tf
module "acm" {
count = length(var.domain_name)
source = "./modules/acm"
domain_name = var.domain_name[count.index]
validation_method = var.validation_method
tags = var.tags
subject_alternative_names = var.subject_alternative_names
}
resource.tf
variable "domain_name" {
default = ""
description = "Nmae of the domain"
}
variable "validation_method" {
default = ""
description = "Validation method DNS or EMAIL"
}
variable "tags" {
default = ""
description = "tags for the ACM certificate"
}
variable "subject_alternative_names" {
default = ""
description = "subject_alternative_names"
}
resource "aws_acm_certificate" "acm_cert" {
domain_name = var.domain_name
validation_method = var.validation_method
subject_alternative_names = var.subject_alternative_names
lifecycle {
create_before_destroy = true
}
tags = {
Name = var.tags
}
}
The easiest way would be to use a single map:
variable "domain_name_with_alternate_names" {
default = {
"domain.com" = [
"domain.com",
"domain2.com",
"domain3.com",
],
"helloworld.com" = [
"helloworld1.com",
"helloworld2.com"
],
"hiworld.com" = [
"hiworld1.com",
"hiworld2.com"
],
"hiwodd4.com" = []
}
}
module "acm" {
for_each = var.domain_name_with_alternate_names
source = "./modules/acm"
domain_name = each.key
validation_method = var.validation_method
tags = var.tags
subject_alternative_names = each.value
}

Wafv2 with terraform. how to do I exclude rules?

I created a WAFV2 as a modules and this is part of my code
name = var.name
description = "WAFv2 ACL for ${var.name}"
scope = var.scope
default_action {
allow {}
}
visibility_config {
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
metric_name = var.name
}
dynamic "rule" {
for_each = var.managed_rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
dynamic "none" {
for_each = rule.value.override_action == "none" ? [1] : []
content {}
}
dynamic "count" {
for_each = rule.value.override_action == "count" ? [1] : []
content {}
}
}
But after setting up kinesis firehouse I noticed some requests are been blocked by WAFV2, can anyone help me to figure out how to exclude some of the AwsManagdRules been blocked? here are some examples of them.
"CrossSiteScripting_BODY", "GenericLFI_BODY"
but I tried something like this one below in the tableau server using the waf is this correct?
name = aws_wafv2_rule_group.aws-wafv2-tableau.name
arn = aws_wafv2_rule_group.aws-wafv2-tableau.arn
priority = 0
override_action = "allow"
excluded_rules = ["CrossSiteScripting_BODY","GenericLFI_BODY"]
}]```

Dynamically create multiple WAF rules with Terraform

I've got a piece of Terraform code that creates a Web ACL with a set of rules in AWS.
provider "aws" {
region = "eu-west-2"
}
resource "aws_wafv2_web_acl" "foo" {
name = "foo"
description = "foo"
scope = "REGIONAL"
default_action {
block {}
}
rule {
name = "AWS-AWSManagedRulesLinuxRuleSet"
priority = 0
override_action {
count {}
}
statement {
managed_rule_group_statement {
name = "AWS-AWSManagedRulesLinuxRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "foo_name"
sampled_requests_enabled = false
}
}
rule {
name = "AWS-AWSManagedRulesSQLiRuleSet"
priority = 1
override_action {
count {}
}
statement {
managed_rule_group_statement {
name = "AWS-AWSManagedRulesSQLiRuleSet"
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = "foo_name"
sampled_requests_enabled = false
}
}
tags = {
Tag1 = "Value1"
}
visibility_config {
metric_name = "foo"
sampled_requests_enabled = false
cloudwatch_metrics_enabled = false
}
}
This works fine, but adding more rules means that my code starts to turn into somewhat of a monolith.
Is there a way to create multiple rules in Terraform using dynamic_blocks or for_each or something else, in a way that looks cleaner and dry?
You use dynamic in combination with for_each like this:
Define a variable:
variable "rules" {
type = list
default = [
{
name = "AWS-AWSManagedRulesLinuxRuleSet"
priority = 0
managed_rule_group_statement_name = "AWS-AWSManagedRulesLinuxRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesSQLiRuleSet"
priority = 1
managed_rule_group_statement_name = "AWS-AWSManagedRulesSQLiRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
}
]
}
Then use it in the resource:
dynamic "rule" {
for_each = toset(var.rules)
content {
name = rule.value.name
priority = rule.value.priority
override_action {
count {}
}
statement {
managed_rule_group_statement {
name = rule.value.managed_rule_group_statement_name
vendor_name = rule.value.managed_rule_group_statement_vendor_name
}
}
visibility_config {
cloudwatch_metrics_enabled = false
metric_name = rule.value.metric_name
sampled_requests_enabled = false
}
}
}
(Note: Obviously this replaces your previous rule blocks. See also the documentation about Dynamic Blocks for more information.)

Error when using aws wafv2 create-web-acl

I am using version 2.0.50 of the AWS cli on Linux, and trying to create a v2 AWS WAF. Running the command aws wafv2 create-web-acl --cli-input-json file://waf.json results in the following response:
An error occurred (WAFInvalidParameterException) when calling the CreateWebACL operation: Error reason: Your statement has multiple values set for a field that requires exactly one value., field: RULE, parameter: Rule
Can somebody identify what is wrong with the following JSON, or confirm that they are seeing the same issue?
{
"DefaultAction": {
"Allow": {}
},
"Name": "test-web-acl",
"Rules": [
{
"Name": "rule-one",
"Priority": 1,
"Statement": {
"ManagedRuleGroupStatement": {
"Name": "AWSManagedRulesUnixRuleSet",
"VendorName": "AWS"
}
},
"VisibilityConfig": {
"CloudWatchMetricsEnabled": false,
"MetricName": "rule-one-metric",
"SampledRequestsEnabled": false
}
}
],
"Scope": "REGIONAL",
"VisibilityConfig": {
"CloudWatchMetricsEnabled": false,
"MetricName": "test-web-acl-metric",
"SampledRequestsEnabled": false
}
}
I can't see what is incorrect about the JSON according to the syntax described here CreateWebACL
The answer is that the OverrideAction attribute is missing from the Rule object. When adding "OverrideAction":{"None":{}} to the Rule object, then the ACL was created. The error message is misleading.
# resources.tf
resource "aws_wafv2_ip_set" "ip_whitelist" {
name = var.waf_name
scope = var.waf_scope
ip_address_version = var.waf_ip_address_version
addresses = [var.waf_addresses]
}
resource "aws_wafv2_web_acl" "web_acl" {
name = var.waf_web_acl_name
description = var.waf_description
scope = var.waf_scope
default_action {
allow {}
}
# ipsets
rule {
name = var.waf_name
priority = 0
action {
allow {}
}
statement {
ip_set_reference_statement {
arn = aws_wafv2_ip_set.ip_whitelist.arn
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = var.waf_name
sampled_requests_enabled = true
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = var.waf_name
sampled_requests_enabled = true
}
dynamic "rule" {
for_each = var.rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = rule.value.managed_rule_group_statement_name
vendor_name = rule.value.managed_rule_group_statement_vendor_name
}
}
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = rule.value.metric_name
sampled_requests_enabled = true
}
}
}
}
resource "aws_wafv2_web_acl_association" "waf_alb" {
resource_arn = aws_alb.alb.arn
web_acl_arn = aws_wafv2_web_acl.web_acl.arn
}
# variables.tf
# waf ipset name
variable "waf_name" {
type = string
default = "ip-whitelist"
}
variable "waf_scope" {
type = string
default = "REGIONAL"
}
variable "waf_ip_address_version" {
default = "IPV4"
type=string
}
variable "waf_addresses" {
default = "your-ip/32"
type = string
}
# waf details
variable "waf_web_acl_name" {
type=string
default = "waf-rules"
}
variable "waf_description" {
type=string
default = "waf rules"
}
# waf multiple rules
variable "rules" {
type = list(any)
default = [
{
name = "AWS-AWSManagedRulesAdminProtectionRuleSet"
priority = 1
managed_rule_group_statement_name = "AWSManagedRulesAdminProtectionRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesPHPRuleSet"
priority = 2
managed_rule_group_statement_name = "AWSManagedRulesPHPRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesLinuxRuleSet"
priority = 3
managed_rule_group_statement_name = "AWSManagedRulesLinuxRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesAmazonIpReputationList"
priority = 4
managed_rule_group_statement_name = "AWSManagedRulesAmazonIpReputationList"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesSQLiRuleSet"
priority = 5
managed_rule_group_statement_name = "AWSManagedRulesSQLiRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesUnixRuleSet"
priority = 6
managed_rule_group_statement_name = "AWSManagedRulesUnixRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
},
{
name = "AWS-AWSManagedRulesCommonRuleSet"
priority = 7
managed_rule_group_statement_name = "AWSManagedRulesCommonRuleSet"
managed_rule_group_statement_vendor_name = "AWS"
metric_name = "foo_name"
}
]
}