Skip to content

Commit af9b918

Browse files
committed
enha: added option to configure WAF web ACL (#1)
1 parent 3f16b9e commit af9b918

File tree

4 files changed

+118
-0
lines changed

4 files changed

+118
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ This module provides an API Gateway with the option to define routes which invok
2727
| description | Short text of what the API Gateway is trying to accomplish. | `string` | "" | no |
2828
| domain | Custom domain pointed to the API Gateway. | `string` | n/a | yes |
2929
| zone_id | ID of the public hosted zone for the domain. (When not specified the public hosted zone of the domain will be pulled with a data resource from your account) | `string` | "" | no |
30+
| rate_limit | Rate limit for traffic from the same IP address over a period of 5 minutes. | `number` | 0 | no |
3031
| routes | A list of objects for the definition of routes in the API Gateway. | `list(object)` | [] | no |
3132
| log_config | An object for the definition of a CloudWatch log for the API Gateway. | `object` | null | no |
3233
| cors_config | An object for the definition of the CORS configuration for the API Gateway. | `object` | null | no |

main.tf

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,3 +171,64 @@ resource "aws_route53_record" "main" {
171171
evaluate_target_health = false
172172
}
173173
}
174+
175+
################################
176+
# WAF Web ACL #
177+
################################
178+
179+
resource "aws_wafv2_web_acl" "main" {
180+
count = var.rate_limit > 0 ? 1 : 0
181+
name = "${var.identifier}-api-gw"
182+
scope = "REGIONAL"
183+
184+
default_action {
185+
allow {}
186+
}
187+
188+
custom_response_body {
189+
key = "blocked_request_custom_response"
190+
content = "{\n \"error\":\"Too Many Requests.\"\n}"
191+
content_type = "APPLICATION_JSON"
192+
}
193+
194+
visibility_config {
195+
cloudwatch_metrics_enabled = true
196+
metric_name = "${var.identifier}-api-gw"
197+
sampled_requests_enabled = true
198+
}
199+
200+
rule {
201+
name = "RateLimit"
202+
priority = 1
203+
204+
action {
205+
block {
206+
custom_response {
207+
custom_response_body_key = "blocked_request_custom_response"
208+
response_code = 429
209+
}
210+
}
211+
}
212+
213+
statement {
214+
rate_based_statement {
215+
aggregate_key_type = "IP"
216+
limit = var.rate_limit
217+
}
218+
}
219+
220+
visibility_config {
221+
cloudwatch_metrics_enabled = true
222+
metric_name = "${var.identifier}-api-gw-RateLimit"
223+
sampled_requests_enabled = true
224+
}
225+
}
226+
227+
tags = var.tags
228+
}
229+
230+
resource "aws_wafv2_web_acl_association" "main" {
231+
count = var.rate_limit > 0 ? 1 : 0
232+
resource_arn = aws_apigatewayv2_stage.main.arn
233+
web_acl_arn = aws_wafv2_web_acl.main[0].arn
234+
}

tests/waf.tftest.hcl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
provider "aws" {
2+
region = "eu-central-1"
3+
default_tags {
4+
tags = {
5+
Environment = "Test"
6+
}
7+
}
8+
}
9+
10+
run "with_web_acl" {
11+
command = plan
12+
13+
variables {
14+
identifier = "abc"
15+
domain = "test.com"
16+
zone_id = "test-zone"
17+
rate_limit = 100
18+
}
19+
20+
assert {
21+
condition = length(aws_wafv2_web_acl.main) == 1
22+
error_message = "Web ACL was not created"
23+
}
24+
25+
assert {
26+
condition = length(aws_wafv2_web_acl_association.main) == 1
27+
error_message = "Web ACL association was not created"
28+
}
29+
}
30+
31+
run "without_web_acl" {
32+
command = plan
33+
34+
variables {
35+
identifier = "abc"
36+
domain = "test.com"
37+
zone_id = "test-zone"
38+
rate_limit = 0
39+
}
40+
41+
assert {
42+
condition = length(aws_wafv2_web_acl.main) == 0
43+
error_message = "Web ACL was created unexpectedly"
44+
}
45+
46+
assert {
47+
condition = length(aws_wafv2_web_acl_association.main) == 0
48+
error_message = "Web ACL association was created unexpectedly"
49+
}
50+
}

variables.tf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,12 @@ variable "zone_id" {
2424
default = ""
2525
}
2626

27+
variable "rate_limit" {
28+
description = "Rate limit for traffic from the same IP address over a period of 5 minutes."
29+
type = number
30+
default = 0
31+
}
32+
2733
variable "log_config" {
2834
description = "An object for the definition of a CloudWatch log for the API Gateway."
2935
type = object({

0 commit comments

Comments
 (0)