From 4cd7cab63c3b2eca6f862aa7ffb7717b98309ebb Mon Sep 17 00:00:00 2001 From: Danniel Magno Date: Thu, 29 Jun 2017 14:32:24 -0300 Subject: [PATCH 1/2] Add support for aws_wafregional_xss_match_set --- aws/provider.go | 1 + aws/resource_aws_wafregional_xss_match_set.go | 173 +++++++++++++ ...urce_aws_wafregional_xss_match_set_test.go | 235 ++++++++++++++++++ website/aws.erb | 4 + .../r/wafregional_xss_match_set.html.markdown | 47 ++++ 5 files changed, 460 insertions(+) create mode 100644 aws/resource_aws_wafregional_xss_match_set.go create mode 100644 aws/resource_aws_wafregional_xss_match_set_test.go create mode 100644 website/docs/r/wafregional_xss_match_set.html.markdown diff --git a/aws/provider.go b/aws/provider.go index 6aa0203b3ac..f1a1aca0e17 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -554,6 +554,7 @@ func Provider() terraform.ResourceProvider { "aws_waf_sql_injection_match_set": resourceAwsWafSqlInjectionMatchSet(), "aws_wafregional_byte_match_set": resourceAwsWafRegionalByteMatchSet(), "aws_wafregional_ipset": resourceAwsWafRegionalIPSet(), + "aws_wafregional_xss_match_set": resourceAwsWafRegionalXssMatchSet(), "aws_batch_compute_environment": resourceAwsBatchComputeEnvironment(), "aws_batch_job_definition": resourceAwsBatchJobDefinition(), "aws_batch_job_queue": resourceAwsBatchJobQueue(), diff --git a/aws/resource_aws_wafregional_xss_match_set.go b/aws/resource_aws_wafregional_xss_match_set.go new file mode 100644 index 00000000000..8e185267507 --- /dev/null +++ b/aws/resource_aws_wafregional_xss_match_set.go @@ -0,0 +1,173 @@ +package aws + +import ( + "log" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/awserr" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceAwsWafRegionalXssMatchSet() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsWafRegionalXssMatchSetCreate, + Read: resourceAwsWafRegionalXssMatchSetRead, + Update: resourceAwsWafRegionalXssMatchSetUpdate, + Delete: resourceAwsWafRegionalXssMatchSetDelete, + + Schema: map[string]*schema.Schema{ + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "xss_match_tuples": &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_to_match": { + Type: schema.TypeSet, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "data": { + Type: schema.TypeString, + Optional: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + "text_transformation": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + }, + }, + }, + }, + } +} + +func resourceAwsWafRegionalXssMatchSetCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafregionalconn + region := meta.(*AWSClient).region + + log.Printf("[INFO] Creating XssMatchSet: %s", d.Get("name").(string)) + + wr := newWafRegionalRetryer(conn, region) + out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + params := &waf.CreateXssMatchSetInput{ + ChangeToken: token, + Name: aws.String(d.Get("name").(string)), + } + + return conn.CreateXssMatchSet(params) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error creating XssMatchSet: {{err}}", err) + } + resp := out.(*waf.CreateXssMatchSetOutput) + + d.SetId(*resp.XssMatchSet.XssMatchSetId) + + return resourceAwsWafRegionalXssMatchSetUpdate(d, meta) +} + +func resourceAwsWafRegionalXssMatchSetRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafregionalconn + log.Printf("[INFO] Reading XssMatchSet: %s", d.Get("name").(string)) + params := &waf.GetXssMatchSetInput{ + XssMatchSetId: aws.String(d.Id()), + } + + resp, err := conn.GetXssMatchSet(params) + if err != nil { + if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" { + log.Printf("[WARN] WAF IPSet (%s) not found, error code (404)", d.Id()) + d.SetId("") + return nil + } + + return err + } + + d.Set("name", resp.XssMatchSet.Name) + + return nil +} + +func resourceAwsWafRegionalXssMatchSetUpdate(d *schema.ResourceData, meta interface{}) error { + log.Printf("[INFO] Updating XssMatchSet: %s", d.Get("name").(string)) + err := updateXssMatchSetResourceWR(d, meta, waf.ChangeActionInsert) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + } + return resourceAwsWafRegionalXssMatchSetRead(d, meta) +} + +func resourceAwsWafRegionalXssMatchSetDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafregionalconn + region := meta.(*AWSClient).region + + log.Printf("[INFO] Deleting XssMatchSet: %s", d.Get("name").(string)) + err := updateXssMatchSetResourceWR(d, meta, waf.ChangeActionDelete) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + } + + wr := newWafRegionalRetryer(conn, region) + _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.DeleteXssMatchSetInput{ + ChangeToken: token, + XssMatchSetId: aws.String(d.Id()), + } + + return conn.DeleteXssMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + } + + return nil +} + +func updateXssMatchSetResourceWR(d *schema.ResourceData, meta interface{}, ChangeAction string) error { + conn := meta.(*AWSClient).wafregionalconn + region := meta.(*AWSClient).region + + wr := newWafRegionalRetryer(conn, region) + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateXssMatchSetInput{ + ChangeToken: token, + XssMatchSetId: aws.String(d.Id()), + } + + xssMatchTuples := d.Get("xss_match_tuples").(*schema.Set) + for _, xssMatchTuple := range xssMatchTuples.List() { + xmt := xssMatchTuple.(map[string]interface{}) + xssMatchTupleUpdate := &waf.XssMatchSetUpdate{ + Action: aws.String(ChangeAction), + XssMatchTuple: &waf.XssMatchTuple{ + FieldToMatch: expandFieldToMatch(xmt["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})), + TextTransformation: aws.String(xmt["text_transformation"].(string)), + }, + } + req.Updates = append(req.Updates, xssMatchTupleUpdate) + } + + return conn.UpdateXssMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + } + + return nil +} diff --git a/aws/resource_aws_wafregional_xss_match_set_test.go b/aws/resource_aws_wafregional_xss_match_set_test.go new file mode 100644 index 00000000000..752d7632ef0 --- /dev/null +++ b/aws/resource_aws_wafregional_xss_match_set_test.go @@ -0,0 +1,235 @@ +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/aws/awserr" + "github.com/aws/aws-sdk-go/service/waf" + "github.com/hashicorp/errwrap" + "github.com/hashicorp/terraform/helper/acctest" +) + +func TestAccAWSWafRegionalXssMatchSet_basic(t *testing.T) { + var v waf.XssMatchSet + xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalXssMatchSetDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccAWSWafRegionalXssMatchSetConfig(xssMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &v), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSet), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + ), + }, + }, + }) +} + +func TestAccAWSWafRegionalXssMatchSet_changeNameForceNew(t *testing.T) { + var before, after waf.XssMatchSet + xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + xssMatchSetNewName := fmt.Sprintf("xssMatchSetNewName-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalXssMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalXssMatchSetConfig(xssMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &before), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSet), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + ), + }, + { + Config: testAccAWSWafRegionalXssMatchSetConfigChangeName(xssMatchSetNewName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &after), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSetNewName), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + ), + }, + }, + }) +} + +func TestAccAWSWafRegionalXssMatchSet_disappears(t *testing.T) { + var v waf.XssMatchSet + xssMatchSet := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalXssMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalXssMatchSetConfig(xssMatchSet), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &v), + testAccCheckAWSWafRegionalXssMatchSetDisappears(&v), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccCheckAWSWafRegionalXssMatchSetDisappears(v *waf.XssMatchSet) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).wafregionalconn + region := testAccProvider.Meta().(*AWSClient).region + + wr := newWafRegionalRetryer(conn, region) + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { + req := &waf.UpdateXssMatchSetInput{ + ChangeToken: token, + XssMatchSetId: v.XssMatchSetId, + } + + for _, xssMatchTuple := range v.XssMatchTuples { + xssMatchTupleUpdate := &waf.XssMatchSetUpdate{ + Action: aws.String("DELETE"), + XssMatchTuple: &waf.XssMatchTuple{ + FieldToMatch: xssMatchTuple.FieldToMatch, + TextTransformation: xssMatchTuple.TextTransformation, + }, + } + req.Updates = append(req.Updates, xssMatchTupleUpdate) + } + return conn.UpdateXssMatchSet(req) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + } + + _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + opts := &waf.DeleteXssMatchSetInput{ + ChangeToken: token, + XssMatchSetId: v.XssMatchSetId, + } + return conn.DeleteXssMatchSet(opts) + }) + if err != nil { + return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + } + return nil + } +} + +func testAccCheckAWSWafRegionalXssMatchSetExists(n string, v *waf.XssMatchSet) 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 XssMatchSet ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).wafregionalconn + resp, err := conn.GetXssMatchSet(&waf.GetXssMatchSetInput{ + XssMatchSetId: aws.String(rs.Primary.ID), + }) + + if err != nil { + return err + } + + if *resp.XssMatchSet.XssMatchSetId == rs.Primary.ID { + *v = *resp.XssMatchSet + return nil + } + + return fmt.Errorf("WAF XssMatchSet (%s) not found", rs.Primary.ID) + } +} + +func testAccCheckAWSWafRegionalXssMatchSetDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_wafregional_byte_match_set" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).wafregionalconn + resp, err := conn.GetXssMatchSet( + &waf.GetXssMatchSetInput{ + XssMatchSetId: aws.String(rs.Primary.ID), + }) + + if err == nil { + if *resp.XssMatchSet.XssMatchSetId == rs.Primary.ID { + return fmt.Errorf("WAF XssMatchSet %s still exists", rs.Primary.ID) + } + } + + // Return nil if the XssMatchSet is already destroyed + if awsErr, ok := err.(awserr.Error); ok { + if awsErr.Code() == "WAFNonexistentItemException" { + return nil + } + } + + return err + } + + return nil +} + +func testAccAWSWafRegionalXssMatchSetConfig(name string) string { + return fmt.Sprintf(` +resource "aws_wafregional_xss_match_set" "xss_match_set" { + name = "%s" + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "URI" + } + } + + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "QUERY_STRING" + } + } +}`, name) +} + +func testAccAWSWafRegionalXssMatchSetConfigChangeName(name string) string { + return fmt.Sprintf(` +resource "aws_wafregional_xss_match_set" "xss_match_set" { + name = "%s" + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "URI" + } + } + + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "QUERY_STRING" + } + } +}`, name) +} diff --git a/website/aws.erb b/website/aws.erb index 12f5c36fad6..498be4a7550 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -1507,6 +1507,10 @@ aws_wafregional_ipset + > + aws_wafregional_xss_match_set + + diff --git a/website/docs/r/wafregional_xss_match_set.html.markdown b/website/docs/r/wafregional_xss_match_set.html.markdown new file mode 100644 index 00000000000..2692ca3be5d --- /dev/null +++ b/website/docs/r/wafregional_xss_match_set.html.markdown @@ -0,0 +1,47 @@ +--- +layout: "aws" +page_title: "AWS: wafregional_xss_match_set" +sidebar_current: "docs-aws-resource-wafregional-xss-match-set" +description: |- + Provides a AWS WAF Regional XssMatchSet resource for use with ALB. +--- + +# aws\_wafregional\_xss\_match\_set + +Provides a WAF Regional XSS Match Set Resource for use with Application Load Balancer. + +## Example Usage + +``` +resource "aws_wafregional_xss_match_set" "xss_match_set" { + name = "xss_match_set" + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "URI" + } + } + + xss_match_tuples { + text_transformation = "NONE" + field_to_match { + type = "QUERY_STRING" + } + } +} +``` + +## Argument Reference + +The following arguments are supported: + +* `name` - (Required) The name or description of the SizeConstraintSet. +* `xss_match_tuples` - The parts of web requests that you want to inspect for cross-site scripting attacks. + +## Remarks + +## Attributes Reference + +The following attributes are exported: + +* `id` - The ID of the WAF XssMatchSet. From c8c384d95363f6617442d57f433992abb0a9c281 Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Thu, 8 Mar 2018 12:45:31 +0000 Subject: [PATCH 2/2] Implement feedback and clean up code --- aws/resource_aws_wafregional_xss_match_set.go | 80 ++++---- ...urce_aws_wafregional_xss_match_set_test.go | 172 +++++++++++++++--- .../r/wafregional_xss_match_set.html.markdown | 26 ++- 3 files changed, 209 insertions(+), 69 deletions(-) diff --git a/aws/resource_aws_wafregional_xss_match_set.go b/aws/resource_aws_wafregional_xss_match_set.go index 8e185267507..eed3d928b6c 100644 --- a/aws/resource_aws_wafregional_xss_match_set.go +++ b/aws/resource_aws_wafregional_xss_match_set.go @@ -1,12 +1,12 @@ package aws import ( + "fmt" "log" "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" - "github.com/hashicorp/errwrap" + "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/terraform/helper/schema" ) @@ -23,9 +23,9 @@ func resourceAwsWafRegionalXssMatchSet() *schema.Resource { Required: true, ForceNew: true, }, - "xss_match_tuples": &schema.Schema{ + "xss_match_tuple": &schema.Schema{ Type: schema.TypeSet, - Required: true, + Optional: true, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "field_to_match": { @@ -60,7 +60,7 @@ func resourceAwsWafRegionalXssMatchSetCreate(d *schema.ResourceData, meta interf conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region - log.Printf("[INFO] Creating XssMatchSet: %s", d.Get("name").(string)) + log.Printf("[INFO] Creating regional WAF XSS Match Set: %s", d.Get("name").(string)) wr := newWafRegionalRetryer(conn, region) out, err := wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -72,7 +72,7 @@ func resourceAwsWafRegionalXssMatchSetCreate(d *schema.ResourceData, meta interf return conn.CreateXssMatchSet(params) }) if err != nil { - return errwrap.Wrapf("[ERROR] Error creating XssMatchSet: {{err}}", err) + return fmt.Errorf("Failed creating regional WAF XSS Match Set: %s", err) } resp := out.(*waf.CreateXssMatchSetOutput) @@ -83,15 +83,15 @@ func resourceAwsWafRegionalXssMatchSetCreate(d *schema.ResourceData, meta interf func resourceAwsWafRegionalXssMatchSetRead(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).wafregionalconn - log.Printf("[INFO] Reading XssMatchSet: %s", d.Get("name").(string)) + log.Printf("[INFO] Reading regional WAF XSS Match Set: %s", d.Get("name").(string)) params := &waf.GetXssMatchSetInput{ XssMatchSetId: aws.String(d.Id()), } resp, err := conn.GetXssMatchSet(params) if err != nil { - if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "WAFNonexistentItemException" { - log.Printf("[WARN] WAF IPSet (%s) not found, error code (404)", d.Id()) + if isAWSErr(err, wafregional.ErrCodeWAFNonexistentItemException, "") { + log.Printf("[WARN] Regional WAF XSS Match Set (%s) not found, error code (404)", d.Id()) d.SetId("") return nil } @@ -99,17 +99,28 @@ func resourceAwsWafRegionalXssMatchSetRead(d *schema.ResourceData, meta interfac return err } - d.Set("name", resp.XssMatchSet.Name) + set := resp.XssMatchSet + + d.Set("xss_match_tuple", flattenWafXssMatchTuples(set.XssMatchTuples)) + d.Set("name", set.Name) return nil } func resourceAwsWafRegionalXssMatchSetUpdate(d *schema.ResourceData, meta interface{}) error { - log.Printf("[INFO] Updating XssMatchSet: %s", d.Get("name").(string)) - err := updateXssMatchSetResourceWR(d, meta, waf.ChangeActionInsert) - if err != nil { - return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + conn := meta.(*AWSClient).wafregionalconn + region := meta.(*AWSClient).region + + if d.HasChange("xss_match_tuple") { + o, n := d.GetChange("xss_match_tuple") + oldT, newT := o.(*schema.Set).List(), n.(*schema.Set).List() + + err := updateXssMatchSetResourceWR(d.Id(), oldT, newT, conn, region) + if err != nil { + return fmt.Errorf("Failed updating regional WAF XSS Match Set: %s", err) + } } + return resourceAwsWafRegionalXssMatchSetRead(d, meta) } @@ -117,14 +128,19 @@ func resourceAwsWafRegionalXssMatchSetDelete(d *schema.ResourceData, meta interf conn := meta.(*AWSClient).wafregionalconn region := meta.(*AWSClient).region - log.Printf("[INFO] Deleting XssMatchSet: %s", d.Get("name").(string)) - err := updateXssMatchSetResourceWR(d, meta, waf.ChangeActionDelete) - if err != nil { - return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + if v, ok := d.GetOk("xss_match_tuple"); ok { + oldTuples := v.(*schema.Set).List() + if len(oldTuples) > 0 { + noTuples := []interface{}{} + err := updateXssMatchSetResourceWR(d.Id(), oldTuples, noTuples, conn, region) + if err != nil { + return fmt.Errorf("Error updating regional WAF XSS Match Set: %s", err) + } + } } wr := newWafRegionalRetryer(conn, region) - _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { + _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { req := &waf.DeleteXssMatchSetInput{ ChangeToken: token, XssMatchSetId: aws.String(d.Id()), @@ -133,40 +149,26 @@ func resourceAwsWafRegionalXssMatchSetDelete(d *schema.ResourceData, meta interf return conn.DeleteXssMatchSet(req) }) if err != nil { - return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + return fmt.Errorf("Failed deleting regional WAF XSS Match Set: %s", err) } return nil } -func updateXssMatchSetResourceWR(d *schema.ResourceData, meta interface{}, ChangeAction string) error { - conn := meta.(*AWSClient).wafregionalconn - region := meta.(*AWSClient).region - +func updateXssMatchSetResourceWR(id string, oldT, newT []interface{}, conn *wafregional.WAFRegional, region string) error { wr := newWafRegionalRetryer(conn, region) _, err := wr.RetryWithToken(func(token *string) (interface{}, error) { req := &waf.UpdateXssMatchSetInput{ ChangeToken: token, - XssMatchSetId: aws.String(d.Id()), - } - - xssMatchTuples := d.Get("xss_match_tuples").(*schema.Set) - for _, xssMatchTuple := range xssMatchTuples.List() { - xmt := xssMatchTuple.(map[string]interface{}) - xssMatchTupleUpdate := &waf.XssMatchSetUpdate{ - Action: aws.String(ChangeAction), - XssMatchTuple: &waf.XssMatchTuple{ - FieldToMatch: expandFieldToMatch(xmt["field_to_match"].(*schema.Set).List()[0].(map[string]interface{})), - TextTransformation: aws.String(xmt["text_transformation"].(string)), - }, - } - req.Updates = append(req.Updates, xssMatchTupleUpdate) + XssMatchSetId: aws.String(id), + Updates: diffWafXssMatchSetTuples(oldT, newT), } + log.Printf("[INFO] Updating XSS Match Set tuples: %s", req) return conn.UpdateXssMatchSet(req) }) if err != nil { - return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + return fmt.Errorf("Failed updating regional WAF XSS Match Set: %s", err) } return nil diff --git a/aws/resource_aws_wafregional_xss_match_set_test.go b/aws/resource_aws_wafregional_xss_match_set_test.go index 752d7632ef0..cddee2eac61 100644 --- a/aws/resource_aws_wafregional_xss_match_set_test.go +++ b/aws/resource_aws_wafregional_xss_match_set_test.go @@ -4,14 +4,13 @@ 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/aws/awserr" "github.com/aws/aws-sdk-go/service/waf" + "github.com/aws/aws-sdk-go/service/wafregional" "github.com/hashicorp/errwrap" "github.com/hashicorp/terraform/helper/acctest" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" ) func TestAccAWSWafRegionalXssMatchSet_basic(t *testing.T) { @@ -30,7 +29,23 @@ func TestAccAWSWafRegionalXssMatchSet_basic(t *testing.T) { resource.TestCheckResourceAttr( "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSet), resource.TestCheckResourceAttr( - "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "2"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.text_transformation", "NONE"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.3756326843.data", ""), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.3756326843.type", "URI"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.text_transformation", "NONE"), ), }, }, @@ -54,7 +69,7 @@ func TestAccAWSWafRegionalXssMatchSet_changeNameForceNew(t *testing.T) { resource.TestCheckResourceAttr( "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSet), resource.TestCheckResourceAttr( - "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "2"), ), }, { @@ -64,7 +79,7 @@ func TestAccAWSWafRegionalXssMatchSet_changeNameForceNew(t *testing.T) { resource.TestCheckResourceAttr( "aws_wafregional_xss_match_set.xss_match_set", "name", xssMatchSetNewName), resource.TestCheckResourceAttr( - "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuples.#", "2"), + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "2"), ), }, }, @@ -92,6 +107,94 @@ func TestAccAWSWafRegionalXssMatchSet_disappears(t *testing.T) { }) } +func TestAccAWSWafRegionalXssMatchSet_changeTuples(t *testing.T) { + var before, after waf.XssMatchSet + setName := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalXssMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalXssMatchSetConfig(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &before), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "2"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.2316364334.data", ""), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.field_to_match.2316364334.type", "QUERY_STRING"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2018581549.text_transformation", "NONE"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.3756326843.data", ""), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.field_to_match.3756326843.type", "URI"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2786024938.text_transformation", "NONE"), + ), + }, + { + Config: testAccAWSWafRegionalXssMatchSetConfig_changeTuples(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &after), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "2"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2893682529.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2893682529.field_to_match.4253810390.data", "GET"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2893682529.field_to_match.4253810390.type", "METHOD"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.2893682529.text_transformation", "HTML_ENTITY_DECODE"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.4270311415.field_to_match.#", "1"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.4270311415.field_to_match.281401076.data", ""), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.4270311415.field_to_match.281401076.type", "BODY"), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.4270311415.text_transformation", "CMD_LINE"), + ), + }, + }, + }) +} + +func TestAccAWSWafRegionalXssMatchSet_noTuples(t *testing.T) { + var ipset waf.XssMatchSet + setName := fmt.Sprintf("xssMatchSet-%s", acctest.RandString(5)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSWafRegionalXssMatchSetDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSWafRegionalXssMatchSetConfig_noTuples(setName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckAWSWafRegionalXssMatchSetExists("aws_wafregional_xss_match_set.xss_match_set", &ipset), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "name", setName), + resource.TestCheckResourceAttr( + "aws_wafregional_xss_match_set.xss_match_set", "xss_match_tuple.#", "0"), + ), + }, + }, + }) +} + func testAccCheckAWSWafRegionalXssMatchSetDisappears(v *waf.XssMatchSet) resource.TestCheckFunc { return func(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).wafregionalconn @@ -117,7 +220,7 @@ func testAccCheckAWSWafRegionalXssMatchSetDisappears(v *waf.XssMatchSet) resourc return conn.UpdateXssMatchSet(req) }) if err != nil { - return errwrap.Wrapf("[ERROR] Error updating XssMatchSet: {{err}}", err) + return errwrap.Wrapf("[ERROR] Error updating regional WAF XSS Match Set: {{err}}", err) } _, err = wr.RetryWithToken(func(token *string) (interface{}, error) { @@ -128,7 +231,7 @@ func testAccCheckAWSWafRegionalXssMatchSetDisappears(v *waf.XssMatchSet) resourc return conn.DeleteXssMatchSet(opts) }) if err != nil { - return errwrap.Wrapf("[ERROR] Error deleting XssMatchSet: {{err}}", err) + return errwrap.Wrapf("[ERROR] Error deleting regional WAF XSS Match Set: {{err}}", err) } return nil } @@ -142,7 +245,7 @@ func testAccCheckAWSWafRegionalXssMatchSetExists(n string, v *waf.XssMatchSet) r } if rs.Primary.ID == "" { - return fmt.Errorf("No WAF XssMatchSet ID is set") + return fmt.Errorf("No regional WAF XSS Match Set ID is set") } conn := testAccProvider.Meta().(*AWSClient).wafregionalconn @@ -159,13 +262,13 @@ func testAccCheckAWSWafRegionalXssMatchSetExists(n string, v *waf.XssMatchSet) r return nil } - return fmt.Errorf("WAF XssMatchSet (%s) not found", rs.Primary.ID) + return fmt.Errorf("Regional WAF XSS Match Set (%s) not found", rs.Primary.ID) } } func testAccCheckAWSWafRegionalXssMatchSetDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_wafregional_byte_match_set" { + if rs.Type != "aws_wafregional_xss_match_set" { continue } @@ -177,15 +280,13 @@ func testAccCheckAWSWafRegionalXssMatchSetDestroy(s *terraform.State) error { if err == nil { if *resp.XssMatchSet.XssMatchSetId == rs.Primary.ID { - return fmt.Errorf("WAF XssMatchSet %s still exists", rs.Primary.ID) + return fmt.Errorf("Regional WAF XSS Match Set %s still exists", rs.Primary.ID) } } - // Return nil if the XssMatchSet is already destroyed - if awsErr, ok := err.(awserr.Error); ok { - if awsErr.Code() == "WAFNonexistentItemException" { - return nil - } + // Return nil if the regional WAF XSS Match Set is already destroyed + if isAWSErr(err, wafregional.ErrCodeWAFNonexistentItemException, "") { + return nil } return err @@ -198,14 +299,14 @@ func testAccAWSWafRegionalXssMatchSetConfig(name string) string { return fmt.Sprintf(` resource "aws_wafregional_xss_match_set" "xss_match_set" { name = "%s" - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "URI" } } - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "QUERY_STRING" @@ -218,14 +319,14 @@ func testAccAWSWafRegionalXssMatchSetConfigChangeName(name string) string { return fmt.Sprintf(` resource "aws_wafregional_xss_match_set" "xss_match_set" { name = "%s" - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "URI" } } - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "QUERY_STRING" @@ -233,3 +334,30 @@ resource "aws_wafregional_xss_match_set" "xss_match_set" { } }`, name) } + +func testAccAWSWafRegionalXssMatchSetConfig_changeTuples(name string) string { + return fmt.Sprintf(` +resource "aws_wafregional_xss_match_set" "xss_match_set" { + name = "%s" + xss_match_tuple { + text_transformation = "CMD_LINE" + field_to_match { + type = "BODY" + } + } + xss_match_tuple { + text_transformation = "HTML_ENTITY_DECODE" + field_to_match { + type = "METHOD" + data = "GET" + } + } +}`, name) +} + +func testAccAWSWafRegionalXssMatchSetConfig_noTuples(name string) string { + return fmt.Sprintf(` +resource "aws_wafregional_xss_match_set" "xss_match_set" { + name = "%s" +}`, name) +} diff --git a/website/docs/r/wafregional_xss_match_set.html.markdown b/website/docs/r/wafregional_xss_match_set.html.markdown index 2692ca3be5d..e2bd193dd2b 100644 --- a/website/docs/r/wafregional_xss_match_set.html.markdown +++ b/website/docs/r/wafregional_xss_match_set.html.markdown @@ -3,10 +3,10 @@ layout: "aws" page_title: "AWS: wafregional_xss_match_set" sidebar_current: "docs-aws-resource-wafregional-xss-match-set" description: |- - Provides a AWS WAF Regional XssMatchSet resource for use with ALB. + Provides an AWS WAF Regional XSS Match Set resource for use with ALB. --- -# aws\_wafregional\_xss\_match\_set +# aws_wafregional_xss_match_set Provides a WAF Regional XSS Match Set Resource for use with Application Load Balancer. @@ -15,14 +15,14 @@ Provides a WAF Regional XSS Match Set Resource for use with Application Load Bal ``` resource "aws_wafregional_xss_match_set" "xss_match_set" { name = "xss_match_set" - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "URI" } } - xss_match_tuples { + xss_match_tuple { text_transformation = "NONE" field_to_match { type = "QUERY_STRING" @@ -35,13 +35,23 @@ resource "aws_wafregional_xss_match_set" "xss_match_set" { The following arguments are supported: -* `name` - (Required) The name or description of the SizeConstraintSet. -* `xss_match_tuples` - The parts of web requests that you want to inspect for cross-site scripting attacks. +* `name` - (Required) The name of the set +* `xss_match_tuple` - (Optional) The parts of web requests that you want to inspect for cross-site scripting attacks. -## Remarks +### Nested fields + +#### `xss_match_tuple` + +* `field_to_match` - (Required) Specifies where in a web request to look for cross-site scripting attacks. +* `text_transformation` - (Required) Which text transformation, if any, to perform on the web request before inspecting the request for cross-site scripting attacks. + +#### `field_to_match` + +* `data` - (Optional) When the value of `type` is `HEADER`, enter the name of the header that you want the WAF to search, for example, `User-Agent` or `Referer`. If the value of `type` is any other value, omit `data`. +* `type` - (Required) The part of the web request that you want AWS WAF to search for a specified string. e.g. `HEADER` or `METHOD` ## Attributes Reference The following attributes are exported: -* `id` - The ID of the WAF XssMatchSet. +* `id` - The ID of the Regional WAF XSS Match Set.