Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add data sources for Managed Rules for WAF and WAF Regional #10563

Merged
merged 28 commits into from
Aug 3, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
82475b1
d/aws_waf_subscribed_rule_group: Add data source for managed waf rules
flosell Oct 20, 2019
17f4ca3
d/aws_wafregional_subscribed_rule_group: Add data source for managed …
flosell Oct 20, 2019
42b9946
d/aws_wafregional_subscribed_rule_group: Add missing link to aws_wafr…
flosell Jul 26, 2020
d8edf00
d/aws_wafregional_subscribed_rule_group: Add subcategory to documenta…
flosell Jul 26, 2020
fcd9c07
d/aws_wafregional_subscribed_rule_group: Fix whitespace in documentat…
flosell Jul 26, 2020
6d142ca
Move provider.go to internal/provider directory
zhelding Jul 26, 2022
fd4ee62
Merge branch 'main' into d-waf-subscribed-rule-group
zhelding Jul 26, 2022
2c9231c
Relocate WAF subscribed rule group files to service package
zhelding Jul 26, 2022
5195577
Amend package names, imports
zhelding Jul 26, 2022
f464823
Amend CRUD and acceptance test function names
zhelding Jul 26, 2022
8597760
Add WAF subscribed rule group data sources to provider.go
zhelding Jul 26, 2022
55eaf06
Amend acceptance test PreChecks
zhelding Jul 26, 2022
c08e92c
Add find function for WAF subscribed rule groups
zhelding Jul 27, 2022
84db21f
Exclude AWS prefix from environmental variables
zhelding Aug 1, 2022
d8c8ee1
Add environmental variables to dictionary
zhelding Aug 1, 2022
6e305dc
Amend incorrect usage of strconv.ParseBool
zhelding Aug 1, 2022
b24ef60
Integrate find function into data source read
zhelding Aug 1, 2022
a589902
Amend acc test capitalization to comply w/ semgrep
zhelding Aug 1, 2022
f35a5cf
Match WAFRegional subscribed rule group w/ WAF
zhelding Aug 1, 2022
9f635f4
Amend subscribed rule finder check for metricName
zhelding Aug 1, 2022
7e4e465
Run terrrafmt
zhelding Aug 1, 2022
712b681
Add CheckDestroy: nil to acceptance tests
zhelding Aug 1, 2022
6c7a37f
Remove superfluous aws.StringValue() calls
zhelding Aug 1, 2022
d9c1fc8
Amend docs subcategory: WAF -> WAF Classic
zhelding Aug 1, 2022
cc1b832
Merge branch 'main' into pr/flosell/10563
zhelding Aug 2, 2022
7e81e8c
Remove aws.erb file; no longer part of docs
zhelding Aug 2, 2022
4a2bb85
Amend WAF Regional docs sub-category: add Classic
zhelding Aug 2, 2022
6787fc1
Amend find functions; reduce conditionals
zhelding Aug 2, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions docs/contributing/maintaining.md
Original file line number Diff line number Diff line change
Expand Up @@ -412,6 +412,8 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi
| `TF_ACC` | Enables Go tests containing `resource.Test()` and `resource.ParallelTest()`. |
| `TF_ACC_ASSUME_ROLE_ARN` | Amazon Resource Name of existing IAM Role to use for limited permissions acceptance testing. |
| `TF_TEST_CLOUDFRONT_RETAIN` | Flag to disable but dangle CloudFront Distributions during testing to reduce feedback time (must be manually destroyed afterwards) |
| `WAF_SUBSCRIBED_RULE_GROUP_NAME` | Subscribed rule group name for WAF testing. Should be set to the name of an existing subscribed rule group within the account. |
| `WAF_SUBSCRIBED_RULE_GROUP_METRIC_NAME` | The name of the metric measured by the subscribed rule group used for WAF testing. Required as the rule group name is not a unique identifier. |

## Label Dictionary

