diff --git a/aws/config.go b/aws/config.go index d9858b2b596..d42325cedd7 100644 --- a/aws/config.go +++ b/aws/config.go @@ -720,7 +720,7 @@ func (c *Config) Client() (interface{}, error) { r.Retryable = aws.Bool(true) } - if r.Operation.Name == "CreateIPSet" || r.Operation.Name == "CreateRegexPatternSet" { + if r.Operation.Name == "CreateIPSet" || r.Operation.Name == "CreateRegexPatternSet" || r.Operation.Name == "CreateRuleGroup" { // WAFv2 supports tag on create which can result in the below error codes according to the documentation if isAWSErr(r.Error, wafv2.ErrCodeWAFTagOperationException, "Retry your request") { r.Retryable = aws.Bool(true) diff --git a/aws/provider.go b/aws/provider.go index 6d17d999c04..2978ccb37ca 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -887,6 +887,7 @@ func Provider() terraform.ResourceProvider { "aws_wafregional_web_acl_association": resourceAwsWafRegionalWebAclAssociation(), "aws_wafv2_ip_set": resourceAwsWafv2IPSet(), "aws_wafv2_regex_pattern_set": resourceAwsWafv2RegexPatternSet(), + "aws_wafv2_rule_group": resourceAwsWafv2RuleGroup(), "aws_worklink_fleet": resourceAwsWorkLinkFleet(), "aws_worklink_website_certificate_authority_association": resourceAwsWorkLinkWebsiteCertificateAuthorityAssociation(), "aws_workspaces_directory": resourceAwsWorkspacesDirectory(), diff --git a/aws/resource_aws_wafv2_rule_group.go b/aws/resource_aws_wafv2_rule_group.go new file mode 100644 index 00000000000..de94a5ea712 --- /dev/null +++ b/aws/resource_aws_wafv2_rule_group.go @@ -0,0 +1,1346 @@ +package aws + +import ( + "fmt" + "log" + "regexp" + "strings" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/wafv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" +) + +func resourceAwsWafv2RuleGroup() *schema.Resource { + return &schema.Resource{ + Create: resourceAwsWafv2RuleGroupCreate, + Read: resourceAwsWafv2RuleGroupRead, + Update: resourceAwsWafv2RuleGroupUpdate, + Delete: resourceAwsWafv2RuleGroupDelete, + Importer: &schema.ResourceImporter{ + State: func(d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) { + idParts := strings.Split(d.Id(), "/") + if len(idParts) != 3 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" { + return nil, fmt.Errorf("Unexpected format of ID (%q), expected ID/NAME/SCOPE", d.Id()) + } + id := idParts[0] + name := idParts[1] + scope := idParts[2] + d.SetId(id) + d.Set("name", name) + d.Set("scope", scope) + return []*schema.ResourceData{d}, nil + }, + }, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "capacity": { + Type: schema.TypeInt, + Required: true, + ForceNew: true, + ValidateFunc: validation.IntAtLeast(1), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 256), + }, + "lock_token": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-_]+$`), "must contain only alphanumeric hyphen and underscore characters"), + ), + }, + "scope": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice([]string{ + wafv2.ScopeCloudfront, + wafv2.ScopeRegional, + }, false), + }, + "rule": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "action": { + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "allow": wafv2EmptySchema(), + "block": wafv2EmptySchema(), + "count": wafv2EmptySchema(), + }, + }, + }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 128), + }, + "priority": { + Type: schema.TypeInt, + Required: true, + }, + "statement": wafv2RootStatementSchema(3), + "visibility_config": wafv2VisibilityConfigSchema(), + }, + }, + }, + "tags": tagsSchema(), + "visibility_config": wafv2VisibilityConfigSchema(), + }, + } +} + +func resourceAwsWafv2RuleGroupCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafv2conn + var resp *wafv2.CreateRuleGroupOutput + + params := &wafv2.CreateRuleGroupInput{ + Name: aws.String(d.Get("name").(string)), + Scope: aws.String(d.Get("scope").(string)), + Capacity: aws.Int64(int64(d.Get("capacity").(int))), + Rules: expandWafv2Rules(d.Get("rule").(*schema.Set).List()), + VisibilityConfig: expandWafv2VisibilityConfig(d.Get("visibility_config").([]interface{})), + } + + if v, ok := d.GetOk("description"); ok { + params.Description = aws.String(v.(string)) + } + + if v := d.Get("tags").(map[string]interface{}); len(v) > 0 { + params.Tags = keyvaluetags.New(v).IgnoreAws().Wafv2Tags() + } + + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + var err error + resp, err = conn.CreateRuleGroup(params) + if err != nil { + if isAWSErr(err, wafv2.ErrCodeWAFUnavailableEntityException, "") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if isResourceTimeoutError(err) { + _, err = conn.CreateRuleGroup(params) + } + + if err != nil { + return fmt.Errorf("Error creating WAFv2 RuleGroup: %s", err) + } + + if resp == nil || resp.Summary == nil { + return fmt.Errorf("Error creating WAFv2 RuleGroup") + } + + d.SetId(aws.StringValue(resp.Summary.Id)) + + return resourceAwsWafv2RuleGroupRead(d, meta) +} + +func resourceAwsWafv2RuleGroupRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafv2conn + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + + params := &wafv2.GetRuleGroupInput{ + Id: aws.String(d.Id()), + Name: aws.String(d.Get("name").(string)), + Scope: aws.String(d.Get("scope").(string)), + } + + resp, err := conn.GetRuleGroup(params) + if err != nil { + if isAWSErr(err, wafv2.ErrCodeWAFNonexistentItemException, "") { + log.Printf("[WARN] WAFv2 RuleGroup (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + return err + } + + if resp == nil || resp.RuleGroup == nil { + return fmt.Errorf("Error getting WAFv2 RuleGroup") + } + + d.Set("name", aws.StringValue(resp.RuleGroup.Name)) + d.Set("capacity", aws.Int64Value(resp.RuleGroup.Capacity)) + d.Set("description", aws.StringValue(resp.RuleGroup.Description)) + d.Set("arn", aws.StringValue(resp.RuleGroup.ARN)) + d.Set("lock_token", aws.StringValue(resp.LockToken)) + + if err := d.Set("rule", flattenWafv2Rules(resp.RuleGroup.Rules)); err != nil { + return fmt.Errorf("Error setting rule: %s", err) + } + + if err := d.Set("visibility_config", flattenWafv2VisibilityConfig(resp.RuleGroup.VisibilityConfig)); err != nil { + return fmt.Errorf("Error setting visibility_config: %s", err) + } + + arn := aws.StringValue(resp.RuleGroup.ARN) + tags, err := keyvaluetags.Wafv2ListTags(conn, arn) + if err != nil { + return fmt.Errorf("Error listing tags for WAFv2 RuleGroup (%s): %s", arn, err) + } + + if err := d.Set("tags", tags.IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("Error setting tags: %s", err) + } + + return nil +} + +func resourceAwsWafv2RuleGroupUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafv2conn + + log.Printf("[INFO] Updating WAFv2 RuleGroup %s", d.Id()) + + u := &wafv2.UpdateRuleGroupInput{ + Id: aws.String(d.Id()), + Name: aws.String(d.Get("name").(string)), + Scope: aws.String(d.Get("scope").(string)), + LockToken: aws.String(d.Get("lock_token").(string)), + Rules: expandWafv2Rules(d.Get("rule").(*schema.Set).List()), + VisibilityConfig: expandWafv2VisibilityConfig(d.Get("visibility_config").([]interface{})), + } + + if v, ok := d.GetOk("description"); ok { + u.Description = aws.String(v.(string)) + } + + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + _, err := conn.UpdateRuleGroup(u) + if err != nil { + if isAWSErr(err, wafv2.ErrCodeWAFUnavailableEntityException, "") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if isResourceTimeoutError(err) { + _, err = conn.UpdateRuleGroup(u) + } + + if err != nil { + return fmt.Errorf("Error updating WAFv2 RuleGroup: %s", err) + } + + if d.HasChange("tags") { + o, n := d.GetChange("tags") + if err := keyvaluetags.Wafv2UpdateTags(conn, d.Get("arn").(string), o, n); err != nil { + return fmt.Errorf("Error updating tags: %s", err) + } + } + + return resourceAwsWafv2RuleGroupRead(d, meta) +} + +func resourceAwsWafv2RuleGroupDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*AWSClient).wafv2conn + + log.Printf("[INFO] Deleting WAFv2 RuleGroup %s", d.Id()) + + r := &wafv2.DeleteRuleGroupInput{ + Id: aws.String(d.Id()), + Name: aws.String(d.Get("name").(string)), + Scope: aws.String(d.Get("scope").(string)), + LockToken: aws.String(d.Get("lock_token").(string)), + } + + err := resource.Retry(5*time.Minute, func() *resource.RetryError { + _, err := conn.DeleteRuleGroup(r) + if err != nil { + if isAWSErr(err, wafv2.ErrCodeWAFAssociatedItemException, "") { + return resource.RetryableError(err) + } + if isAWSErr(err, wafv2.ErrCodeWAFUnavailableEntityException, "") { + return resource.RetryableError(err) + } + return resource.NonRetryableError(err) + } + return nil + }) + + if isResourceTimeoutError(err) { + _, err = conn.DeleteRuleGroup(r) + } + + if err != nil { + return fmt.Errorf("Error deleting WAFv2 RuleGroup: %s", err) + } + + return nil +} + +func wafv2EmptySchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{}, + }, + } +} + +func wafv2RootStatementSchema(level int) *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "and_statement": wafv2StatementSchema(level - 1), + "byte_match_statement": wafv2ByteMatchStatementSchema(), + "geo_match_statement": wafv2GeoMatchStatementSchema(), + "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "not_statement": wafv2StatementSchema(level - 1), + "or_statement": wafv2StatementSchema(level - 1), + "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), + "size_constraint_statement": wafv2SizeConstraintSchema(), + "sqli_match_statement": wafv2SqliMatchStatementSchema(), + "xss_match_statement": wafv2XssMatchStatementSchema(), + }, + }, + } +} + +func wafv2StatementSchema(level int) *schema.Schema { + if level > 1 { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "statement": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "and_statement": wafv2StatementSchema(level - 1), + "byte_match_statement": wafv2ByteMatchStatementSchema(), + "geo_match_statement": wafv2GeoMatchStatementSchema(), + "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "not_statement": wafv2StatementSchema(level - 1), + "or_statement": wafv2StatementSchema(level - 1), + "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), + "size_constraint_statement": wafv2SizeConstraintSchema(), + "sqli_match_statement": wafv2SqliMatchStatementSchema(), + "xss_match_statement": wafv2XssMatchStatementSchema(), + }, + }, + }, + }, + }, + } + } + + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "statement": { + Type: schema.TypeList, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "byte_match_statement": wafv2ByteMatchStatementSchema(), + "geo_match_statement": wafv2GeoMatchStatementSchema(), + "ip_set_reference_statement": wafv2IpSetReferenceStatementSchema(), + "regex_pattern_set_reference_statement": wafv2RegexPatternSetReferenceStatementSchema(), + "size_constraint_statement": wafv2SizeConstraintSchema(), + "sqli_match_statement": wafv2SqliMatchStatementSchema(), + "xss_match_statement": wafv2XssMatchStatementSchema(), + }, + }, + }, + }, + }, + } +} + +func wafv2ByteMatchStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_to_match": wafv2FieldToMatchSchema(), + "positional_constraint": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + wafv2.PositionalConstraintContains, + wafv2.PositionalConstraintContainsWord, + wafv2.PositionalConstraintEndsWith, + wafv2.PositionalConstraintExactly, + wafv2.PositionalConstraintStartsWith, + }, false), + }, + "search_string": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 200), + }, + "text_transformation": wafv2TextTransformationSchema(), + }, + }, + } +} + +func wafv2GeoMatchStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "country_codes": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + }, + }, + } +} + +func wafv2IpSetReferenceStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + }, + }, + } +} + +func wafv2RegexPatternSetReferenceStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + "field_to_match": wafv2FieldToMatchSchema(), + "text_transformation": wafv2TextTransformationSchema(), + }, + }, + } +} + +func wafv2SizeConstraintSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "comparison_operator": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + wafv2.ComparisonOperatorEq, + wafv2.ComparisonOperatorGe, + wafv2.ComparisonOperatorGt, + wafv2.ComparisonOperatorLe, + wafv2.ComparisonOperatorLt, + wafv2.ComparisonOperatorNe, + }, false), + }, + "field_to_match": wafv2FieldToMatchSchema(), + "size": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(0, 21474836480), + }, + "text_transformation": wafv2TextTransformationSchema(), + }, + }, + } +} + +func wafv2SqliMatchStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_to_match": wafv2FieldToMatchSchema(), + "text_transformation": wafv2TextTransformationSchema(), + }, + }, + } +} + +func wafv2XssMatchStatementSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "field_to_match": wafv2FieldToMatchSchema(), + "text_transformation": wafv2TextTransformationSchema(), + }, + }, + } +} + +func wafv2FieldToMatchSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "all_query_arguments": wafv2EmptySchema(), + "body": wafv2EmptySchema(), + "method": wafv2EmptySchema(), + "query_string": wafv2EmptySchema(), + "single_header": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 40), + // The value is returned in lower case by the API. + // Trying to solve it with StateFunc and/or DiffSuppressFunc resulted in hash problem of the rule field or didn't work. + validation.StringMatch(regexp.MustCompile(`^[a-z0-9-_]+$`), "must contain only lowercase alphanumeric characters, underscores, and hyphens"), + ), + }, + }, + }, + }, + "single_query_argument": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 30), + // The value is returned in lower case by the API. + // Trying to solve it with StateFunc and/or DiffSuppressFunc resulted in hash problem of the rule field or didn't work. + validation.StringMatch(regexp.MustCompile(`^[a-z0-9-_]+$`), "must contain only lowercase alphanumeric characters, underscores, and hyphens"), + ), + }, + }, + }, + }, + "uri_path": wafv2EmptySchema(), + }, + }, + } +} + +func wafv2TextTransformationSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeSet, + Required: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "priority": { + Type: schema.TypeInt, + Required: true, + }, + "type": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + wafv2.TextTransformationTypeCmdLine, + wafv2.TextTransformationTypeCompressWhiteSpace, + wafv2.TextTransformationTypeHtmlEntityDecode, + wafv2.TextTransformationTypeLowercase, + wafv2.TextTransformationTypeNone, + wafv2.TextTransformationTypeUrlDecode, + }, false), + }, + }, + }, + } +} + +func wafv2VisibilityConfigSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloudwatch_metrics_enabled": { + Type: schema.TypeBool, + Required: true, + }, + "metric_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 128), + validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9-_]+$`), "must contain only alphanumeric hyphen and underscore characters"), + ), + }, + "sampled_requests_enabled": { + Type: schema.TypeBool, + Required: true, + }, + }, + }, + } +} + +func expandWafv2Rules(l []interface{}) []*wafv2.Rule { + if len(l) == 0 || l[0] == nil { + return nil + } + + rules := make([]*wafv2.Rule, 0) + + for _, rule := range l { + if rule == nil { + continue + } + rules = append(rules, expandWafv2Rule(rule.(map[string]interface{}))) + } + + return rules +} + +func expandWafv2Rule(m map[string]interface{}) *wafv2.Rule { + if m == nil { + return nil + } + + return &wafv2.Rule{ + Name: aws.String(m["name"].(string)), + Priority: aws.Int64(int64(m["priority"].(int))), + Action: expandWafv2RuleAction(m["action"].([]interface{})), + Statement: expandWafv2RootStatement(m["statement"].([]interface{})), + VisibilityConfig: expandWafv2VisibilityConfig(m["visibility_config"].([]interface{})), + } +} + +func expandWafv2RuleAction(l []interface{}) *wafv2.RuleAction { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + action := &wafv2.RuleAction{} + + if v, ok := m["allow"]; ok && len(v.([]interface{})) > 0 { + action.Allow = &wafv2.AllowAction{} + } + + if v, ok := m["block"]; ok && len(v.([]interface{})) > 0 { + action.Block = &wafv2.BlockAction{} + } + + if v, ok := m["count"]; ok && len(v.([]interface{})) > 0 { + action.Count = &wafv2.CountAction{} + } + + return action +} + +func expandWafv2VisibilityConfig(l []interface{}) *wafv2.VisibilityConfig { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + configuration := &wafv2.VisibilityConfig{} + + if v, ok := m["cloudwatch_metrics_enabled"]; ok { + configuration.CloudWatchMetricsEnabled = aws.Bool(v.(bool)) + } + + if v, ok := m["metric_name"]; ok && len(v.(string)) > 0 { + configuration.MetricName = aws.String(v.(string)) + } + + if v, ok := m["sampled_requests_enabled"]; ok { + configuration.SampledRequestsEnabled = aws.Bool(v.(bool)) + } + + return configuration +} + +func expandWafv2RootStatement(l []interface{}) *wafv2.Statement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return expandWafv2Statement(m) +} + +func expandWafv2Statements(l []interface{}) []*wafv2.Statement { + if len(l) == 0 || l[0] == nil { + return nil + } + + statements := make([]*wafv2.Statement, 0) + + for _, statement := range l { + if statement == nil { + continue + } + statements = append(statements, expandWafv2Statement(statement.(map[string]interface{}))) + } + + return statements +} + +func expandWafv2Statement(m map[string]interface{}) *wafv2.Statement { + if m == nil { + return nil + } + + statement := &wafv2.Statement{} + + if v, ok := m["and_statement"]; ok { + statement.AndStatement = expandWafv2AndStatement(v.([]interface{})) + } + + if v, ok := m["byte_match_statement"]; ok { + statement.ByteMatchStatement = expandWafv2ByteMatchStatement(v.([]interface{})) + } + + if v, ok := m["ip_set_reference_statement"]; ok { + statement.IPSetReferenceStatement = expandWafv2IpSetReferenceStatement(v.([]interface{})) + } + + if v, ok := m["geo_match_statement"]; ok { + statement.GeoMatchStatement = expandWafv2GeoMatchStatement(v.([]interface{})) + } + + if v, ok := m["not_statement"]; ok { + statement.NotStatement = expandWafv2NotStatement(v.([]interface{})) + } + + if v, ok := m["or_statement"]; ok { + statement.OrStatement = expandWafv2OrStatement(v.([]interface{})) + } + + if v, ok := m["regex_pattern_set_reference_statement"]; ok { + statement.RegexPatternSetReferenceStatement = expandWafv2RegexPatternSetReferenceStatement(v.([]interface{})) + } + + if v, ok := m["size_constraint_statement"]; ok { + statement.SizeConstraintStatement = expandWafv2SizeConstraintStatement(v.([]interface{})) + } + + if v, ok := m["sqli_match_statement"]; ok { + statement.SqliMatchStatement = expandWafv2SqliMatchStatement(v.([]interface{})) + } + + if v, ok := m["xss_match_statement"]; ok { + statement.XssMatchStatement = expandWafv2XssMatchStatement(v.([]interface{})) + } + + return statement +} + +func expandWafv2AndStatement(l []interface{}) *wafv2.AndStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.AndStatement{ + Statements: expandWafv2Statements(m["statement"].([]interface{})), + } +} + +func expandWafv2ByteMatchStatement(l []interface{}) *wafv2.ByteMatchStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.ByteMatchStatement{ + FieldToMatch: expandWafv2FieldToMatch(m["field_to_match"].([]interface{})), + PositionalConstraint: aws.String(m["positional_constraint"].(string)), + SearchString: []byte(m["search_string"].(string)), + TextTransformations: expandWafv2TextTransformations(m["text_transformation"].(*schema.Set).List()), + } +} + +func expandWafv2FieldToMatch(l []interface{}) *wafv2.FieldToMatch { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + f := &wafv2.FieldToMatch{} + + if v, ok := m["all_query_arguments"]; ok && len(v.([]interface{})) > 0 { + f.AllQueryArguments = &wafv2.AllQueryArguments{} + } + + if v, ok := m["body"]; ok && len(v.([]interface{})) > 0 { + f.Body = &wafv2.Body{} + } + + if v, ok := m["method"]; ok && len(v.([]interface{})) > 0 { + f.Method = &wafv2.Method{} + } + + if v, ok := m["query_string"]; ok && len(v.([]interface{})) > 0 { + f.QueryString = &wafv2.QueryString{} + } + + if v, ok := m["single_header"]; ok && len(v.([]interface{})) > 0 { + f.SingleHeader = expandWafv2SingleHeader(m["single_header"].([]interface{})) + } + + if v, ok := m["single_query_argument"]; ok && len(v.([]interface{})) > 0 { + f.SingleQueryArgument = expandWafv2SingleQueryArgument(m["single_query_argument"].([]interface{})) + } + + if v, ok := m["uri_path"]; ok && len(v.([]interface{})) > 0 { + f.UriPath = &wafv2.UriPath{} + } + + return f +} + +func expandWafv2SingleHeader(l []interface{}) *wafv2.SingleHeader { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.SingleHeader{ + Name: aws.String(m["name"].(string)), + } +} + +func expandWafv2SingleQueryArgument(l []interface{}) *wafv2.SingleQueryArgument { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.SingleQueryArgument{ + Name: aws.String(m["name"].(string)), + } +} + +func expandWafv2TextTransformations(l []interface{}) []*wafv2.TextTransformation { + if len(l) == 0 || l[0] == nil { + return nil + } + + rules := make([]*wafv2.TextTransformation, 0) + + for _, rule := range l { + if rule == nil { + continue + } + rules = append(rules, expandWafv2TextTransformation(rule.(map[string]interface{}))) + } + + return rules +} + +func expandWafv2TextTransformation(m map[string]interface{}) *wafv2.TextTransformation { + if m == nil { + return nil + } + + return &wafv2.TextTransformation{ + Priority: aws.Int64(int64(m["priority"].(int))), + Type: aws.String(m["type"].(string)), + } +} + +func expandWafv2IpSetReferenceStatement(l []interface{}) *wafv2.IPSetReferenceStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.IPSetReferenceStatement{ + ARN: aws.String(m["arn"].(string)), + } +} + +func expandWafv2GeoMatchStatement(l []interface{}) *wafv2.GeoMatchStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.GeoMatchStatement{ + CountryCodes: expandStringList(m["country_codes"].([]interface{})), + } +} + +func expandWafv2NotStatement(l []interface{}) *wafv2.NotStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + s := m["statement"].([]interface{}) + + if len(s) == 0 || s[0] == nil { + return nil + } + + m = s[0].(map[string]interface{}) + + return &wafv2.NotStatement{ + Statement: expandWafv2Statement(m), + } +} + +func expandWafv2OrStatement(l []interface{}) *wafv2.OrStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.OrStatement{ + Statements: expandWafv2Statements(m["statement"].([]interface{})), + } +} + +func expandWafv2RegexPatternSetReferenceStatement(l []interface{}) *wafv2.RegexPatternSetReferenceStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.RegexPatternSetReferenceStatement{ + ARN: aws.String(m["arn"].(string)), + FieldToMatch: expandWafv2FieldToMatch(m["field_to_match"].([]interface{})), + TextTransformations: expandWafv2TextTransformations(m["text_transformation"].(*schema.Set).List()), + } +} + +func expandWafv2SizeConstraintStatement(l []interface{}) *wafv2.SizeConstraintStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.SizeConstraintStatement{ + ComparisonOperator: aws.String(m["comparison_operator"].(string)), + FieldToMatch: expandWafv2FieldToMatch(m["field_to_match"].([]interface{})), + Size: aws.Int64(int64(m["size"].(int))), + TextTransformations: expandWafv2TextTransformations(m["text_transformation"].(*schema.Set).List()), + } +} + +func expandWafv2SqliMatchStatement(l []interface{}) *wafv2.SqliMatchStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.SqliMatchStatement{ + FieldToMatch: expandWafv2FieldToMatch(m["field_to_match"].([]interface{})), + TextTransformations: expandWafv2TextTransformations(m["text_transformation"].(*schema.Set).List()), + } +} + +func expandWafv2XssMatchStatement(l []interface{}) *wafv2.XssMatchStatement { + if len(l) == 0 || l[0] == nil { + return nil + } + + m := l[0].(map[string]interface{}) + + return &wafv2.XssMatchStatement{ + FieldToMatch: expandWafv2FieldToMatch(m["field_to_match"].([]interface{})), + TextTransformations: expandWafv2TextTransformations(m["text_transformation"].(*schema.Set).List()), + } +} + +func flattenWafv2Rules(r []*wafv2.Rule) interface{} { + out := make([]map[string]interface{}, len(r)) + for i, rule := range r { + m := make(map[string]interface{}) + m["action"] = flattenWafv2RuleAction(rule.Action) + m["name"] = aws.StringValue(rule.Name) + m["priority"] = int(aws.Int64Value(rule.Priority)) + m["statement"] = flattenWafv2RootStatement(rule.Statement) + m["visibility_config"] = flattenWafv2VisibilityConfig(rule.VisibilityConfig) + out[i] = m + } + + return out +} + +func flattenWafv2RuleAction(a *wafv2.RuleAction) interface{} { + if a == nil { + return []interface{}{} + } + + m := map[string]interface{}{} + + if a.Allow != nil { + m["allow"] = make([]map[string]interface{}, 1) + } + + if a.Block != nil { + m["block"] = make([]map[string]interface{}, 1) + } + + if a.Count != nil { + m["count"] = make([]map[string]interface{}, 1) + } + + return []interface{}{m} +} + +func flattenWafv2RootStatement(s *wafv2.Statement) interface{} { + if s == nil { + return []interface{}{} + } + + return []interface{}{flattenWafv2Statement(s)} +} + +func flattenWafv2Statements(s []*wafv2.Statement) interface{} { + out := make([]interface{}, len(s)) + for i, statement := range s { + out[i] = flattenWafv2Statement(statement) + } + + return out +} + +func flattenWafv2Statement(s *wafv2.Statement) map[string]interface{} { + if s == nil { + return map[string]interface{}{} + } + + m := map[string]interface{}{} + + if s.AndStatement != nil { + m["and_statement"] = flattenWafv2AndStatement(s.AndStatement) + } + + if s.ByteMatchStatement != nil { + m["byte_match_statement"] = flattenWafv2ByteMatchStatement(s.ByteMatchStatement) + } + + if s.IPSetReferenceStatement != nil { + m["ip_set_reference_statement"] = flattenWafv2IpSetReferenceStatement(s.IPSetReferenceStatement) + } + + if s.GeoMatchStatement != nil { + m["geo_match_statement"] = flattenWafv2GeoMatchStatement(s.GeoMatchStatement) + } + + if s.NotStatement != nil { + m["not_statement"] = flattenWafv2NotStatement(s.NotStatement) + } + + if s.OrStatement != nil { + m["or_statement"] = flattenWafv2OrStatement(s.OrStatement) + } + + if s.RegexPatternSetReferenceStatement != nil { + m["regex_pattern_set_reference_statement"] = flattenWafv2RegexPatternSetReferenceStatement(s.RegexPatternSetReferenceStatement) + } + + if s.SizeConstraintStatement != nil { + m["size_constraint_statement"] = flattenWafv2SizeConstraintStatement(s.SizeConstraintStatement) + } + + if s.SqliMatchStatement != nil { + m["sqli_match_statement"] = flattenWafv2SqliMatchStatement(s.SqliMatchStatement) + } + + if s.XssMatchStatement != nil { + m["xss_match_statement"] = flattenWafv2XssMatchStatement(s.XssMatchStatement) + } + + return m +} + +func flattenWafv2AndStatement(a *wafv2.AndStatement) interface{} { + if a == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "statement": flattenWafv2Statements(a.Statements), + } + + return []interface{}{m} +} + +func flattenWafv2ByteMatchStatement(b *wafv2.ByteMatchStatement) interface{} { + if b == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "field_to_match": flattenWafv2FieldToMatch(b.FieldToMatch), + "positional_constraint": aws.StringValue(b.PositionalConstraint), + "search_string": string(b.SearchString), + "text_transformation": flattenWafv2TextTransformations(b.TextTransformations), + } + + return []interface{}{m} +} + +func flattenWafv2FieldToMatch(f *wafv2.FieldToMatch) interface{} { + if f == nil { + return []interface{}{} + } + + m := map[string]interface{}{} + + if f.AllQueryArguments != nil { + m["all_query_arguments"] = make([]map[string]interface{}, 1) + } + + if f.Body != nil { + m["body"] = make([]map[string]interface{}, 1) + } + + if f.Method != nil { + m["method"] = make([]map[string]interface{}, 1) + } + + if f.QueryString != nil { + m["query_string"] = make([]map[string]interface{}, 1) + } + + if f.SingleHeader != nil { + m["single_header"] = flattenWafv2SingleHeader(f.SingleHeader) + } + + if f.SingleQueryArgument != nil { + m["single_query_argument"] = flattenWafv2SingleQueryArgument(f.SingleQueryArgument) + } + + if f.UriPath != nil { + m["uri_path"] = make([]map[string]interface{}, 1) + } + + return []interface{}{m} +} + +func flattenWafv2SingleHeader(s *wafv2.SingleHeader) interface{} { + if s == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "name": aws.StringValue(s.Name), + } + + return []interface{}{m} +} + +func flattenWafv2SingleQueryArgument(s *wafv2.SingleQueryArgument) interface{} { + if s == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "name": aws.StringValue(s.Name), + } + + return []interface{}{m} +} + +func flattenWafv2TextTransformations(l []*wafv2.TextTransformation) []interface{} { + out := make([]interface{}, len(l)) + for i, t := range l { + m := make(map[string]interface{}) + m["priority"] = int(aws.Int64Value(t.Priority)) + m["type"] = aws.StringValue(t.Type) + out[i] = m + } + return out +} + +func flattenWafv2IpSetReferenceStatement(i *wafv2.IPSetReferenceStatement) interface{} { + if i == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "arn": aws.StringValue(i.ARN), + } + + return []interface{}{m} +} + +func flattenWafv2GeoMatchStatement(g *wafv2.GeoMatchStatement) interface{} { + if g == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "country_codes": flattenStringList(g.CountryCodes), + } + + return []interface{}{m} +} + +func flattenWafv2NotStatement(a *wafv2.NotStatement) interface{} { + if a == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "statement": []interface{}{flattenWafv2Statement(a.Statement)}, + } + + return []interface{}{m} +} + +func flattenWafv2OrStatement(a *wafv2.OrStatement) interface{} { + if a == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "statement": flattenWafv2Statements(a.Statements), + } + + return []interface{}{m} +} + +func flattenWafv2RegexPatternSetReferenceStatement(r *wafv2.RegexPatternSetReferenceStatement) interface{} { + if r == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "arn": aws.StringValue(r.ARN), + "field_to_match": flattenWafv2FieldToMatch(r.FieldToMatch), + "text_transformation": flattenWafv2TextTransformations(r.TextTransformations), + } + + return []interface{}{m} +} + +func flattenWafv2SizeConstraintStatement(s *wafv2.SizeConstraintStatement) interface{} { + if s == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "comparison_operator": aws.StringValue(s.ComparisonOperator), + "field_to_match": flattenWafv2FieldToMatch(s.FieldToMatch), + "size": int(aws.Int64Value(s.Size)), + "text_transformation": flattenWafv2TextTransformations(s.TextTransformations), + } + + return []interface{}{m} +} + +func flattenWafv2SqliMatchStatement(s *wafv2.SqliMatchStatement) interface{} { + if s == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "field_to_match": flattenWafv2FieldToMatch(s.FieldToMatch), + "text_transformation": flattenWafv2TextTransformations(s.TextTransformations), + } + + return []interface{}{m} +} + +func flattenWafv2XssMatchStatement(s *wafv2.XssMatchStatement) interface{} { + if s == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "field_to_match": flattenWafv2FieldToMatch(s.FieldToMatch), + "text_transformation": flattenWafv2TextTransformations(s.TextTransformations), + } + + return []interface{}{m} +} + +func flattenWafv2VisibilityConfig(config *wafv2.VisibilityConfig) interface{} { + if config == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "cloudwatch_metrics_enabled": aws.BoolValue(config.CloudWatchMetricsEnabled), + "metric_name": aws.StringValue(config.MetricName), + "sampled_requests_enabled": aws.BoolValue(config.SampledRequestsEnabled), + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_wafv2_rule_group_test.go b/aws/resource_aws_wafv2_rule_group_test.go new file mode 100644 index 00000000000..55ca8757e20 --- /dev/null +++ b/aws/resource_aws_wafv2_rule_group_test.go @@ -0,0 +1,2488 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/wafv2" + "github.com/hashicorp/terraform-plugin-sdk/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/terraform" +) + +func TestAccAwsWafv2RuleGroup_Basic(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Basic(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_BasicUpdate(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "50"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", "Updated"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.name", "rule-2"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.priority", "10"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.action.0.block.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.action.0.count.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.comparison_operator", "LT"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.field_to_match.0.query_string.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.size", "50"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.text_transformation.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.text_transformation.2212084700.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.text_transformation.2212084700.type", "CMD_LINE"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.text_transformation.4292479961.priority", "5"), + resource.TestCheckResourceAttr(resourceName, "rule.1162901930.statement.0.size_constraint_statement.0.text_transformation.4292479961.type", "NONE"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.name", "rule-1"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.priority", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.count.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_ByteMatchStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.positional_constraint", "CONTAINS"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.search_string", "word"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.text_transformation.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.text_transformation.4292479961.priority", "5"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.text_transformation.4292479961.type", "NONE"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.text_transformation.2156930824.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.3451531458.statement.0.byte_match_statement.0.text_transformation.2156930824.type", "LOWERCASE"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_Update(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.0.positional_constraint", "EXACTLY"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.0.search_string", "sentence"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.0.text_transformation.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.0.text_transformation.766585421.priority", "3"), + resource.TestCheckResourceAttr(resourceName, "rule.3446749900.statement.0.byte_match_statement.0.text_transformation.766585421.type", "CMD_LINE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_ByteMatchStatement_FieldToMatch(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchAllQueryArguments(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2971982489.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchBody(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.body.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.4243272354.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchMethod(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.method.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.1903944126.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchQueryString(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.95492546.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchSingleHeader(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.single_header.0.name", "a-forty-character-long-header-name-40-40"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2127391528.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchSingleQueryArgument(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.0.name", "a-max-30-characters-long-name-"), + resource.TestCheckResourceAttr(resourceName, "rule.492520910.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchUriPath(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.all_query_arguments.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.body.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.method.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.query_string.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.single_header.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.single_query_argument.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.984121555.statement.0.byte_match_statement.0.field_to_match.0.uri_path.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_ChangeNameForceNew(t *testing.T) { + var before, after wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + ruleGroupNewName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Basic(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &before), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_Basic(ruleGroupNewName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &after), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupNewName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupNewName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_ChangeCapacityForceNew(t *testing.T) { + var before, after wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Basic(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &before), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_UpdateCapacity(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &after), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "3"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_ChangeMetricNameForceNew(t *testing.T) { + var before, after wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Basic(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &before), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_UpdateMetricName(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &after), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "updated-friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_Disappears(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Minimal(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccCheckResourceDisappears(testAccProvider, resourceAwsWafv2RuleGroup(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_GeoMatchStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_GeoMatchStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.statement.0.geo_match_statement.0.country_codes.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.statement.0.geo_match_statement.0.country_codes.0", "US"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.statement.0.geo_match_statement.0.country_codes.1", "NL"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_GeoMatchStatement_Update(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.0.geo_match_statement.0.country_codes.#", "3"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.0.geo_match_statement.0.country_codes.0", "ZM"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.0.geo_match_statement.0.country_codes.1", "EE"), + resource.TestCheckResourceAttr(resourceName, "rule.4215509823.statement.0.geo_match_statement.0.country_codes.2", "MM"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_IpSetReferenceStatement(t *testing.T) { + var v wafv2.RuleGroup + var idx int + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_IpSetReferenceStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + computeWafv2IpSetRefStatementIndex(&v, &idx), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.#", &idx, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.0.ip_set_reference_statement.#", &idx, "1"), + testAccMatchResourceAttrArnWithIndexesAddr(resourceName, "rule.%d.statement.0.ip_set_reference_statement.0.arn", &idx, "wafv2", regexp.MustCompile(`regional/ipset/.+$`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_LogicalRuleStatements(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_And(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.867936606.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.867936606.statement.0.and_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.867936606.statement.0.and_statement.0.statement.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.867936606.statement.0.and_statement.0.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.867936606.statement.0.and_statement.0.statement.1.geo_match_statement.#", "1"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_NotAnd(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.0.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.0.statement.0.and_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.0.statement.0.and_statement.0.statement.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.0.statement.0.and_statement.0.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2966210839.statement.0.not_statement.0.statement.0.and_statement.0.statement.1.geo_match_statement.#", "1"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_OrNotAnd(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.0.not_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.0.not_statement.0.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.0.not_statement.0.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.1.and_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.1.and_statement.0.statement.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.1.and_statement.0.statement.0.geo_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.464720012.statement.0.or_statement.0.statement.1.and_statement.0.statement.1.geo_match_statement.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_Minimal(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_Minimal(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "rule.#", "0"), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.cloudwatch_metrics_enabled", "false"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.metric_name", "friendly-metric-name"), + resource.TestCheckResourceAttr(resourceName, "visibility_config.0.sampled_requests_enabled", "false"), + ), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_RegexPatternSetReferenceStatement(t *testing.T) { + var v wafv2.RuleGroup + var idx int + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_RegexPatternSetReferenceStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + computeWafv2RegexSetRefStatementIndex(&v, &idx), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.#", &idx, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.0.regex_pattern_set_reference_statement.#", &idx, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.0.regex_pattern_set_reference_statement.0.field_to_match.#", &idx, "1"), + testCheckResourceAttrWithIndexesAddr(resourceName, "rule.%d.statement.0.regex_pattern_set_reference_statement.0.text_transformation.#", &idx, "1"), + testAccMatchResourceAttrArnWithIndexesAddr(resourceName, "rule.%d.statement.0.regex_pattern_set_reference_statement.0.arn", &idx, "wafv2", regexp.MustCompile(`regional/regexpatternset/.+$`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_RuleAction(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionAllow(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.action.0.allow.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2064993648.action.0.count.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionBlock(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2490412960.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2490412960.action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.2490412960.action.0.block.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2490412960.action.0.count.#", "0"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_RuleActionCount(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "capacity", "2"), + resource.TestCheckResourceAttr(resourceName, "name", ruleGroupName), + resource.TestCheckResourceAttr(resourceName, "description", ""), + resource.TestCheckResourceAttr(resourceName, "scope", wafv2.ScopeRegional), + resource.TestCheckResourceAttr(resourceName, "visibility_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.allow.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.block.#", "0"), + resource.TestCheckResourceAttr(resourceName, "rule.3400404505.action.0.count.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_SizeConstraintStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_SizeConstraintStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.0.comparison_operator", "GT"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.0.size", "100"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.0.field_to_match.0.method.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.204038473.statement.0.size_constraint_statement.0.text_transformation.#", "1"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_SizeConstraintStatement_Update(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.0.comparison_operator", "LT"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.0.size", "50"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.0.field_to_match.0.query_string.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3233602303.statement.0.size_constraint_statement.0.text_transformation.#", "2"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_SqliMatchStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_SqliMatchStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.field_to_match.0.all_query_arguments.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.text_transformation.#", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.text_transformation.1247795808.priority", "5"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.text_transformation.1247795808.type", "URL_DECODE"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.text_transformation.2156930824.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.1169024249.statement.0.sqli_match_statement.0.text_transformation.2156930824.type", "LOWERCASE"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_SqliMatchStatement_Update(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.field_to_match.0.body.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.#", "3"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.1247795808.priority", "5"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.1247795808.type", "URL_DECODE"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.4120379776.priority", "4"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.4120379776.type", "HTML_ENTITY_DECODE"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.1521630275.priority", "3"), + resource.TestCheckResourceAttr(resourceName, "rule.2934928563.statement.0.sqli_match_statement.0.text_transformation.1521630275.type", "COMPRESS_WHITE_SPACE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_Tags(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_OneTag(ruleGroupName, "Tag1", "Value1"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Tag1", "Value1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_TwoTags(ruleGroupName, "Tag1", "Value1Updated", "Tag2", "Value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Tag1", "Value1Updated"), + resource.TestCheckResourceAttr(resourceName, "tags.Tag2", "Value2"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_OneTag(ruleGroupName, "Tag2", "Value2"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Tag2", "Value2"), + ), + }, + }, + }) +} + +func TestAccAwsWafv2RuleGroup_XssMatchStatement(t *testing.T) { + var v wafv2.RuleGroup + ruleGroupName := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "aws_wafv2_rule_group.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAwsWafv2RuleGroupDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAwsWafv2RuleGroupConfig_XssMatchStatement(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.0.field_to_match.0.body.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.0.text_transformation.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.0.text_transformation.2336416342.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.377378487.statement.0.xss_match_statement.0.text_transformation.2336416342.type", "NONE"), + ), + }, + { + Config: testAccAwsWafv2RuleGroupConfig_XssMatchStatement_Update(ruleGroupName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsWafv2RuleGroupExists(resourceName, &v), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "wafv2", regexp.MustCompile(`regional/rulegroup/.+$`)), + resource.TestCheckResourceAttr(resourceName, "rule.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.0.field_to_match.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.0.field_to_match.0.body.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.0.text_transformation.#", "1"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.0.text_transformation.2876362756.priority", "2"), + resource.TestCheckResourceAttr(resourceName, "rule.3452423088.statement.0.xss_match_statement.0.text_transformation.2876362756.type", "URL_DECODE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateIdFunc: testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName), + }, + }, + }) +} + +func testAccMatchResourceAttrArnWithIndexesAddr(name, format string, idx *int, arnService string, arnResourceRegexp *regexp.Regexp) resource.TestCheckFunc { + return func(s *terraform.State) error { + return testAccMatchResourceAttrRegionalARN(name, fmt.Sprintf(format, *idx), "wafv2", arnResourceRegexp)(s) + } +} + +// Calculates the index which isn't static because ARN is generated as part of the test +func computeWafv2IpSetRefStatementIndex(r *wafv2.RuleGroup, idx *int) resource.TestCheckFunc { + return func(s *terraform.State) error { + ruleResource := resourceAwsWafv2RuleGroup().Schema["rule"].Elem.(*schema.Resource) + + rule := map[string]interface{}{ + "name": "rule-1", + "priority": 1, + "action": []interface{}{ + map[string]interface{}{ + "allow": make([]interface{}, 1), + "block": []interface{}{}, + "count": []interface{}{}, + }, + }, + "statement": []interface{}{ + map[string]interface{}{ + "and_statement": []interface{}{}, + "byte_match_statement": []interface{}{}, + "geo_match_statement": []interface{}{}, + "ip_set_reference_statement": []interface{}{ + map[string]interface{}{ + "arn": aws.StringValue(r.Rules[0].Statement.IPSetReferenceStatement.ARN), + }, + }, + "not_statement": []interface{}{}, + "or_statement": []interface{}{}, + "regex_pattern_set_reference_statement": []interface{}{}, + "size_constraint_statement": []interface{}{}, + "sqli_match_statement": []interface{}{}, + "xss_match_statement": []interface{}{}, + }, + }, + "visibility_config": []interface{}{ + map[string]interface{}{ + "cloudwatch_metrics_enabled": false, + "metric_name": "friendly-rule-metric-name", + "sampled_requests_enabled": false, + }, + }, + } + + f := schema.HashResource(ruleResource) + *idx = f(rule) + + return nil + } +} + +// Calculates the index which isn't static because ARN is generated as part of the test +func computeWafv2RegexSetRefStatementIndex(r *wafv2.RuleGroup, idx *int) resource.TestCheckFunc { + return func(s *terraform.State) error { + ruleResource := resourceAwsWafv2RuleGroup().Schema["rule"].Elem.(*schema.Resource) + textTransformationResource := ruleResource.Schema["statement"].Elem.(*schema.Resource).Schema["regex_pattern_set_reference_statement"].Elem.(*schema.Resource).Schema["text_transformation"].Elem.(*schema.Resource) + rule := map[string]interface{}{ + "name": "rule-1", + "priority": 1, + "action": []interface{}{ + map[string]interface{}{ + "allow": make([]interface{}, 1), + "block": []interface{}{}, + "count": []interface{}{}, + }, + }, + "statement": []interface{}{ + map[string]interface{}{ + "and_statement": []interface{}{}, + "byte_match_statement": []interface{}{}, + "geo_match_statement": []interface{}{}, + "ip_set_reference_statement": []interface{}{}, + "not_statement": []interface{}{}, + "or_statement": []interface{}{}, + "regex_pattern_set_reference_statement": []interface{}{ + map[string]interface{}{ + "arn": aws.StringValue(r.Rules[0].Statement.RegexPatternSetReferenceStatement.ARN), + "field_to_match": []interface{}{ + map[string]interface{}{ + "all_query_arguments": []interface{}{}, + "body": make([]interface{}, 1), + "method": []interface{}{}, + "query_string": []interface{}{}, + "single_header": []interface{}{}, + "single_query_argument": []interface{}{}, + "uri_path": []interface{}{}, + }, + }, + "text_transformation": schema.NewSet(schema.HashResource(textTransformationResource), []interface{}{ + map[string]interface{}{ + "priority": 2, + "type": "NONE", + }, + }), + }, + }, + "size_constraint_statement": []interface{}{}, + "sqli_match_statement": []interface{}{}, + "xss_match_statement": []interface{}{}, + }, + }, + "visibility_config": []interface{}{ + map[string]interface{}{ + "cloudwatch_metrics_enabled": false, + "metric_name": "friendly-rule-metric-name", + "sampled_requests_enabled": false, + }, + }, + } + + f := schema.HashResource(ruleResource) + *idx = f(rule) + + return nil + } +} + +func testAccCheckAwsWafv2RuleGroupDestroy(s *terraform.State) error { + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_wafv2_rule_group" { + continue + } + + conn := testAccProvider.Meta().(*AWSClient).wafv2conn + resp, err := conn.GetRuleGroup( + &wafv2.GetRuleGroupInput{ + Id: aws.String(rs.Primary.ID), + Name: aws.String(rs.Primary.Attributes["name"]), + Scope: aws.String(rs.Primary.Attributes["scope"]), + }) + + if err == nil { + if resp == nil || resp.RuleGroup == nil { + return fmt.Errorf("Error getting WAFv2 RuleGroup") + } + + if aws.StringValue(resp.RuleGroup.Id) == rs.Primary.ID { + return fmt.Errorf("WAFv2 RuleGroup %s still exists", rs.Primary.ID) + } + + return nil + } + + // Return nil if the RuleGroup is already destroyed + if isAWSErr(err, wafv2.ErrCodeWAFNonexistentItemException, "") { + return nil + } + + return err + } + + return nil +} + +func testAccCheckAwsWafv2RuleGroupExists(n string, v *wafv2.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 WAFv2 RuleGroup ID is set") + } + + conn := testAccProvider.Meta().(*AWSClient).wafv2conn + resp, err := conn.GetRuleGroup(&wafv2.GetRuleGroupInput{ + Id: aws.String(rs.Primary.ID), + Name: aws.String(rs.Primary.Attributes["name"]), + Scope: aws.String(rs.Primary.Attributes["scope"]), + }) + + if err != nil { + return err + } + + if resp == nil || resp.RuleGroup == nil { + return fmt.Errorf("Error getting WAFv2 RuleGroup") + } + + if aws.StringValue(resp.RuleGroup.Id) == rs.Primary.ID { + *v = *resp.RuleGroup + return nil + } + + return fmt.Errorf("WAFv2 RuleGroup (%s) not found", rs.Primary.ID) + } +} + +func testAccAwsWafv2RuleGroupConfig_Basic(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + description = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, name) +} + +func testAccAwsWafv2RuleGroupConfig_BasicUpdate(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 50 + name = "%s" + description = "Updated" + scope = "REGIONAL" + + rule { + name = "rule-2" + priority = 10 + + action { + block {} + } + + statement { + size_constraint_statement { + comparison_operator = "LT" + size = 50 + + field_to_match { + query_string {} + } + + text_transformation { + priority = 5 + type = "NONE" + } + + text_transformation { + priority = 2 + type = "CMD_LINE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + rule { + name = "rule-1" + priority = 1 + + action { + count {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_UpdateCapacity(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 3 + name = "%s" + description = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, name) +} + +func testAccAwsWafv2RuleGroupConfig_UpdateMetricName(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + description = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "updated-friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, name) +} + +func testAccAwsWafv2RuleGroupConfig_Minimal(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_RuleActionAllow(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_RuleActionBlock(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + block {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_RuleActionCount(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + count {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 300 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + all_query_arguments {} + } + + text_transformation { + priority = 5 + type = "NONE" + } + + text_transformation { + priority = 2 + type = "LOWERCASE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_Update(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 30 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "EXACTLY" + search_string = "sentence" + + field_to_match { + all_query_arguments {} + } + + text_transformation { + priority = 3 + type = "CMD_LINE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchAllQueryArguments(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 30 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + all_query_arguments {} + } + + text_transformation { + priority = 5 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchBody(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 15 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + body {} + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchMethod(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 15 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + method {} + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchQueryString(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 15 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + query_string {} + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchSingleHeader(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 15 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + single_header { + name = "a-forty-character-long-header-name-40-40" + } + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchSingleQueryArgument(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 30 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + single_query_argument { + name = "a-max-30-characters-long-name-" + } + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_ByteMatchStatement_FieldToMatchUriPath(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 15 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + byte_match_statement { + positional_constraint = "CONTAINS" + search_string = "word" + + field_to_match { + uri_path {} + } + + text_transformation { + priority = 1 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_IpSetReferenceStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_ip_set" "test" { + name = "ip-set-%s" + scope = "REGIONAL" + ip_address_version = "IPV4" + addresses = ["1.1.1.1/32", "2.2.2.2/32"] +} + +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + ip_set_reference_statement { + arn = aws_wafv2_ip_set.test.arn + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, name) +} + +func testAccAwsWafv2RuleGroupConfig_GeoMatchStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + geo_match_statement { + country_codes = ["US", "NL"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_GeoMatchStatement_Update(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + geo_match_statement { + country_codes = ["ZM", "EE", "MM"] + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_And(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + and_statement { + statement { + geo_match_statement { + country_codes = ["US"] + } + } + statement { + geo_match_statement { + country_codes = ["NL"] + } + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_NotAnd(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + not_statement { + statement { + and_statement { + statement { + geo_match_statement { + country_codes = ["US"] + } + } + statement { + geo_match_statement { + country_codes = ["NL"] + } + } + } + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_LogicalRuleStatement_OrNotAnd(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 3 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + or_statement { + statement { + not_statement { + statement { + geo_match_statement { + country_codes = ["DE"] + } + } + } + } + statement { + and_statement { + statement { + geo_match_statement { + country_codes = ["US"] + } + } + statement { + geo_match_statement { + country_codes = ["NL"] + } + } + } + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_RegexPatternSetReferenceStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_regex_pattern_set" "test" { + name = "regex-pattern-set-%s" + scope = "REGIONAL" + + regular_expression { + regex_string = "one" + } +} + +resource "aws_wafv2_rule_group" "test" { + capacity = 50 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + regex_pattern_set_reference_statement { + arn = aws_wafv2_regex_pattern_set.test.arn + + field_to_match { + body {} + } + + text_transformation { + priority = 2 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name, name) +} + +func testAccAwsWafv2RuleGroupConfig_SizeConstraintStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 30 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + size_constraint_statement { + comparison_operator = "GT" + size = 100 + + field_to_match { + method {} + } + + text_transformation { + priority = 5 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_SizeConstraintStatement_Update(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 30 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + size_constraint_statement { + comparison_operator = "LT" + size = 50 + + field_to_match { + query_string {} + } + + text_transformation { + priority = 5 + type = "NONE" + } + + text_transformation { + priority = 2 + type = "CMD_LINE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_SqliMatchStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 300 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + sqli_match_statement { + field_to_match { + all_query_arguments {} + } + + text_transformation { + priority = 5 + type = "URL_DECODE" + } + + text_transformation { + priority = 2 + type = "LOWERCASE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_SqliMatchStatement_Update(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 300 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + sqli_match_statement { + field_to_match { + body {} + } + + text_transformation { + priority = 5 + type = "URL_DECODE" + } + + text_transformation { + priority = 4 + type = "HTML_ENTITY_DECODE" + } + + text_transformation { + priority = 3 + type = "COMPRESS_WHITE_SPACE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_XssMatchStatement(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 300 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + block {} + } + + statement { + xss_match_statement { + + field_to_match { + body {} + } + + text_transformation { + priority = 2 + type = "NONE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_XssMatchStatement_Update(name string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 300 + name = "%s" + scope = "REGIONAL" + + rule { + name = "rule-1" + priority = 1 + + action { + allow {} + } + + statement { + xss_match_statement { + field_to_match { + body {} + } + + text_transformation { + priority = 2 + type = "URL_DECODE" + } + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-rule-metric-name" + sampled_requests_enabled = false + } + } + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } +} +`, name) +} + +func testAccAwsWafv2RuleGroupConfig_OneTag(name, tagKey, tagValue string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + description = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } + + tags = { + "%s" = "%s" + } +} +`, name, name, tagKey, tagValue) +} + +func testAccAwsWafv2RuleGroupConfig_TwoTags(name, tag1Key, tag1Value, tag2Key, tag2Value string) string { + return fmt.Sprintf(` +resource "aws_wafv2_rule_group" "test" { + capacity = 2 + name = "%s" + description = "%s" + scope = "REGIONAL" + + visibility_config { + cloudwatch_metrics_enabled = false + metric_name = "friendly-metric-name" + sampled_requests_enabled = false + } + + tags = { + "%s" = "%s" + "%s" = "%s" + } +} +`, name, name, tag1Key, tag1Value, tag2Key, tag2Value) +} + +func testAccAwsWafv2RuleGroupImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s/%s", rs.Primary.ID, rs.Primary.Attributes["name"], rs.Primary.Attributes["scope"]), nil + } +} diff --git a/website/aws.erb b/website/aws.erb index 883dddb4d6a..d7191bed5b3 100644 --- a/website/aws.erb +++ b/website/aws.erb @@ -3574,6 +3574,9 @@