From 5dfc34a7ece1eee0aa4c6d631983c7bec5c79848 Mon Sep 17 00:00:00 2001 From: Michael Souza Date: Tue, 6 Feb 2018 19:51:30 -0500 Subject: [PATCH] Add support for AWS WAF Geo Match Set. --- aws/provider.go | 1 + aws/resource_aws_waf_geo_match_set.go | 200 +++++++++++ aws/resource_aws_waf_geo_match_set_test.go | 326 ++++++++++++++++++ aws/resource_aws_waf_rule_test.go | 68 ++++ aws/validators.go | 1 + website/aws.erb | 4 + .../docs/r/waf_geo_match_set.html.markdown | 55 +++ website/docs/r/waf_rule.html.markdown | 3 +- 8 files changed, 657 insertions(+), 1 deletion(-) create mode 100644 aws/resource_aws_waf_geo_match_set.go create mode 100644 aws/resource_aws_waf_geo_match_set_test.go create mode 100644 website/docs/r/waf_geo_match_set.html.markdown diff --git a/aws/provider.go b/aws/provider.go index edc26a51f80..ae8a58d3bf0 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -553,6 +553,7 @@ func Provider() terraform.ResourceProvider { "aws_waf_web_acl": resourceAwsWafWebAcl(), "aws_waf_xss_match_set": resourceAwsWafXssMatchSet(), "aws_waf_sql_injection_match_set": resourceAwsWafSqlInjectionMatchSet(), + "aws_waf_geo_match_set": resourceAwsWafGeoMatchSet(), "aws_wafregional_byte_match_set": resourceAwsWafRegionalByteMatchSet(), "aws_wafregional_ipset": resourceAwsWafRegionalIPSet(), "aws_wafregional_xss_match_set": resourceAwsWafRegionalXssMatchSet(), diff --git a/aws/resource_aws_waf_geo_match_set.go b/aws/resource_aws_waf_geo_match_set.go new file mode 100644 index 00000000000..cc5c2dbd104 --- /dev/null +++ b/aws/resource_aws_waf_geo_match_set.go @@ -0,0 +1,200 @@ +package aws + +import ( + "fmt" + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsWafGeoMatchSet() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsWafGeoMatchSetCreate, + Read: resourceAwsWafGeoMatchSetRead, + Update: resourceAwsWafGeoMatchSetUpdate, + Delete: resourceAwsWafGeoMatchSetDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "geo_match_constraint": &schema.Schema{ + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + Type: schema.TypeString, + Required: true, + }, + "value": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceAwsWafGeoMatchSetCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + log.Printf("[INFO] Creating GeoMatchSet: %s", d.Get("name").(string)) + + wr := newWafRetryer(conn, "global") + out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + params := &waf.CreateGeoMatchSetInput{ + ChangeToken: token, + Name: aws.String(d.Get("name").(string)), + } + + return conn.CreateGeoMatchSet(params) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error creating GeoMatchSet: {{err}}", err) + } + resp := out.(*waf.CreateGeoMatchSetOutput) + + d.SetId(*resp.GeoMatchSet.GeoMatchSetId) + + return resourceAwsWafGeoMatchSetUpdate(d, meta) +} + +func resourceAwsWafGeoMatchSetRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + log.Printf("[INFO] Reading GeoMatchSet: %s", d.Get("name").(string)) + params := &waf.GetGeoMatchSetInput{ + GeoMatchSetId: aws.String(d.Id()), + } + + resp, err := conn.GetGeoMatchSet(params) + if err != nil { + if isAWSErr(err, "WAFNonexistentItemException", "") { + log.Printf("[WARN] WAF GeoMatchSet (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + return err + } + + d.Set("name", resp.GeoMatchSet.Name) + d.Set("geo_match_constraint", flattenWafGeoMatchConstraint(resp.GeoMatchSet.GeoMatchConstraints)) + + return nil +} + +func resourceAwsWafGeoMatchSetUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + if d.HasChange("geo_match_constraint") { + o, n := d.GetChange("geo_match_constraint") + oldT, newT := o.(*schema.Set).List(), n.(*schema.Set).List() + + err := updateGeoMatchSetResource(d.Id(), oldT, newT, conn) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating GeoMatchSet: {{err}}", err) + } + } + + return resourceAwsWafGeoMatchSetRead(d, meta) +} + +func resourceAwsWafGeoMatchSetDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafconn + + oldConstraints := d.Get("geo_match_constraint").(*schema.Set).List() + if len(oldConstraints) > 0 { + noConstraints := []interface{}{} + err := updateGeoMatchSetResource(d.Id(), oldConstraints, noConstraints, conn) + if err != nil { + return fmt.Errorf("Error updating GeoMatchConstraint: %s", err) + } + } + + wr := newWafRetryer(conn, "global") + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.DeleteGeoMatchSetInput{ + ChangeToken: token, + GeoMatchSetId: aws.String(d.Id()), + } + + return conn.DeleteGeoMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting GeoMatchSet: {{err}}", err) + } + + return nil +} + +func updateGeoMatchSetResource(id string, oldT, newT []interface{}, conn *waf.WAF) error { + wr := newWafRetryer(conn, "global") + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateGeoMatchSetInput{ + ChangeToken: token, + GeoMatchSetId: aws.String(id), + Updates: diffWafGeoMatchSetConstraints(oldT, newT), + } + + log.Printf("[INFO] Updating GeoMatchSet constraints: %s", req) + return conn.UpdateGeoMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating GeoMatchSet: {{err}}", err) + } + + return nil +} + +func flattenWafGeoMatchConstraint(ts []*waf.GeoMatchConstraint) []interface{} { + out := make([]interface{}, len(ts), len(ts)) + for i, t := range ts { + m := make(map[string]interface{}) + m["type"] = *t.Type + m["value"] = *t.Value + out[i] = m + } + return out +} + +func diffWafGeoMatchSetConstraints(oldT, newT []interface{}) []*waf.GeoMatchSetUpdate { + updates := make([]*waf.GeoMatchSetUpdate, 0) + + for _, od := range oldT { + constraint := od.(map[string]interface{}) + + if idx, contains := sliceContainsMap(newT, constraint); contains { + newT = append(newT[:idx], newT[idx+1:]...) + continue + } + + updates = append(updates, &waf.GeoMatchSetUpdate{ + Action: aws.String(waf.ChangeActionDelete), + GeoMatchConstraint: &waf.GeoMatchConstraint{ + Type: aws.String(constraint["type"].(string)), + Value: aws.String(constraint["value"].(string)), + }, + }) + } + + for _, nd := range newT { + constraint := nd.(map[string]interface{}) + + updates = append(updates, &waf.GeoMatchSetUpdate{ + Action: aws.String(waf.ChangeActionInsert), + GeoMatchConstraint: &waf.GeoMatchConstraint{ + Type: aws.String(constraint["type"].(string)), + Value: aws.String(constraint["value"].(string)), + }, + }) + } + return updates +} diff --git a/aws/resource_aws_waf_geo_match_set_test.go b/aws/resource_aws_waf_geo_match_set_test.go new file mode 100644 index 00000000000..13782a3e2b7 --- /dev/null +++ b/aws/resource_aws_waf_geo_match_set_test.go @@ -0,0 +1,326 @@ +package aws + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/acctest" +) + +func TestAccAWSWafGeoMatchSet_basic(t *testing.T) { + var v waf.GeoMatchSet + geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafGeoMatchSetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &v), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSet), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.value", "US"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.value", "CA"), + ), + }, + }, + }) +} + +func TestAccAWSWafGeoMatchSet_changeNameForceNew(t *testing.T) { + var before, after waf.GeoMatchSet + geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + geoMatchSetNewName := fmt.Sprintf("geoMatchSetNewName-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafGeoMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &before), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSet), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + ), + }, + { + Config: testAccAWSWafGeoMatchSetConfigChangeName(geoMatchSetNewName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &after), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", geoMatchSetNewName), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + ), + }, + }, + }) +} + +func TestAccAWSWafGeoMatchSet_disappears(t *testing.T) { + var v waf.GeoMatchSet + geoMatchSet := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafGeoMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafGeoMatchSetConfig(geoMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &v), + testAccCheckAWSWafGeoMatchSetDisappears(&v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAWSWafGeoMatchSet_changeConstraints(t *testing.T) { + var before, after waf.GeoMatchSet + setName := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafGeoMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafGeoMatchSetConfig(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &before), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.384465307.value", "US"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1991628426.value", "CA"), + ), + }, + { + Config: testAccAWSWafGeoMatchSetConfig_changeConstraints(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &after), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "2"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1174390936.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.1174390936.value", "RU"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.4046309957.type", "Country"), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.4046309957.value", "CN"), + ), + }, + }, + }) +} + +func TestAccAWSWafGeoMatchSet_noConstraints(t *testing.T) { + var ipset waf.GeoMatchSet + setName := fmt.Sprintf("geoMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafGeoMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafGeoMatchSetConfig_noConstraints(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &ipset), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_waf_geo_match_set.geo_match_set", "geo_match_constraint.#", "0"), + ), + }, + }, + }) +} + +func testAccCheckAWSWafGeoMatchSetDisappears(v *waf.GeoMatchSet) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).wafconn + + wr := newWafRetryer(conn, "global") + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateGeoMatchSetInput{ + ChangeToken: token, + GeoMatchSetId: v.GeoMatchSetId, + } + + for _, geoMatchConstraint := range v.GeoMatchConstraints { + geoMatchConstraintUpdate := &waf.GeoMatchSetUpdate{ + Action: aws.String("DELETE"), + GeoMatchConstraint: &waf.GeoMatchConstraint{ + Type: geoMatchConstraint.Type, + Value: geoMatchConstraint.Value, + }, + } + req.Updates = append(req.Updates, geoMatchConstraintUpdate) + } + return conn.UpdateGeoMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating GeoMatchSet: {{err}}", err) + } + + _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + opts := &waf.DeleteGeoMatchSetInput{ + ChangeToken: token, + GeoMatchSetId: v.GeoMatchSetId, + } + return conn.DeleteGeoMatchSet(opts) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting GeoMatchSet: {{err}}", err) + } + return nil + } +} + +func testAccCheckAWSWafGeoMatchSetExists(n string, v *waf.GeoMatchSet) 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 GeoMatchSet ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).wafconn + resp, err := conn.GetGeoMatchSet(&waf.GetGeoMatchSetInput{ + GeoMatchSetId: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + if *resp.GeoMatchSet.GeoMatchSetId == rs.Primary.ID { + *v = *resp.GeoMatchSet + return nil + } + + return fmt.Errorf("WAF GeoMatchSet (%s) not found", rs.Primary.ID) + } +} + +func testAccCheckAWSWafGeoMatchSetDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_waf_geo_match_set" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).wafconn + resp, err := conn.GetGeoMatchSet( + &waf.GetGeoMatchSetInput{ + GeoMatchSetId: aws.String(rs.Primary.ID), + }) + + if err == nil { + if *resp.GeoMatchSet.GeoMatchSetId == rs.Primary.ID { + return fmt.Errorf("WAF GeoMatchSet %s still exists", rs.Primary.ID) + } + } + + // Return nil if the GeoMatchSet is already destroyed + if isAWSErr(err, "WAFNonexistentItemException", "") { + return nil + } + + return err + } + + return nil +} + +func testAccAWSWafGeoMatchSetConfig(name string) string { + return fmt.Sprintf(` +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "%s" + geo_match_constraint { + type = "Country" + value = "US" + } + + geo_match_constraint { + type = "Country" + value = "CA" + } +}`, name) +} + +func testAccAWSWafGeoMatchSetConfigChangeName(name string) string { + return fmt.Sprintf(` +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "%s" + geo_match_constraint { + type = "Country" + value = "US" + } + + geo_match_constraint { + type = "Country" + value = "CA" + } +}`, name) +} + +func testAccAWSWafGeoMatchSetConfig_changeConstraints(name string) string { + return fmt.Sprintf(` +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "%s" + geo_match_constraint { + type = "Country" + value = "RU" + } + + geo_match_constraint { + type = "Country" + value = "CN" + } +}`, name) +} + +func testAccAWSWafGeoMatchSetConfig_noConstraints(name string) string { + return fmt.Sprintf(` +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "%s" +}`, name) +} diff --git a/aws/resource_aws_waf_rule_test.go b/aws/resource_aws_waf_rule_test.go index 456b1f5aab1..21c7b4eb0a0 100644 --- a/aws/resource_aws_waf_rule_test.go +++ b/aws/resource_aws_waf_rule_test.go @@ -137,6 +137,34 @@ func TestAccAWSWafRule_changePredicates(t *testing.T) { }) } +func TestAccAWSWafRule_geoMatchSetPredicate(t *testing.T) { + var geoMatchSet waf.GeoMatchSet + + var v waf.Rule + var idx int + ruleName := fmt.Sprintf("wafrule%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRuleDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRuleConfig_geoMatchSetPredicate(ruleName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafGeoMatchSetExists("aws_waf_geo_match_set.geo_match_set", &geoMatchSet), + testAccCheckAWSWafRuleExists("aws_waf_rule.wafrule", &v), + resource.TestCheckResourceAttr("aws_waf_rule.wafrule", "name", ruleName), + resource.TestCheckResourceAttr("aws_waf_rule.wafrule", "predicates.#", "1"), + computeWafRulePredicateWithGeoMatchSet(&geoMatchSet, true, "GeoMatch", &idx), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule.wafrule", "predicates.%d.negated", &idx, "true"), + testCheckResourceAttrWithIndexesAddr("aws_waf_rule.wafrule", "predicates.%d.type", &idx, "GeoMatch"), + ), + }, + }, + }) +} + // computeWafRulePredicateWithIpSet calculates index // which isn't static because dataId is generated as part of the test func computeWafRulePredicateWithIpSet(ipSet *waf.IPSet, negated bool, pType string, idx *int) resource.TestCheckFunc { @@ -175,6 +203,25 @@ func computeWafRulePredicateWithByteMatchSet(set *waf.ByteMatchSet, negated bool } } +// computeWafRulePredicateWithGeoMatchSet calculates index +// which isn't static because dataId is generated as part of the test +func computeWafRulePredicateWithGeoMatchSet(set *waf.GeoMatchSet, negated bool, pType string, idx *int) resource.TestCheckFunc { + return func(s *terraform.State) error { + predicateResource := resourceAwsWafRule().Schema["predicates"].Elem.(*schema.Resource) + + m := map[string]interface{}{ + "data_id": *set.GeoMatchSetId, + "negated": negated, + "type": pType, + } + + f := schema.HashResource(predicateResource) + *idx = f(m) + + return nil + } +} + func testCheckResourceAttrWithIndexesAddr(name, format string, idx *int, value string) resource.TestCheckFunc { return func(s *terraform.State) error { return resource.TestCheckResourceAttr(name, fmt.Sprintf(format, *idx), value)(s) @@ -393,3 +440,24 @@ resource "aws_waf_rule" "wafrule" { metric_name = "%s" }`, name, name) } + +func testAccAWSWafRuleConfig_geoMatchSetPredicate(name string) string { + return fmt.Sprintf(` +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "%s" + geo_match_constraint { + type = "Country" + value = "US" + } +} + +resource "aws_waf_rule" "wafrule" { + name = "%s" + metric_name = "%s" + predicates { + data_id = "${aws_waf_geo_match_set.geo_match_set.id}" + negated = true + type = "GeoMatch" + } +}`, name, name, name) +} diff --git a/aws/validators.go b/aws/validators.go index bf47509f8c2..79fc3c2f165 100644 --- a/aws/validators.go +++ b/aws/validators.go @@ -1452,6 +1452,7 @@ func validateWafPredicatesType() schema.SchemaValidateFunc { waf.PredicateTypeSqlInjectionMatch, waf.PredicateTypeSizeConstraint, waf.PredicateTypeXssMatch, + waf.PredicateTypeGeoMatch, }, false) } diff --git a/website/aws.erb b/website/aws.erb index d4822a87659..b13c397805b 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1468,6 +1468,10 @@ aws_waf_byte_match_set + > + aws_waf_geo_match_set + + > aws_waf_ipset diff --git a/website/docs/r/waf_geo_match_set.html.markdown b/website/docs/r/waf_geo_match_set.html.markdown new file mode 100644 index 00000000000..2d943a5b9e7 --- /dev/null +++ b/website/docs/r/waf_geo_match_set.html.markdown @@ -0,0 +1,55 @@ +--- +layout: "aws" +page_title: "AWS: waf_geo_match_set" +sidebar_current: "docs-aws-resource-waf-geo-match-set" +description: |- + Provides a AWS WAF GeoMatchSet resource. +--- + +# aws_waf_geo_match_set + +Provides a WAF Geo Match Set Resource + +## Example Usage + +```hcl +resource "aws_waf_geo_match_set" "geo_match_set" { + name = "geo_match_set" + + geo_match_constraint { + type = "Country" + value = "US" + } + + geo_match_constraint { + type = "Country" + value = "CA" + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name or description of the GeoMatchSet. +* `geo_match_constraint` - (Optional) The GeoMatchConstraint objects which contain the country that you want AWS WAF to search for. + +## Nested Blocks + +### `geo_match_constraint` + +#### Arguments + +* `type` - (Required) The type of geographical area you want AWS WAF to search for. Currently Country is the only valid value. +* `value` - (Required) The country that you want AWS WAF to search for. + This is the two-letter country code, e.g. `US`, `CA`, `RU`, `CN`, etc. + See [docs](https://docs.aws.amazon.com/waf/latest/APIReference/API_GeoMatchConstraint.html) for all supported values. + +## Remarks + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the WAF GeoMatchSet. diff --git a/website/docs/r/waf_rule.html.markdown b/website/docs/r/waf_rule.html.markdown index 86ae6693d2d..8876b8c849b 100644 --- a/website/docs/r/waf_rule.html.markdown +++ b/website/docs/r/waf_rule.html.markdown @@ -54,7 +54,8 @@ The following arguments are supported: For example, if an IPSet includes the IP address `192.0.2.44`, AWS WAF will allow or block requests based on that IP address. If set to `true`, AWS WAF will allow, block, or count requests based on all IP addresses _except_ `192.0.2.44`. * `data_id` - (Required) A unique identifier for a predicate in the rule, such as Byte Match Set ID or IPSet ID. -* `type` - (Required) The type of predicate in a rule. Valid value is one of `ByteMatch`, `IPMatch`, `SizeConstraint`, `SqlInjectionMatch` or `XssMatch`. +* `type` - (Required) The type of predicate in a rule. Valid value is one of `ByteMatch`, `IPMatch`, `SizeConstraint`, `SqlInjectionMatch`, or `XssMatch`. + See [docs](https://docs.aws.amazon.com/waf/latest/APIReference/API_Predicate.html) for all supported values. ## Remarks