Terraform で ALB 用 AWS WAF v2 を構築する

2020年10月10日

概要

やりたいこと

Terraform で ALB 用の AWS WAF v2 を構築したい。

過去に AWS WAF v1 は Terraform で構築した。

CloudFormation で AWS WAF v2 は構築した。

CloudFormation で AWS WAF v2 に AWS Managed Rules を設定する

Terraform WAF v2

WAF v2 リソースを Terraform で作成する場合、以下のドキュメントに全て載っている。

「Managed Rule」サンプルをそのままコピーして実行すれば「managed-rule-example」 ACL が作成される。

以下の AWSManagedRulesCommonRuleSet を rule-1 という名前で登録している。

AWSManagedRulesCommonRuleSet は検知(Count)モードが設定される。
以下2つのルールは exclude rule に指定されいる。

  • NoUserAgent_HEADER
  • SizeRestrictions_QUERYSTRING

AWS WAF のアクションの意味は以下を参照。

Terraform

準備

WAF v2

以下 8 個のルールを適用し、 Web ACL Rule Capacity Units は 1478/1500。

  • AWSManagedRulesCommonRuleSet
  • AWSManagedRulesKnownBadInputsRuleSet
  • AWSManagedRulesAmazonIpReputationList
  • AWSManagedRulesAnonymousIpList
  • AWSManagedRulesSQLiRuleSet
  • AWSManagedRulesLinuxRuleSet
  • AWSManagedRulesUnixRuleSet
  • AWSRateBasedRule

Terraform はケバブケースなので、キャメルケースの変数名が浮いているが。。

resource "aws_wafv2_web_acl" "example" {
  name        = "TerraformWebACL"
  description = "Example of a managed rule by terraform."
  scope       = "REGIONAL"

  default_action {
    allow {}
  }

  rule {
    name     = "AWSManagedRulesCommonRuleSet"
    priority = 10

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesCommonRuleSet"
        vendor_name = "AWS"

        excluded_rule {
          name = "SizeRestrictions_QUERYSTRING"
        }

        excluded_rule {
          name = "NoUserAgent_HEADER"
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesCommonRuleSetMetric"
      sampled_requests_enabled   = false
    }
  }


  rule {
    name     = "AWSManagedRulesKnownBadInputsRuleSet"
    priority = 20

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesKnownBadInputsRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesKnownBadInputsRuleSetMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSManagedRulesAmazonIpReputationList"
    priority = 30

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesAmazonIpReputationList"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesAmazonIpReputationListMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSManagedRulesAnonymousIpList"
    priority = 40

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesAnonymousIpList"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesAnonymousIpListMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSManagedRulesSQLiRuleSet"
    priority = 50

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesSQLiRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesSQLiRuleSetMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSManagedRulesLinuxRuleSet"
    priority = 60

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesLinuxRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesLinuxRuleSetMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSManagedRulesUnixRuleSet"
    priority = 70

    override_action {
      count {}
    }

    statement {
      managed_rule_group_statement {
        name        = "AWSManagedRulesUnixRuleSet"
        vendor_name = "AWS"
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSManagedRulesUnixRuleSetMetric"
      sampled_requests_enabled   = false
    }
  }

  rule {
    name     = "AWSRateBasedRule"
    priority = 1

    action {
      count {}
    }

    statement {
      rate_based_statement {
        limit              = 500
        aggregate_key_type = "IP"

        scope_down_statement {
          geo_match_statement {
            country_codes = ["US", "NL"]
          }
        }
      }
    }

    visibility_config {
      cloudwatch_metrics_enabled = false
      metric_name                = "AWSRateBasedRuleMetric"
      sampled_requests_enabled   = false
    }
  }

  tags = {
    Tag1 = "Value1"
    Tag2 = "Value2"
  }

  visibility_config {
    cloudwatch_metrics_enabled = false
    metric_name                = "TerraformWebACLMetric"
    sampled_requests_enabled   = false
  }
}

デプロイ。

terraform apply

TerraformWebACL という ACL が作成れる。

ルールも登録されている。

ALB にアタッチ

aws_wafv2_web_acl_association という Terraform Resource が準備されているが、アタッチは手動でやるケースが多いので割愛。。

参考

Resource: aws_wafv2_web_acl