Expand Down
20 changes: 11 additions & 9 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -887,15 +887,17 @@ func New(_ context.Context) (*schema.Provider, error) {

"aws_transfer_server": transfer.DataSourceServer(),

"aws_waf_ipset": waf.DataSourceIPSet(),
"aws_waf_rule": waf.DataSourceRule(),
"aws_waf_rate_based_rule": waf.DataSourceRateBasedRule(),
"aws_waf_web_acl": waf.DataSourceWebACL(),

"aws_wafregional_ipset": wafregional.DataSourceIPSet(),
"aws_wafregional_rule": wafregional.DataSourceRule(),
"aws_wafregional_rate_based_rule": wafregional.DataSourceRateBasedRule(),
"aws_wafregional_web_acl": wafregional.DataSourceWebACL(),
"aws_waf_ipset": waf.DataSourceIPSet(),
"aws_waf_rule": waf.DataSourceRule(),
"aws_waf_rate_based_rule": waf.DataSourceRateBasedRule(),
"aws_waf_subscribed_rule_group": waf.DataSourceSubscribedRuleGroup(),
"aws_waf_web_acl": waf.DataSourceWebACL(),

"aws_wafregional_ipset": wafregional.DataSourceIPSet(),
"aws_wafregional_rule": wafregional.DataSourceRule(),
"aws_wafregional_rate_based_rule": wafregional.DataSourceRateBasedRule(),
"aws_wafregional_subscribed_rule_group": wafregional.DataSourceSubscribedRuleGroup(),
"aws_wafregional_web_acl": wafregional.DataSourceWebACL(),

"aws_wafv2_ip_set": wafv2.DataSourceIPSet(),
"aws_wafv2_regex_pattern_set": wafv2.DataSourceRegexPatternSet(),
Expand Down
74 changes: 74 additions & 0 deletions internal/service/waf/find.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
package waf

import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/waf"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func FindSubscribedRuleGroupByNameOrMetricName(ctx context.Context, conn *waf.WAF, name string, metricName string) (*waf.SubscribedRuleGroupSummary, error) {
hasName := name != ""
hasMetricName := metricName != ""
hasMatch := false

if !hasName && !hasMetricName {
return nil, errors.New("must specify either name or metricName")
}

input := &waf.ListSubscribedRuleGroupsInput{}

matchingRuleGroup := &waf.SubscribedRuleGroupSummary{}

for {
output, err := conn.ListSubscribedRuleGroupsWithContext(ctx, input)

if tfawserr.ErrCodeContains(err, waf.ErrCodeNonexistentItemException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

for _, ruleGroup := range output.RuleGroups {
respName := aws.StringValue(ruleGroup.Name)
respMetricName := aws.StringValue(ruleGroup.MetricName)

if hasName && respName != name {
continue
}
if hasMetricName && respMetricName != metricName {
continue
}
if hasName && hasMetricName && (name != respName || metricName != respMetricName) {
continue
}
// Previous conditionals catch all non-matches
if hasMatch {
return nil, fmt.Errorf("multiple matches found for name %s and metricName %s", name, metricName)
}

matchingRuleGroup = ruleGroup
hasMatch = true
}

if output.NextMarker == nil {
break
}
input.NextMarker = output.NextMarker
}

if !hasMatch {
return nil, fmt.Errorf("no matches found for name %s and metricName %s", name, metricName)
}

return matchingRuleGroup, nil
}
61 changes: 61 additions & 0 deletions internal/service/waf/subscribed_rule_group.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package waf

import (
"context"
"errors"

"github.com/aws/aws-sdk-go/aws"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-provider-aws/internal/conns"
"github.com/hashicorp/terraform-provider-aws/names"
)

const (
DSNameSubscribedRuleGroup = "Subscribed Rule Group Data Source"
)

func DataSourceSubscribedRuleGroup() *schema.Resource {
return &schema.Resource{
ReadWithoutTimeout: dataSourceSubscribedRuleGroupRead,

Schema: map[string]*schema.Schema{
"name": {
Type: schema.TypeString,
Optional: true,
},
"metric_name": {
Type: schema.TypeString,
Optional: true,
},
},
}
}

func dataSourceSubscribedRuleGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
conn := meta.(*conns.AWSClient).WAFConn
name, nameOk := d.Get("name").(string)
metricName, metricNameOk := d.Get("metric_name").(string)

// Error out if string-assertion fails for either name or metricName
if !nameOk || !metricNameOk {
if !nameOk {
name = DSNameSubscribedRuleGroup
}

err := errors.New("unable to read attributes")
return names.DiagError(names.WAF, names.ErrActionReading, DSNameSubscribedRuleGroup, name, err)
}

output, err := FindSubscribedRuleGroupByNameOrMetricName(ctx, conn, name, metricName)

if err != nil {
return names.DiagError(names.WAF, names.ErrActionReading, DSNameSubscribedRuleGroup, name, err)
}

d.SetId(aws.StringValue(output.RuleGroupId))
d.Set("metric_name", output.MetricName)
d.Set("name", output.Name)

return nil
}
106 changes: 106 additions & 0 deletions internal/service/waf/subscribed_rule_group_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package waf_test

import (
"fmt"
"os"
"regexp"
"testing"

"github.com/aws/aws-sdk-go/service/waf"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-provider-aws/internal/acctest"
)

