Skip to content

Commit c91acf6

Browse files
Extended the wafv2_web_acl module with custom_response_bodies argument (#721)
Extended the wafv2_web_acl module with custom_response_bodies argument SUMMARY Extended the wafv2_web_acl module to also take the custom_response_bodies argument, improved docs and extended tests ISSUE TYPE Feature Pull Request COMPONENT NAME wafv2_web_acl ADDITIONAL INFORMATION Also touched docs of aws_waf_web_acl to make it easier to find the WAF v2 modules as I had trouble finding that at first. Reviewed-by: Markus Bergholz <[email protected]> Reviewed-by: Stefan Horning <None> Reviewed-by: Mark Chappell <None> Reviewed-by: Alina Buzachis <None>
1 parent 239136b commit c91acf6

File tree

8 files changed

+405
-177
lines changed

8 files changed

+405
-177
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
minor_changes:
2+
- wafv2_web_acl - Extended the wafv2_web_acl module to also take the ``custom_response_bodies`` argument (https://github.com/ansible-collections/community.aws/pull/721).
3+
- wafv2_web_acl - Documentation updates wafv2_web_acl and aws_waf_web_acl (https://github.com/ansible-collections/community.aws/pull/721).

plugins/modules/aws_waf_web_acl.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,11 @@
88

99
DOCUMENTATION = r'''
1010
module: aws_waf_web_acl
11-
short_description: Create and delete WAF Web ACLs.
11+
short_description: Create and delete WAF Web ACLs
1212
version_added: 1.0.0
1313
description:
14-
- Read the AWS documentation for WAF
15-
U(https://aws.amazon.com/documentation/waf/).
14+
- Module for WAF classic, for WAF v2 use the I(wafv2_*) modules.
15+
- Read the AWS documentation for WAF U(https://docs.aws.amazon.com/waf/latest/developerguide/classic-waf-chapter.html).
1616
1717
author:
1818
- Mike Mochan (@mmochan)

plugins/modules/wafv2_web_acl.py

Lines changed: 116 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@
1111
version_added: 1.5.0
1212
author:
1313
- "Markus Bergholz (@markuman)"
14-
short_description: wafv2_web_acl
14+
short_description: Create and delete WAF Web ACLs
1515
description:
16-
- Create, modify or delete a wafv2 web acl.
16+
- Create, modify or delete AWS WAF v2 web ACLs (not for classic WAF).
17+
- See docs at U(https://docs.aws.amazon.com/waf/latest/developerguide/waf-chapter.html)
1718
options:
1819
state:
1920
description:
@@ -28,9 +29,9 @@
2829
type: str
2930
scope:
3031
description:
31-
- Scope of wafv2 web acl.
32+
- Geographical scope of the web acl.
3233
required: true
33-
choices: ["CLOUDFRONT","REGIONAL"]
34+
choices: ["CLOUDFRONT", "REGIONAL"]
3435
type: str
3536
description:
3637
description:
@@ -39,7 +40,7 @@
3940
default_action:
4041
description:
4142
- Default action of the wafv2 web acl.
42-
choices: ["Block","Allow"]
43+
choices: ["Block", "Allow"]
4344
type: str
4445
sampled_requests:
4546
description:
@@ -87,6 +88,14 @@
8788
description:
8889
- Rule configuration.
8990
type: dict
91+
custom_response_bodies:
92+
description:
93+
- A map of custom response keys and content bodies. Define response bodies here and reference them in the rules by providing
94+
- the key of the body dictionary element.
95+
- Each element must have a unique dict key and in the dict two keys for I(content_type) and I(content).
96+
- Requires botocore >= 1.21.0
97+
type: dict
98+
version_added: 3.1.0
9099
purge_rules:
91100
description:
92101
- When set to C(no), keep the existing load balancer rules in place. Will modify and add, but will not delete.
@@ -100,16 +109,15 @@
100109
'''
101110

102111
EXAMPLES = '''
103-
- name: create web acl
112+
- name: Create test web acl
104113
community.aws.wafv2_web_acl:
105114
name: test05
106-
state: present
107115
description: hallo eins
108116
scope: REGIONAL
109117
default_action: Allow
110118
sampled_requests: no
111119
cloudwatch_metrics: yes
112-
metric_name: blub
120+
metric_name: test05-acl-metric
113121
rules:
114122
- name: zwei
115123
priority: 0
@@ -191,10 +199,56 @@
191199
text_transformations:
192200
- type: LOWERCASE
193201
priority: 0
202+
purge_rules: yes
194203
tags:
195204
A: B
196205
C: D
197-
register: out
206+
state: present
207+
208+
- name: Create IP filtering web ACL
209+
community.aws.wafv2_web_acl:
210+
name: ip-filtering-traffic
211+
description: ACL that filters web traffic based on rate limits and whitelists some IPs
212+
scope: REGIONAL
213+
default_action: Allow
214+
sampled_requests: yes
215+
cloudwatch_metrics: yes
216+
metric_name: ip-filtering-traffic
217+
rules:
218+
- name: whitelist-own-IPs
219+
priority: 0
220+
action:
221+
allow: {}
222+
statement:
223+
ip_set_reference_statement:
224+
arn: 'arn:aws:wafv2:us-east-1:520789123123:regional/ipset/own-public-ips/1c4bdfc4-0f77-3b23-5222-123123123'
225+
visibility_config:
226+
sampled_requests_enabled: yes
227+
cloud_watch_metrics_enabled: yes
228+
metric_name: waf-acl-rule-whitelist-own-IPs
229+
- name: rate-limit-per-IP
230+
priority: 1
231+
action:
232+
block:
233+
custom_response:
234+
response_code: 429
235+
custom_response_body_key: too_many_requests
236+
statement:
237+
rate_based_statement:
238+
limit: 5000
239+
aggregate_key_type: IP
240+
visibility_config:
241+
sampled_requests_enabled: yes
242+
cloud_watch_metrics_enabled: yes
243+
metric_name: waf-acl-rule-rate-limit-per-IP
244+
purge_rules: yes
245+
custom_response_bodies:
246+
too_many_requests:
247+
content_type: APPLICATION_JSON
248+
content: '{ message: "Your request has been blocked due to too many HTTP requests coming from your IP" }'
249+
region: us-east-1
250+
state: present
251+
198252
'''
199253

200254
RETURN = """
@@ -218,6 +272,12 @@
218272
sample: test02
219273
returned: Always, as long as the web acl exists
220274
type: str
275+
default_action:
276+
description: Default action of ACL
277+
returned: Always, as long as the web acl exists
278+
sample:
279+
allow: {}
280+
type: dict
221281
rules:
222282
description: Current rules of the web acl
223283
returned: Always, as long as the web acl exists
@@ -235,6 +295,14 @@
235295
cloud_watch_metrics_enabled: true
236296
metric_name: admin_protect
237297
sampled_requests_enabled: true
298+
custom_response_bodies:
299+
description: Custom response body configurations to be used in rules
300+
type: dict
301+
sample:
302+
too_many_requests:
303+
content_type: APPLICATION_JSON
304+
content: '{ message: "Your request has been blocked due to too many HTTP requests coming from your IP" }'
305+
returned: Always, as long as the web acl exists
238306
visibility_config:
239307
description: Visibility config of the web acl
240308
returned: Always, as long as the web acl exists
@@ -267,22 +335,27 @@ def __init__(self, wafv2, name, scope, fail_json_aws):
267335
self.fail_json_aws = fail_json_aws
268336
self.existing_acl, self.id, self.locktoken = self.get_web_acl()
269337

270-
def update(self, default_action, description, rules, sampled_requests, cloudwatch_metrics, metric_name):
338+
def update(self, default_action, description, rules, sampled_requests, cloudwatch_metrics, metric_name, custom_response_bodies):
339+
req_obj = {
340+
'Name': self.name,
341+
'Scope': self.scope,
342+
'Id': self.id,
343+
'DefaultAction': default_action,
344+
'Description': description,
345+
'Rules': rules,
346+
'VisibilityConfig': {
347+
'SampledRequestsEnabled': sampled_requests,
348+
'CloudWatchMetricsEnabled': cloudwatch_metrics,
349+
'MetricName': metric_name
350+
},
351+
'LockToken': self.locktoken
352+
}
353+
354+
if custom_response_bodies:
355+
req_obj['CustomResponseBodies'] = custom_response_bodies
356+
271357
try:
272-
response = self.wafv2.update_web_acl(
273-
Name=self.name,
274-
Scope=self.scope,
275-
Id=self.id,
276-
DefaultAction=default_action,
277-
Description=description,
278-
Rules=rules,
279-
VisibilityConfig={
280-
'SampledRequestsEnabled': sampled_requests,
281-
'CloudWatchMetricsEnabled': cloudwatch_metrics,
282-
'MetricName': metric_name
283-
},
284-
LockToken=self.locktoken
285-
)
358+
response = self.wafv2.update_web_acl(**req_obj)
286359
except (BotoCoreError, ClientError) as e:
287360
self.fail_json_aws(e, msg="Failed to update wafv2 web acl.")
288361
return response
@@ -331,7 +404,7 @@ def get_web_acl(self):
331404
def list(self):
332405
return wafv2_list_web_acls(self.wafv2, self.scope, self.fail_json_aws)
333406

334-
def create(self, default_action, rules, sampled_requests, cloudwatch_metrics, metric_name, tags, description):
407+
def create(self, default_action, rules, sampled_requests, cloudwatch_metrics, metric_name, tags, description, custom_response_bodies):
335408
req_obj = {
336409
'Name': self.name,
337410
'Scope': self.scope,
@@ -343,6 +416,9 @@ def create(self, default_action, rules, sampled_requests, cloudwatch_metrics, me
343416
'MetricName': metric_name
344417
}
345418
}
419+
420+
if custom_response_bodies:
421+
req_obj['CustomResponseBodies'] = custom_response_bodies
346422
if description:
347423
req_obj['Description'] = description
348424
if tags:
@@ -370,6 +446,7 @@ def main():
370446
cloudwatch_metrics=dict(type='bool', default=True),
371447
metric_name=dict(type='str'),
372448
tags=dict(type='dict'),
449+
custom_response_bodies=dict(type='dict'),
373450
purge_rules=dict(default=True, type='bool')
374451
)
375452

@@ -392,6 +469,14 @@ def main():
392469
purge_rules = module.params.get("purge_rules")
393470
check_mode = module.check_mode
394471

472+
custom_response_bodies = module.params.get("custom_response_bodies")
473+
if custom_response_bodies:
474+
module.require_botocore_at_least('1.21.0', reason='to set custom response bodies')
475+
custom_response_bodies = {}
476+
477+
for custom_name, body in module.params.get("custom_response_bodies").items():
478+
custom_response_bodies[custom_name] = snake_dict_to_camel_dict(body, capitalize_first=True)
479+
395480
if default_action == 'Block':
396481
default_action = {'Block': {}}
397482
elif default_action == 'Allow':
@@ -422,7 +507,8 @@ def main():
422507
rules,
423508
sampled_requests,
424509
cloudwatch_metrics,
425-
metric_name
510+
metric_name,
511+
custom_response_bodies
426512
)
427513

428514
else:
@@ -438,7 +524,8 @@ def main():
438524
cloudwatch_metrics,
439525
metric_name,
440526
tags,
441-
description
527+
description,
528+
custom_response_bodies
442529
)
443530

444531
elif state == 'absent':
@@ -453,7 +540,8 @@ def main():
453540
rules,
454541
sampled_requests,
455542
cloudwatch_metrics,
456-
metric_name
543+
metric_name,
544+
custom_response_bodies
457545
)
458546
else:
459547
change = True
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
dependencies:
2+
- setup_remote_tmp_dir
3+
- role: setup_botocore_pip
4+
vars:
5+
boto3_version: "1.18.0"
6+
botocore_version: "1.21.0"

tests/integration/targets/wafv2/tasks/alb.yml

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,5 @@
101101

102102
- assert:
103103
that:
104-
- alb.changed
105104
- alb.listeners|length == 1
106105
- alb.listeners[0].rules|length == 1

0 commit comments

Comments
 (0)