🔨
aws_wafv2_web_acl 用のイデオムについて
問題
terraformのWAF v2用リソースは、ルール定義がnested blockとして実装されている。
これにより再利用性がかなり低い。これは aws_cloudfront_distribution
と同じ欠点である。
aws_wafv2_web_acl
の場合はCloudFrontよりはまだ状況はマシで、ルールグループを使えば最低限の再利用性は確保できる。
ただし、ルールグループを使用しても aws_wafv2_web_acl
内にかなりの記述をすることには変わりがない。
これらの問題を解決し、 WAF v2の再利用性を最大限確保しつつ冗長な記述をなくしたい。
解決策
resource "aws_wafv2_web_acl" "cloudfront" {
provider = aws.us_east_1
scope = "CLOUDFRONT"
name = "cloudfront"
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "cloudfront"
sampled_requests_enabled = true
}
default_action {
allow {}
}
#####################################################
# マネージドルールグループのdynamic blockループ
#####################################################
dynamic "rule" {
for_each = [
{
name = "aws-managed-rules-amazon-ip-reputation-list"
priority = 21
managed_rule_group_name = "AWSManagedRulesAmazonIpReputationList"
excluded_rule_names = []
},
# https://docs.aws.amazon.com/waf/latest/developerguide/aws-managed-rule-groups-ip-rep.html
{
name = "aws-managed-rules-anonymous-ip-list"
priority = 22
managed_rule_group_name = "AWSManagedRulesAnonymousIpList"
excluded_rule_names = ["HostingProviderIPList"]
},
]
content {
name = rule.value["name"]
priority = rule.value["priority"]
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = rule.value["name"]
sampled_requests_enabled = true
}
override_action {
none {}
}
statement {
managed_rule_group_statement {
name = rule.value["managed_rule_group_name"]
vendor_name = "AWS"
dynamic "excluded_rule" {
for_each = rule.value["excluded_rule_names"]
content {
name = excluded_rule.value
}
}
}
}
}
}
#####################################################
# 非マネージドなルールグループのdynamic blockループ
#####################################################
dynamic "rule" {
for_each = [
{
name = module.waf_rule_group_allow_pagespeed_insights_cloudfront.name
priority = 50
arn = module.waf_rule_group_allow_pagespeed_insights_cloudfront.arn
},
],
[
{
name = module.waf_rule_group_allow_privileged_ip_addresses_cloudfront.name
priority = 131
arn = module.waf_rule_group_allow_privileged_ip_addresses_cloudfront.arn
},
],
]
content {
name = rule.value["name"]
priority = rule.value["priority"]
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = rule.value["name"]
sampled_requests_enabled = true
}
override_action {
none {}
}
statement {
rule_group_reference_statement {
arn = rule.value["arn"]
}
}
}
}
#####################################################
# ルールグループではない直接ACLに書かれたルール
#####################################################
# 以下通常の直書きルール
}
キモは マネージドルールグループのdynamic blockループ
と 非マネージドなルールグループのdynamic blockループ
にある。
これらを書く場合、 override_action
や visibility_config
を細かくチューンしたいときは少ない。そこで、これらにデフォルト値を与えつつdynamic blocksでfor_eachにすることでルールグループの宣言を以下の5行に集約している。
{
name = module.waf_rule_group_allow_privileged_ip_addresses_cloudfront.name
priority = 131
arn = module.waf_rule_group_allow_privileged_ip_addresses_cloudfront.arn
},
実際やってみた感じ
3ヶ月ぐらいこのイデオムを複数のシステムで使ってみたが、ほとんどのユースケースをカバーでき非常に汎用性が高い。
スポンサー
この記事はSpeeeでの業務中に書きました。
Discussion