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

Custom Block Response #56

Merged
merged 16 commits into from
May 17, 2022
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
<a name="unreleased"></a>
## [Unreleased]

- [README] updated to list custom responses capabilities.
- [make] changelog
- [make] validate.
- [Formatting] main.tf
- [Custom Response] handling on per rules basis with dynamic block definitions.
- [Formatting]
- [Variable] definition typo in type fix.
- [README] updated with input info.
- [Block] custom_response http status code.


<a name="3.7.3"></a>
## [3.7.3] - 2022-05-12

- Add 'version' to managed_rule_group_statement ([#55](https://github.com/umotif-public/terraform-aws-waf-webaclv2/issues/55))


<a name="3.7.2"></a>
## [3.7.2] - 2022-05-12

- removed duplicated code ([#53](https://github.com/umotif-public/terraform-aws-waf-webaclv2/issues/53))


<a name="3.7.1"></a>
Expand Down Expand Up @@ -174,10 +195,11 @@ All notable changes to this project will be documented in this file.
- Initial commit


[Unreleased]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.7.1...HEAD
[Unreleased]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.7.3...HEAD
[3.7.3]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.7.2...3.7.3
[3.7.2]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.7.1...3.7.2
[3.7.1]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.7.0...3.7.1
[3.7.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.6.0-patch-1...3.7.0
[3.6.0-patch-1]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.6.0...3.6.0-patch-1
[3.7.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.6.0...3.7.0
[3.6.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.5.0...3.6.0
[3.5.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.4.0...3.5.0
[3.4.0]: https://github.com/umotif-public/terraform-aws-waf-webaclv2/compare/3.3.0...3.4.0
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Supported WAF v2 components:
- Size constraint statements
- Label Match statements
- Regex Pattern Match statements
- Custom responses

## Terraform versions

Expand Down Expand Up @@ -364,6 +365,7 @@ No modules.
| <a name="input_allow_default_action"></a> [allow\_default\_action](#input\_allow\_default\_action) | Set to `true` for WAF to allow requests by default. Set to `false` for WAF to block requests by default. | `bool` | `true` | no |
| <a name="input_create_alb_association"></a> [create\_alb\_association](#input\_create\_alb\_association) | Whether to create alb association with WAF web acl | `bool` | `true` | no |
| <a name="input_create_logging_configuration"></a> [create\_logging\_configuration](#input\_create\_logging\_configuration) | Whether to create logging configuration in order start logging from a WAFv2 Web ACL to Amazon Kinesis Data Firehose. | `bool` | `false` | no |
| <a name="input_custom_response_bodies"></a> [custom\_response\_bodies](#input\_custom\_response\_bodies) | A custom response body to be referenced on a per rule basis. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#custom-response-body | <pre>list(object({<br> key = string<br> content = string<br> content_type = string<br> }))</pre> | `[]` | no |
| <a name="input_description"></a> [description](#input\_description) | A friendly description of the WebACL | `string` | `null` | no |
| <a name="input_enabled"></a> [enabled](#input\_enabled) | Whether to create the resources. Set to `false` to prevent the module from creating any resources | `bool` | `true` | no |
| <a name="input_log_destination_configs"></a> [log\_destination\_configs](#input\_log\_destination\_configs) | The Amazon Kinesis Data Firehose Amazon Resource Name (ARNs) that you want to associate with the web ACL. Currently, only 1 ARN is supported. | `list(string)` | `[]` | no |
Expand Down
65 changes: 65 additions & 0 deletions examples/wafv2-custom-response-code/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
provider "aws" {
region = "eu-west-1"
}

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

name_prefix = var.name_prefix
allow_default_action = true

create_alb_association = false

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "${var.name_prefix}-waf-setup-waf-main-metrics"
sampled_requests_enabled = false
}

rules = [
{
name = "ip-rate-based"
priority = "6"
action = "block"

custom_response = true
custom_response_code = 412

rate_based_statement = {
limit = 2000 # Note this is by default in a 5-min span, ref: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#rate_based_statement
aggregate_key_type = "IP"
}

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "IPRateBased-metric"
sampled_requests_enabled = false
}
},
{
# Note: custom responses can not be applied to AWS managed rule groups directly. Must use a label technical, ref: https://aws.amazon.com/blogs/security/how-to-customize-behavior-of-aws-managed-rules-for-aws-waf/
name = "AWSManagedRulesBotControlRuleSet-rule-0"
priority = "0"

# Note: override_action is for managed rule sets only, otherwise would be action
override_action = "none"

managed_rule_group_statement = {
name = "AWSManagedRulesBotControlRuleSet"
vendor_name = "AWS",
excluded_rule = [
"SignalNonBrowserUserAgent",
"CategoryHttpLibrary",
"SignalAutomatedBrowser",
"CategoryMonitoring"
]
}

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "AWSManagedRulesBotControlRuleSet-metric"
sampled_requests_enabled = false
}
}
]
}
24 changes: 24 additions & 0 deletions examples/wafv2-custom-response-code/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
output "web_acl_name" {
description = "The name of the WAFv2 WebACL."
value = module.waf.web_acl_name
}

output "web_acl_arn" {
description = "The ARN of the WAFv2 WebACL."
value = module.waf.web_acl_arn
}

output "web_acl_capacity" {
description = "The web ACL capacity units (WCUs) currently being used by this web ACL."
value = module.waf.web_acl_capacity
}

output "web_acl_visibility_config_name" {
description = "The web ACL visibility config name"
value = module.waf.web_acl_visibility_config_name
}

output "web_acl_rule_names" {
description = "List of created rule names"
value = module.waf.web_acl_rule_names
}
5 changes: 5 additions & 0 deletions examples/wafv2-custom-response-code/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "name_prefix" {
description = "A prefix used for naming resources."
type = string
default = "example"
}
89 changes: 89 additions & 0 deletions examples/wafv2-custom-response/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
provider "aws" {
region = "eu-west-1"
}

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

name_prefix = var.name_prefix
allow_default_action = true

create_alb_association = false

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "${var.name_prefix}-waf-setup-waf-main-metrics"
sampled_requests_enabled = false
}

custom_response_bodies = [
{
key = "custom_response_body_1",
content = "You are not authorized to access this resource.",
content_type = "TEXT_PLAIN"
},
{
key = "custom_response_body_2",
content = "You there, are not authorized to access this resource.",
content_type = "TEXT_PLAIN"
}
]

rules = [
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the catch here as well... nuked the visibility_config from the copy of my personal block because had local variables I didn't want to bother with here. But just added the block ✔️ .

{
name = "ip-rate-based"
priority = "6"
action = "block"

custom_response = true
custom_response_code = 412
custom_response_key = "custom_response_body_1"
custom_response_headers = [
{
name = "X-Custom-Header"
value = "You are not authorized to access this resource."
},
{
name = "X-Custom-Header-2"
value = "You are still not authorized to access this resource."
}
]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
custom_response = true
custom_response_code = 412
custom_response_key = "custom_response_body_1"
custom_response_headers = [
{
name = "X-Custom-Header"
value = "You are not authorized to access this resource."
},
{
name = "X-Custom-Header-2"
value = "You are still not authorized to access this resource."
}
]
custom_response = {
enabled = true
code = 412
body_key = "custom_response_body_1"
headers = [
{
name = "X-Custom-Header"
value = "You are not authorized to access this resource."
},
{
name = "X-Custom-Header-2"
value = "You are still not authorized to access this resource."
}
]
}

nit: nested instead of flat


rate_based_statement = {
limit = 2000 # Note this is by default in a 5-min span, ref: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#rate_based_statement
aggregate_key_type = "IP"
}

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "IPRateBased-metric"
sampled_requests_enabled = false
}
},
{
# Note: custom responses can not be applied to AWS managed rule groups directly. Must use a label technical, ref: https://aws.amazon.com/blogs/security/how-to-customize-behavior-of-aws-managed-rules-for-aws-waf/
name = "AWSManagedRulesBotControlRuleSet-rule-0"
priority = "0"

# Note: override_action is for managed rule sets only, otherwise would be action
override_action = "none"

managed_rule_group_statement = {
name = "AWSManagedRulesBotControlRuleSet"
vendor_name = "AWS",
excluded_rule = [
"SignalNonBrowserUserAgent",
"CategoryHttpLibrary",
"SignalAutomatedBrowser",
"CategoryMonitoring"
]
}

visibility_config = {
cloudwatch_metrics_enabled = false
metric_name = "AWSManagedRulesBotControlRuleSet-metric"
sampled_requests_enabled = false
}
}
]
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
}
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. Was working on this very change. :)

24 changes: 24 additions & 0 deletions examples/wafv2-custom-response/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
output "web_acl_name" {
description = "The name of the WAFv2 WebACL."
value = module.waf.web_acl_name
}

output "web_acl_arn" {
description = "The ARN of the WAFv2 WebACL."
value = module.waf.web_acl_arn
}

output "web_acl_capacity" {
description = "The web ACL capacity units (WCUs) currently being used by this web ACL."
value = module.waf.web_acl_capacity
}

output "web_acl_visibility_config_name" {
description = "The web ACL visibility config name"
value = module.waf.web_acl_visibility_config_name
}

output "web_acl_rule_names" {
description = "List of created rule names"
value = module.waf.web_acl_rule_names
}
5 changes: 5 additions & 0 deletions examples/wafv2-custom-response/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
variable "name_prefix" {
description = "A prefix used for naming resources."
type = string
default = "example"
}
27 changes: 26 additions & 1 deletion main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,15 @@ resource "aws_wafv2_web_acl" "main" {

description = var.description

dynamic "custom_response_body" {
for_each = var.custom_response_bodies
content {
key = custom_response_body.value.key
content = custom_response_body.value.content
content_type = custom_response_body.value.content_type
}
}

default_action {
dynamic "allow" {
for_each = var.allow_default_action ? [1] : []
Expand All @@ -17,6 +26,7 @@ resource "aws_wafv2_web_acl" "main" {

dynamic "block" {
for_each = var.allow_default_action ? [] : [1]
# Despite seemingly would want to add default custom_response defintions here, the docs state an empyt configuration block is required. ref: https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#default-action
content {}
}
}
Expand All @@ -43,7 +53,22 @@ resource "aws_wafv2_web_acl" "main" {

dynamic "block" {
for_each = lookup(rule.value, "action", {}) == "block" ? [1] : []
content {}
content {
dynamic "custom_response" {
for_each = lookup(rule.value, "custom_response", false) == true ? [1] : []
content {
custom_response_body_key = lookup(rule.value, "custom_response_key", null)
response_code = lookup(rule.value, "custom_response_code", 403)
dynamic "response_header" {
for_each = lookup(rule.value, "custom_response_headers", [])
content {
name = lookup(response_header.value, "name")
value = lookup(response_header.value, "value")
}
}
}
}
}
}
}
}
Expand Down
10 changes: 10 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -86,3 +86,13 @@ variable "description" {
description = "A friendly description of the WebACL"
default = null
}

variable "custom_response_bodies" {
type = list(object({
key = string
content = string
content_type = string
}))
description = "A custom response body to be referenced on a per rule basis. https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/wafv2_web_acl#custom-response-body"
default = []
}