func TestAccWAFSubscribedRuleGroupDataSource_basic(t *testing.T) {
if os.Getenv("WAF_SUBSCRIBED_RULE_GROUP_NAME") == "" {
t.Skip("Environment variable WAF_SUBSCRIBED_RULE_GROUP_NAME is not set")
}

ruleGroupName := os.Getenv("WAF_SUBSCRIBED_RULE_GROUP_NAME")

if os.Getenv("WAF_SUBSCRIBED_RULE_GROUP_METRIC_NAME") == "" {
t.Skip("Environment variable WAF_SUBSCRIBED_RULE_GROUP_METRIC_NAME is not set")
}

metricName := os.Getenv("WAF_SUBSCRIBED_RULE_GROUP_METRIC_NAME")

datasourceName := "data.aws_waf_subscribed_rule_group.rulegroup"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t); acctest.PreCheckPartitionHasService(waf.EndpointsID, t) },
ErrorCheck: acctest.ErrorCheck(t, waf.EndpointsID),
CheckDestroy: nil,
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccSubscribedRuleGroupDataSourceConfig_nonexistent,
ExpectError: regexp.MustCompile(`no matches found`),
},
{
Config: testAccSubscribedRuleGroupDataSourceConfig_name(ruleGroupName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(datasourceName, "name", ruleGroupName),
resource.TestCheckResourceAttr(datasourceName, "metric_name", metricName),
),
},
{
Config: testAccSubscribedRuleGroupDataSourceConfig_metricName(metricName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(datasourceName, "name", ruleGroupName),
resource.TestCheckResourceAttr(datasourceName, "metric_name", metricName),
),
},
{
Config: testAccSubscribedRuleGroupDataSourceConfig_nameAndMetricName(ruleGroupName, metricName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(datasourceName, "name", ruleGroupName),
resource.TestCheckResourceAttr(datasourceName, "metric_name", metricName),
),
},
{
Config: testAccSubscribedRuleGroupDataSourceConfig_nameAndMismatchingMetricName(ruleGroupName),
ExpectError: regexp.MustCompile(`no matches found`),
},
},
})
}

func testAccSubscribedRuleGroupDataSourceConfig_name(name string) string {
return fmt.Sprintf(`
data "aws_waf_subscribed_rule_group" "rulegroup" {
name = %[1]q
}
`, name)
}

func testAccSubscribedRuleGroupDataSourceConfig_metricName(metricName string) string {
return fmt.Sprintf(`
data "aws_waf_subscribed_rule_group" "rulegroup" {
metric_name = %[1]q
}
`, metricName)
}

func testAccSubscribedRuleGroupDataSourceConfig_nameAndMetricName(name string, metricName string) string {
return fmt.Sprintf(`
data "aws_waf_subscribed_rule_group" "rulegroup" {
name = %[1]q
metric_name = %[2]q
}
`, name, metricName)
}

func testAccSubscribedRuleGroupDataSourceConfig_nameAndMismatchingMetricName(name string) string {
return fmt.Sprintf(`
data "aws_waf_subscribed_rule_group" "rulegroup" {
name = %[1]q
metric_name = "tf-acc-test-does-not-exist"
}
`, name)
}

const testAccSubscribedRuleGroupDataSourceConfig_nonexistent = `
data "aws_waf_subscribed_rule_group" "rulegroup" {
name = "tf-acc-test-does-not-exist"
}
`
68 changes: 68 additions & 0 deletions internal/service/wafregional/find.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,15 @@
package wafregional

import (
"context"
"errors"
"fmt"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/waf"
"github.com/aws/aws-sdk-go/service/wafregional"
"github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

func FindRegexMatchSetByID(conn *wafregional.WAFRegional, id string) (*waf.RegexMatchSet, error) {
Expand All @@ -13,3 +19,65 @@ func FindRegexMatchSetByID(conn *wafregional.WAFRegional, id string) (*waf.Regex

return result.RegexMatchSet, err
}

func FindSubscribedRuleGroupByNameOrMetricName(ctx context.Context, conn *wafregional.WAFRegional, name string, metricName string) (*waf.SubscribedRuleGroupSummary, error) {
hasName := name != ""
hasMetricName := metricName != ""
hasMatch := false

if !hasName && !hasMetricName {
return nil, errors.New("must specify either name or metricName")
}

input := &waf.ListSubscribedRuleGroupsInput{}

matchingRuleGroup := &waf.SubscribedRuleGroupSummary{}

for {
output, err := conn.ListSubscribedRuleGroupsWithContext(ctx, input)

if tfawserr.ErrCodeContains(err, waf.ErrCodeNonexistentItemException) {
return nil, &resource.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

for _, ruleGroup := range output.RuleGroups {
respName := aws.StringValue(ruleGroup.Name)
respMetricName := aws.StringValue(ruleGroup.MetricName)

if hasName && respName != name {
continue
}
if hasMetricName && respMetricName != metricName {
continue
}
if hasName && hasMetricName && (name != respName || metricName != respMetricName) {
continue
}
// Previous conditionals catch all non-matches
if hasMatch {
return nil, fmt.Errorf("multiple matches found for name %s and metricName %s", name, metricName)
}

matchingRuleGroup = ruleGroup
hasMatch = true
}

if output.NextMarker == nil {
break
}
input.NextMarker = output.NextMarker
}

if !hasMatch {
return nil, fmt.Errorf("no matches found for name %s and metricName %s", name, metricName)
}

return matchingRuleGroup, nil
}
Loading