From 9a4fb4bd09c8cd294e12cefef2a758239af8e1c5 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Fri, 23 Mar 2018 13:47:49 +0000 Subject: [PATCH] New Resource: aws_waf_rule_group --- aws/provider.go | 1 + aws/resource_aws_waf_rule_group.go | 251 ++++++++++++ aws/resource_aws_waf_rule_group_test.go | 424 ++++++++++++++++++++ website/aws.erb | 4 + website/docs/r/waf_rule_group.html.markdown | 58 +++ 5 files changed, 738 insertions(+) create mode 100644 aws/resource_aws_waf_rule_group.go create mode 100644 aws/resource_aws_waf_rule_group_test.go create mode 100644 website/docs/r/waf_rule_group.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 42de2ffeab1e..006b3b7722ef 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -548,6 +548,7 @@ func Provider() terraform.ResourceProvider { "aws_waf_byte_match_set": resourceAwsWafByteMatchSet(), "aws_waf_ipset": resourceAwsWafIPSet(), "aws_waf_rule": resourceAwsWafRule(), + "aws_waf_rule_group": resourceAwsWafRuleGroup(), "aws_waf_rate_based_rule": resourceAwsWafRateBasedRule(), "aws_waf_size_constraint_set": resourceAwsWafSizeConstraintSet(), "aws_waf_web_acl": resourceAwsWafWebAcl(), diff --git a/aws/resource_aws_waf_rule_group.go b/aws/resource_aws_waf_rule_group.go new file mode 100644 index 000000000000..39a37ba1bbf2 --- /dev/null +++ b/aws/resource_aws_waf_rule_group.go @@ -0,0 +1,251 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsWafRuleGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsWafRuleGroupCreate, + Read: resourceAwsWafRuleGroupRead, + Update: resourceAwsWafRuleGroupUpdate, + Delete: resourceAwsWafRuleGroupDelete, + + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "metric_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validateWafMetricName, + }, + "activated_rule": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + MaxItems: 1, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "priority": { + Type: schema.TypeInt, + Required: true, + }, + "rule_id": { + Type: schema.TypeString, + Required: true, + }, + "type": { + Type: schema.TypeString, + Optional: true, + Default: waf.WafRuleTypeRegular, + }, + }, + }, + }, + }, + } +} + +func resourceAwsWafRuleGroupCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + wr := newWafRetryer(conn, "global") + out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + params := &waf.CreateRuleGroupInput{ + ChangeToken: token, + MetricName: aws.String(d.Get("metric_name").(string)), + Name: aws.String(d.Get("name").(string)), + } + + return conn.CreateRuleGroup(params) + }) + if err != nil { + return err + } + resp := out.(*waf.CreateRuleGroupOutput) + d.SetId(*resp.RuleGroup.RuleGroupId) + return resourceAwsWafRuleGroupUpdate(d, meta) +} + +func resourceAwsWafRuleGroupRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + params := &waf.GetRuleGroupInput{ + RuleGroupId: aws.String(d.Id()), + } + + resp, err := conn.GetRuleGroup(params) + if err != nil { + if isAWSErr(err, "WAFNonexistentItemException", "") { + log.Printf("[WARN] WAF Rule Group (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + return err + } + + rResp, err := conn.ListActivatedRulesInRuleGroup(&waf.ListActivatedRulesInRuleGroupInput{ + RuleGroupId: aws.String(d.Id()), + }) + + d.Set("activated_rule", flattenWafActivatedRules(rResp.ActivatedRules)) + d.Set("name", resp.RuleGroup.Name) + d.Set("metric_name", resp.RuleGroup.MetricName) + + return nil +} + +func resourceAwsWafRuleGroupUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + if d.HasChange("activated_rule") { + o, n := d.GetChange("activated_rule") + oldRules, newRules := o.(*schema.Set).List(), n.(*schema.Set).List() + + err := updateWafRuleGroupResource(d.Id(), oldRules, newRules, conn) + if err != nil { + return fmt.Errorf("Error Updating WAF Rule Group: %s", err) + } + } + + return resourceAwsWafRuleGroupRead(d, meta) +} + +func resourceAwsWafRuleGroupDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + oldRules := d.Get("activated_rule").(*schema.Set).List() + err := deleteWafRuleGroup(d.Id(), oldRules, conn) + if err != nil { + return err + } + + return nil +} + +func deleteWafRuleGroup(id string, oldRules []interface{}, conn *waf.WAF) error { + if len(oldRules) > 0 { + noRules := []interface{}{} + err := updateWafRuleGroupResource(id, oldRules, noRules, conn) + if err != nil { + return fmt.Errorf("Error updating WAF Rule Group Predicates: %s", err) + } + } + + wr := newWafRetryer(conn, "global") + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.DeleteRuleGroupInput{ + ChangeToken: token, + RuleGroupId: aws.String(id), + } + log.Printf("[INFO] Deleting WAF Rule Group") + return conn.DeleteRuleGroup(req) + }) + if err != nil { + return fmt.Errorf("Error deleting WAF Rule Group: %s", err) + } + return nil +} + +func updateWafRuleGroupResource(id string, oldRules, newRules []interface{}, conn *waf.WAF) error { + wr := newWafRetryer(conn, "global") + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateRuleGroupInput{ + ChangeToken: token, + RuleGroupId: aws.String(id), + Updates: diffWafRuleGroupActivatedRules(oldRules, newRules), + } + + return conn.UpdateRuleGroup(req) + }) + if err != nil { + return fmt.Errorf("Error Updating WAF Rule Group: %s", err) + } + + return nil +} + +func diffWafRuleGroupActivatedRules(oldRules, newRules []interface{}) []*waf.RuleGroupUpdate { + updates := make([]*waf.RuleGroupUpdate, 0) + + for _, op := range oldRules { + rule := op.(map[string]interface{}) + + if idx, contains := sliceContainsMap(newRules, rule); contains { + newRules = append(newRules[:idx], newRules[idx+1:]...) + continue + } + + updates = append(updates, &waf.RuleGroupUpdate{ + Action: aws.String(waf.ChangeActionDelete), + ActivatedRule: expandWafActivatedRule(rule), + }) + } + + for _, np := range newRules { + rule := np.(map[string]interface{}) + + updates = append(updates, &waf.RuleGroupUpdate{ + Action: aws.String(waf.ChangeActionInsert), + ActivatedRule: expandWafActivatedRule(rule), + }) + } + return updates +} + +func flattenWafActivatedRules(activatedRules []*waf.ActivatedRule) []interface{} { + out := make([]interface{}, len(activatedRules), len(activatedRules)) + for i, ar := range activatedRules { + rule := map[string]interface{}{ + "priority": int(*ar.Priority), + "rule_id": *ar.RuleId, + "type": *ar.Type, + } + if ar.Action != nil { + rule["action"] = []interface{}{ + map[string]interface{}{ + "type": *ar.Action.Type, + }, + } + } + out[i] = rule + } + return out +} + +func expandWafActivatedRule(rule map[string]interface{}) *waf.ActivatedRule { + r := &waf.ActivatedRule{ + Priority: aws.Int64(int64(rule["priority"].(int))), + RuleId: aws.String(rule["rule_id"].(string)), + Type: aws.String(rule["type"].(string)), + } + + if a, ok := rule["action"].([]interface{}); ok && len(a) > 0 { + m := a[0].(map[string]interface{}) + r.Action = &waf.WafAction{ + Type: aws.String(m["type"].(string)), + } + } + return r +} diff --git a/aws/resource_aws_waf_rule_group_test.go b/aws/resource_aws_waf_rule_group_test.go new file mode 100644 index 000000000000..20c69176b939 --- /dev/null +++ b/aws/resource_aws_waf_rule_group_test.go @@ -0,0 +1,424 @@ +package aws + +import ( + "fmt" + "log" + "strings" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +func init() { + resource.AddTestSweepers("aws_waf_rule_group", &resource.Sweeper{ + Name: "aws_waf_rule_group", + F: testSweepWafRuleGroups, + }) +} + +func testSweepWafRuleGroups(region string) error { + client, err := sharedClientForRegion(region) + if err != nil { + return fmt.Errorf("error getting client: %s", err) + } + conn := client.(*AWSClient).wafconn + + req := &waf.ListRuleGroupsInput{} + resp, err := conn.ListRuleGroups(req) + if err != nil { + return fmt.Errorf("Error describing WAF Rule Groups: %s", err) + } + + if len(resp.RuleGroups) == 0 { + log.Print("[DEBUG] No AWS WAF Rule Groups to sweep") + return nil + } + + for _, group := range resp.RuleGroups { + if !strings.HasPrefix(*group.Name, "tfacc") { + continue + } + + rResp, err := conn.ListActivatedRulesInRuleGroup(&waf.ListActivatedRulesInRuleGroupInput{ + RuleGroupId: group.RuleGroupId, + }) + if err != nil { + return err + } + oldRules := flattenWafActivatedRules(rResp.ActivatedRules) + err = deleteWafRuleGroup(*group.RuleGroupId, oldRules, conn) + if err != nil { + return err + } + } + + return nil +} + +func TestAccAWSWafRuleGroup_basic(t *testing.T) { + var rule waf.Rule + var group waf.RuleGroup + var idx int + + ruleName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + groupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRuleGroupDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSWafRuleGroupConfig(ruleName, groupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRuleExists("aws_waf_rule.test", &rule), + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &group), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "name", groupName), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "activated_rule.#", "1"), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "metric_name", groupName), + computeWafActivatedRuleWithRuleId(&rule, "COUNT", 50, &idx), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.action.0.type", &idx, "COUNT"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.priority", &idx, "50"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.type", &idx, waf.WafRuleTypeRegular), + ), + }, + }, + }) +} + +func TestAccAWSWafRuleGroup_changeNameForceNew(t *testing.T) { + var before, after waf.RuleGroup + + ruleName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + groupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + newGroupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafIPSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRuleGroupConfig(ruleName, groupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &before), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "name", groupName), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "activated_rule.#", "1"), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "metric_name", groupName), + ), + }, + { + Config: testAccAWSWafRuleGroupConfig(ruleName, newGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &after), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "name", newGroupName), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "activated_rule.#", "1"), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "metric_name", newGroupName), + ), + }, + }, + }) +} + +func TestAccAWSWafRuleGroup_disappears(t *testing.T) { + var group waf.RuleGroup + ruleName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + groupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRuleGroupConfig(ruleName, groupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &group), + testAccCheckAWSWafRuleGroupDisappears(&group), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSWafRuleGroup_changeActivatedRules(t *testing.T) { + var rule0, rule1, rule2, rule3 waf.Rule + var groupBefore, groupAfter waf.RuleGroup + var idx0, idx1, idx2, idx3 int + + groupName := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + ruleName1 := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + ruleName2 := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + ruleName3 := fmt.Sprintf("tfacc%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRuleGroupConfig(ruleName1, groupName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafRuleExists("aws_waf_rule.test", &rule0), + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &groupBefore), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "name", groupName), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "activated_rule.#", "1"), + computeWafActivatedRuleWithRuleId(&rule0, "COUNT", 50, &idx0), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.action.0.type", &idx0, "COUNT"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.priority", &idx0, "50"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.type", &idx0, waf.WafRuleTypeRegular), + ), + }, + { + Config: testAccAWSWafRuleGroupConfig_changeActivatedRules(ruleName1, ruleName2, ruleName3, groupName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "name", groupName), + resource.TestCheckResourceAttr("aws_waf_rule_group.test", "activated_rule.#", "3"), + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &groupAfter), + + testAccCheckAWSWafRuleExists("aws_waf_rule.test", &rule1), + computeWafActivatedRuleWithRuleId(&rule1, "BLOCK", 10, &idx1), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.action.0.type", &idx1, "BLOCK"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.priority", &idx1, "10"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.type", &idx1, waf.WafRuleTypeRegular), + + testAccCheckAWSWafRuleExists("aws_waf_rule.test2", &rule2), + computeWafActivatedRuleWithRuleId(&rule2, "COUNT", 1, &idx2), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.action.0.type", &idx2, "COUNT"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.priority", &idx2, "1"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.type", &idx2, waf.WafRuleTypeRegular), + + testAccCheckAWSWafRuleExists("aws_waf_rule.test3", &rule3), + computeWafActivatedRuleWithRuleId(&rule3, "BLOCK", 15, &idx3), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.action.0.type", &idx3, "BLOCK"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.priority", &idx3, "15"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule_group.test", "activated_rule.%d.type", &idx3, waf.WafRuleTypeRegular), + ), + }, + }, + }) +} + +// computeWafActivatedRuleWithRuleId calculates index +// which isn't static because ruleId is generated as part of the test +func computeWafActivatedRuleWithRuleId(rule *waf.Rule, actionType string, priority int, idx *int) resource.TestCheckFunc { + return func(s *terraform.State) error { + ruleResource := resourceAwsWafRuleGroup().Schema["activated_rule"].Elem.(*schema.Resource) + + m := map[string]interface{}{ + "action": []interface{}{ + map[string]interface{}{ + "type": actionType, + }, + }, + "priority": priority, + "rule_id": *rule.RuleId, + "type": waf.WafRuleTypeRegular, + } + + f := schema.HashResource(ruleResource) + *idx = f(m) + + return nil + } +} + +func TestAccAWSWafRuleGroup_noActivatedRules(t *testing.T) { + var group waf.RuleGroup + groupName := fmt.Sprintf("test%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRuleGroupConfig_noActivatedRules(groupName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafRuleGroupExists("aws_waf_rule_group.test", &group), + resource.TestCheckResourceAttr( + "aws_waf_rule_group.test", "name", groupName), + resource.TestCheckResourceAttr( + "aws_waf_rule_group.test", "activated_rule.#", "0"), + ), + }, + }, + }) +} + +func testAccCheckAWSWafRuleGroupDisappears(group *waf.RuleGroup) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).wafconn + + rResp, err := conn.ListActivatedRulesInRuleGroup(&waf.ListActivatedRulesInRuleGroupInput{ + RuleGroupId: group.RuleGroupId, + }) + + wr := newWafRetryer(conn, "global") + _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateRuleGroupInput{ + ChangeToken: token, + RuleGroupId: group.RuleGroupId, + } + + for _, rule := range rResp.ActivatedRules { + rule := &waf.RuleGroupUpdate{ + Action: aws.String("DELETE"), + ActivatedRule: rule, + } + req.Updates = append(req.Updates, rule) + } + + return conn.UpdateRuleGroup(req) + }) + if err != nil { + return fmt.Errorf("Error Updating WAF Rule Group: %s", err) + } + + _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + opts := &waf.DeleteRuleGroupInput{ + ChangeToken: token, + RuleGroupId: group.RuleGroupId, + } + return conn.DeleteRuleGroup(opts) + }) + if err != nil { + return fmt.Errorf("Error Deleting WAF Rule Group: %s", err) + } + return nil + } +} + +func testAccCheckAWSWafRuleGroupDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_waf_rule_group" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).wafconn + resp, err := conn.GetRuleGroup(&waf.GetRuleGroupInput{ + RuleGroupId: aws.String(rs.Primary.ID), + }) + + if err == nil { + if *resp.RuleGroup.RuleGroupId == rs.Primary.ID { + return fmt.Errorf("WAF Rule Group %s still exists", rs.Primary.ID) + } + } + + if isAWSErr(err, "WAFNonexistentItemException", "") { + return nil + } + + return err + } + + return nil +} + +func testAccCheckAWSWafRuleGroupExists(n string, group *waf.RuleGroup) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[n] + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.Primary.ID == "" { + return fmt.Errorf("No WAF Rule Group ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).wafconn + resp, err := conn.GetRuleGroup(&waf.GetRuleGroupInput{ + RuleGroupId: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + if *resp.RuleGroup.RuleGroupId == rs.Primary.ID { + *group = *resp.RuleGroup + return nil + } + + return fmt.Errorf("WAF Rule Group (%s) not found", rs.Primary.ID) + } +} + +func testAccAWSWafRuleGroupConfig(ruleName, groupName string) string { + return fmt.Sprintf(` +resource "aws_waf_rule" "test" { + name = "%[1]s" + metric_name = "%[1]s" +} + +resource "aws_waf_rule_group" "test" { + name = "%[2]s" + metric_name = "%[2]s" + activated_rule { + action { + type = "COUNT" + } + priority = 50 + rule_id = "${aws_waf_rule.test.id}" + } +}`, ruleName, groupName) +} + +func testAccAWSWafRuleGroupConfig_changeActivatedRules(ruleName1, ruleName2, ruleName3, groupName string) string { + return fmt.Sprintf(` +resource "aws_waf_rule" "test" { + name = "%[1]s" + metric_name = "%[1]s" +} + +resource "aws_waf_rule" "test2" { + name = "%[2]s" + metric_name = "%[2]s" +} + +resource "aws_waf_rule" "test3" { + name = "%[3]s" + metric_name = "%[3]s" +} + +resource "aws_waf_rule_group" "test" { + name = "%[4]s" + metric_name = "%[4]s" + activated_rule { + action { + type = "BLOCK" + } + priority = 10 + rule_id = "${aws_waf_rule.test.id}" + } + activated_rule { + action { + type = "COUNT" + } + priority = 1 + rule_id = "${aws_waf_rule.test2.id}" + } + activated_rule { + action { + type = "BLOCK" + } + priority = 15 + rule_id = "${aws_waf_rule.test3.id}" + } +}`, ruleName1, ruleName2, ruleName3, groupName) +} + +func testAccAWSWafRuleGroupConfig_noActivatedRules(groupName string) string { + return fmt.Sprintf(` +resource "aws_waf_rule_group" "test" { + name = "%[1]s" + metric_name = "%[1]s" +}`, groupName) +} diff --git a/website/aws.erb b/website/aws.erb index 4b53b411a609..a8cfd58e73a4 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1480,6 +1480,10 @@ aws_waf_rule + > + aws_waf_rule_group + + > aws_waf_rate_based_rule diff --git a/website/docs/r/waf_rule_group.html.markdown b/website/docs/r/waf_rule_group.html.markdown new file mode 100644 index 000000000000..56c807eb089c --- /dev/null +++ b/website/docs/r/waf_rule_group.html.markdown @@ -0,0 +1,58 @@ +--- +layout: "aws" +page_title: "AWS: waf_rule_group" +sidebar_current: "docs-aws-resource-waf-rule-group" +description: |- + Provides a AWS WAF rule group resource. +--- + +# aws_waf_rule_group + +Provides a WAF Rule Group Resource + +## Example Usage + +```hcl +resource "aws_waf_rule" "example" { + name = "example" + metric_name = "example" +} + +resource "aws_waf_rule_group" "example" { + name = "example" + metric_name = "example" + activated_rule { + action { + type = "COUNT" + } + priority = 50 + rule_id = "${aws_waf_rule.example.id}" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) A friendly name of the rule group +* `metric_name` - (Required) A friendly name for the metrics from the rule group +* `activated_rule` - (Optional) A list of activated rules, see below + +## Nested Blocks + +### `activated_rule` + +#### Arguments + +* `action` - (Required) Specifies the action that CloudFront or AWS WAF takes when a web request matches the conditions in the rule. + * `type` - (Required) e.g. `BLOCK`, `ALLOW`, or `COUNT` +* `priority` - (Required) Specifies the order in which the rules are evaluated. Rules with a lower value are evaluated before rules with a higher value. +* `rule_id` - (Required) The ID of a [rule](/docs/r/waf_rule.html) +* `type` - (Optional) The rule type, either [`REGULAR`](/docs/r/waf_rule.html), [`RATE_BASED`]((/docs/r/waf_rate_based_rule.html), or `GROUP`. Defaults to `REGULAR`. + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the WAF rule group.