AWS WAFのAWSマネージドルールをTerraformで一括追加する方法
皆さんは、TerraformでAWS WAFを導入する際に「とりあえずAWS Managedなルールを一括追加してCOUNTモードで挙動を確認したい!」ということはないでしょうか?
本記事はそのような方に向けて、AWS WAFのマネージドルールをシンプルな記述で一括追加できるTerraformコードをご紹介します。
対象読者
- AWS WAFのマネージドルールをCOUNTモードにて、Terraformで一括追加したい方
- Terraformのmap, object, dynamics blockの使い方を、コードを交えて理解したい方
前提
- Terraformを触ったことがある前提でお話しをします
- init, plan, apply, destroyを知っているレベル
- AWS Managed rule: AWS WAF Fraud Control アカウント乗っ取り防止 (ATP) のルールグループについては、Pathの設定が必要になるので今回の対象からは除外しています
実行環境
- OS
macOS Monterey version 13.4 - CPU
Apple M1(Macbook Pro 2020) - MEM
16GB - Program
Terraform 1.4.6
はじめに
Terraformコードを求めている方が多いかと思いますので、はじめにコードを載せます。
コードをコピペしてinit, plan, applyすればwafルールが作成されます。
以降はコードをポイントごとに解説していきます。
また、実際に使う際には適宜Module化して利用するのが良いと思います。
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0.0"
}
}
required_version = ">= 1.4.0"
}
provider "aws" {
profile = "default"
region = "ap-northeast-1"
default_tags {
tags = {
Terraform = true
}
}
}
variable "rules" {
description = "Map of AWS WAF Managed-rules"
type = map(object({
name = string
priority = number
cloudwatch_metrics_enabled = bool
sampled_requests_enabled = bool
}))
default = {
AWSManagedRulesCommonRuleSet = {
name = "AWSManagedRulesCommonRuleSet"
priority = 100
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesAdminProtectionRuleSet = {
name = "AWSManagedRulesAdminProtectionRuleSet"
priority = 200
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesKnownBadInputsRuleSet = {
name = "AWSManagedRulesKnownBadInputsRuleSet"
priority = 300
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesSQLiRuleSet = {
name = "AWSManagedRulesSQLiRuleSet"
priority = 400
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesLinuxRuleSet = {
name = "AWSManagedRulesLinuxRuleSet"
priority = 500
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesUnixRuleSet = {
name = "AWSManagedRulesUnixRuleSet"
priority = 600
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesWindowsRuleSet = {
name = "AWSManagedRulesWindowsRuleSet"
priority = 700
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesPHPRuleSet = {
name = "AWSManagedRulesPHPRuleSet"
priority = 800
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesWordPressRuleSet = {
name = "AWSManagedRulesWordPressRuleSet"
priority = 900
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesAmazonIpReputationList = {
name = "AWSManagedRulesAmazonIpReputationList"
priority = 1000
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesAnonymousIpList = {
name = "AWSManagedRulesAnonymousIpList"
priority = 1200
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
AWSManagedRulesBotControlRuleSet = {
name = "AWSManagedRulesBotControlRuleSet"
priority = 1300
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
}
}
}
resource "aws_wafv2_web_acl" "example" {
name = "TerraformWebACL"
description = "Example of a managed rule created by Terraform."
scope = "REGIONAL"
default_action {
allow {}
}
# AWS Managed rulesを一括追加
dynamic "rule" {
for_each = var.rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
# 以下をnoneとすることでcountモードを解除可能
count {}
}
statement {
managed_rule_group_statement {
name = rule.value.name
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = rule.value.cloudwatch_metrics_enabled
metric_name = "${rule.value.name}WafMetric"
sampled_requests_enabled = rule.value.sampled_requests_enabled
}
}
}
# ruleを追加する際には以下にrule{}を追加
visibility_config {
cloudwatch_metrics_enabled = true
metric_name = "TerraformWebACLMetric"
sampled_requests_enabled = true
}
}
コード解説
マネージドルール定義
Terraformのmapとobjectを利用してマネージドルールのVariable定義を行なっています。
定義したVariableに従って、default = {}
内にて変数を定義しています。変数についてはTerraform公式:aws_wafv2_web_aclを参照してください。
default = {}
内のnameにはAWS公式:AWS マネージドルールのルールグループのリストに記載されている、ルールの名前を記述してください。
また、Module化する場合にはVariableをModule側のvariable.tfなどに記述を行い、呼び出す際にdefaultの部分をrules
などに変更して渡してください。
variable "rules" {
description = "Map of AWS WAF Managed-rules"
type = map(object({
name = string
priority = number
cloudwatch_metrics_enabled = bool
sampled_requests_enabled = bool
}))
default = {
AWSManagedRulesCommonRuleSet = {
name = "AWSManagedRulesCommonRuleSet"
priority = 100
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
},
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// 中略
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
AWSManagedRulesBotControlRuleSet = {
name = "AWSManagedRulesBotControlRuleSet"
priority = 1300
cloudwatch_metrics_enabled = true
sampled_requests_enabled = true
}
}
}
マネージドルール適用
マネージドルールを適用する際にはTerraformのdynamic blocksを利用して繰り返しの記述を避けています。
dynamic blocksは若干ややこしいかと感じる方もいるかもしれないですが、今回のようなruleをぐるぐる回して追加して行く際にはとても有用です。
また、コメントにて記載しておりますが、count {}
--> none {}
とすることでAWSマネージドルールにて検知された通信をBlockする動作にすることができます。
※現在の記載だとCountモードでの動作となります。各モードについてはAWS公式:AWS WAF ルールアクションをご覧ください。
# AWS Managed rulesを一括追加
dynamic "rule" {
for_each = var.rules
content {
name = rule.value.name
priority = rule.value.priority
override_action {
# 以下をnoneとすることでcountモードを解除可能
count {}
}
statement {
managed_rule_group_statement {
name = rule.value.name
vendor_name = "AWS"
}
}
visibility_config {
cloudwatch_metrics_enabled = rule.value.cloudwatch_metrics_enabled
metric_name = "${rule.value.name}WafMetric"
sampled_requests_enabled = rule.value.sampled_requests_enabled
}
}
}
その他Tips
- AWS WAFのPriorityは0 ~ 2,147,483,647の範囲で設定可能
- マネージドルールのPriorityを設定
許可リストを追加する際に追加しやすいよう、各マネージドルール間の間隔を100から100刻みで設定しています。
前述した通り、Priorityの設定可能範囲は広いため、10刻みにするなど、お好みに応じて変更してください。
終わりに
AWS WAFはAWSマネージドルール以外にも、AWS Marketplaceで提供される3rd Partyベンダーさんが提供するマネージドルールも複数ありますので、それぞれの要件に合ったものを適用していただければと思います。
本記事が誰かの助けとなれば幸いです。
Discussion