Skip to content

Commit

Permalink
Merge pull request #18733 from gazoakley/f-route53resolver-firewall-c…
Browse files Browse the repository at this point in the history
…onfig

resource/aws_route53_resolver_firewall_config: Add new resource
  • Loading branch information
ewbankkit authored Jun 16, 2021
2 parents c56ecd3 + a45c360 commit 7564614
Show file tree
Hide file tree
Showing 6 changed files with 400 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/18733.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_route53_resolver_firewall_config
```
34 changes: 34 additions & 0 deletions aws/internal/service/route53resolver/finder/finder.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package finder
import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53resolver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
tfroute53resolver "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver"
)

Expand Down Expand Up @@ -116,6 +117,39 @@ func FirewallDomainListByID(conn *route53resolver.Route53Resolver, firewallDomai
return output.FirewallDomainList, nil
}

// FirewallConfigByID returns the dnssec configuration corresponding to the specified ID.
// Returns NotFoundError if no configuration is found.
func FirewallConfigByID(conn *route53resolver.Route53Resolver, firewallConfigID string) (*route53resolver.FirewallConfig, error) {
input := &route53resolver.ListFirewallConfigsInput{}

var config *route53resolver.FirewallConfig
// GetFirewallConfigs does not support query with id
err := conn.ListFirewallConfigsPages(input, func(page *route53resolver.ListFirewallConfigsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, c := range page.FirewallConfigs {
if aws.StringValue(c.Id) == firewallConfigID {
config = c
return false
}
}

return !lastPage
})

if err != nil {
return nil, err
}

if config == nil {
return nil, &resource.NotFoundError{}
}

return config, nil
}

// FirewallRuleByID returns the DNS Firewall rule corresponding to the specified rule group and domain list IDs.
// Returns nil if no DNS Firewall rule is found.
func FirewallRuleByID(conn *route53resolver.Route53Resolver, firewallRuleId string) (*route53resolver.FirewallRule, error) {
Expand Down
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -963,6 +963,7 @@ func Provider() *schema.Provider {
"aws_route53_health_check": resourceAwsRoute53HealthCheck(),
"aws_route53_resolver_dnssec_config": resourceAwsRoute53ResolverDnssecConfig(),
"aws_route53_resolver_endpoint": resourceAwsRoute53ResolverEndpoint(),
"aws_route53_resolver_firewall_config": resourceAwsRoute53ResolverFirewallConfig(),
"aws_route53_resolver_firewall_domain_list": resourceAwsRoute53ResolverFirewallDomainList(),
"aws_route53_resolver_firewall_rule": resourceAwsRoute53ResolverFirewallRule(),
"aws_route53_resolver_firewall_rule_group": resourceAwsRoute53ResolverFirewallRuleGroup(),
Expand Down
125 changes: 125 additions & 0 deletions aws/resource_aws_route53_resolver_firewall_config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
package aws

import (
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53resolver"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func resourceAwsRoute53ResolverFirewallConfig() *schema.Resource {
return &schema.Resource{
Create: resourceAwsRoute53ResolverFirewallConfigCreate,
Read: resourceAwsRoute53ResolverFirewallConfigRead,
Update: resourceAwsRoute53ResolverFirewallConfigUpdate,
Delete: resourceAwsRoute53ResolverFirewallConfigDelete,
Importer: &schema.ResourceImporter{
State: schema.ImportStatePassthrough,
},

Schema: map[string]*schema.Schema{
"owner_id": {
Type: schema.TypeString,
Computed: true,
},

"resource_id": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"firewall_fail_open": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(route53resolver.FirewallFailOpenStatus_Values(), false),
},
},
}
}

func resourceAwsRoute53ResolverFirewallConfigCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).route53resolverconn

input := &route53resolver.UpdateFirewallConfigInput{
ResourceId: aws.String(d.Get("resource_id").(string)),
}

if v, ok := d.GetOk("firewall_fail_open"); ok {
input.FirewallFailOpen = aws.String(v.(string))
}

log.Printf("[DEBUG] Creating Route 53 Resolver DNS Firewall config: %#v", input)
output, err := conn.UpdateFirewallConfig(input)
if err != nil {
return fmt.Errorf("error creating Route 53 Resolver DNS Firewall config: %w", err)
}

d.SetId(aws.StringValue(output.FirewallConfig.Id))

return resourceAwsRoute53ResolverFirewallConfigRead(d, meta)
}

func resourceAwsRoute53ResolverFirewallConfigRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).route53resolverconn

config, err := finder.FirewallConfigByID(conn, d.Id())

if !d.IsNewResource() && tfresource.NotFound(err) {
log.Printf("[WARN] Route 53 Resolver DNS Firewall config (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error getting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err)
}

d.Set("owner_id", config.OwnerId)
d.Set("resource_id", config.ResourceId)
d.Set("firewall_fail_open", config.FirewallFailOpen)

return nil
}

func resourceAwsRoute53ResolverFirewallConfigUpdate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).route53resolverconn

input := &route53resolver.UpdateFirewallConfigInput{
ResourceId: aws.String(d.Get("resource_id").(string)),
}

if v, ok := d.GetOk("firewall_fail_open"); ok {
input.FirewallFailOpen = aws.String(v.(string))
}

log.Printf("[DEBUG] Updating Route 53 Resolver DNS Firewall config: %#v", input)
_, err := conn.UpdateFirewallConfig(input)
if err != nil {
return fmt.Errorf("error creating Route 53 Resolver DNS Firewall config: %w", err)
}

return resourceAwsRoute53ResolverFirewallConfigRead(d, meta)
}

func resourceAwsRoute53ResolverFirewallConfigDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).route53resolverconn

log.Printf("[DEBUG] Deleting Route 53 Resolver DNS Firewall config")
_, err := conn.UpdateFirewallConfig(&route53resolver.UpdateFirewallConfigInput{
ResourceId: aws.String(d.Get("resource_id").(string)),
FirewallFailOpen: aws.String(route53resolver.FirewallFailOpenStatusDisabled),
})

if err != nil {
return fmt.Errorf("error deleting Route 53 Resolver DNS Firewall config (%s): %w", d.Id(), err)
}

return nil
}
189 changes: 189 additions & 0 deletions aws/resource_aws_route53_resolver_firewall_config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
package aws

import (
"fmt"
"log"
"testing"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/route53resolver"
"github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
"github.com/hashicorp/terraform-plugin-sdk/v2/terraform"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/service/route53resolver/finder"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource"
)

func init() {
resource.AddTestSweepers("aws_route53_resolver_firewall_config", &resource.Sweeper{
Name: "aws_route53_resolver_firewall_config",
F: testSweepRoute53ResolverFirewallConfigs,
Dependencies: []string{
"aws_route53_resolver_firewall_config_association",
},
})
}

func testSweepRoute53ResolverFirewallConfigs(region string) error {
client, err := sharedClientForRegion(region)
if err != nil {
return fmt.Errorf("error getting client: %s", err)
}
conn := client.(*AWSClient).route53resolverconn
var sweeperErrs *multierror.Error

err = conn.ListFirewallConfigsPages(&route53resolver.ListFirewallConfigsInput{}, func(page *route53resolver.ListFirewallConfigsOutput, lastPage bool) bool {
if page == nil {
return !lastPage
}

for _, firewallRuleGroup := range page.FirewallConfigs {
id := aws.StringValue(firewallRuleGroup.Id)

log.Printf("[INFO] Deleting Route53 Resolver DNS Firewall config: %s", id)
r := resourceAwsRoute53ResolverFirewallConfig()
d := r.Data(nil)
d.SetId(id)
err := r.Delete(d, client)

if err != nil {
log.Printf("[ERROR] %s", err)
sweeperErrs = multierror.Append(sweeperErrs, err)
continue
}
}

return !lastPage
})
if testSweepSkipSweepError(err) {
log.Printf("[WARN] Skipping Route53 Resolver DNS Firewall configs sweep for %s: %s", region, err)
return sweeperErrs.ErrorOrNil() // In case we have completed some pages, but had errors
}
if err != nil {
sweeperErrs = multierror.Append(sweeperErrs, fmt.Errorf("error retrieving Route53 Resolver DNS Firewall configs: %w", err))
}

return sweeperErrs.ErrorOrNil()
}

func TestAccAWSRoute53ResolverFirewallConfig_basic(t *testing.T) {
var v route53resolver.FirewallConfig
resourceName := "aws_route53_resolver_firewall_config.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) },
ErrorCheck: testAccErrorCheck(t, route53resolver.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy,
Steps: []resource.TestStep{
{
Config: testAccRoute53ResolverFirewallConfigConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v),
resource.TestCheckResourceAttr(resourceName, "firewall_fail_open", "ENABLED"),
testAccCheckResourceAttrAccountID(resourceName, "owner_id"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccAWSRoute53ResolverFirewallConfig_disappears(t *testing.T) {
var v route53resolver.FirewallConfig
resourceName := "aws_route53_resolver_firewall_config.test"
rName := acctest.RandomWithPrefix("tf-acc-test")

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSRoute53Resolver(t) },
ErrorCheck: testAccErrorCheck(t, route53resolver.EndpointsID),
Providers: testAccProviders,
CheckDestroy: testAccCheckRoute53ResolverFirewallConfigDestroy,
Steps: []resource.TestStep{
{
Config: testAccRoute53ResolverFirewallConfigConfig(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckRoute53ResolverFirewallConfigExists(resourceName, &v),
testAccCheckResourceDisappears(testAccProvider, resourceAwsRoute53ResolverFirewallConfig(), resourceName),
),
ExpectNonEmptyPlan: true,
},
},
})
}

func testAccCheckRoute53ResolverFirewallConfigDestroy(s *terraform.State) error {
conn := testAccProvider.Meta().(*AWSClient).route53resolverconn

for _, rs := range s.RootModule().Resources {
if rs.Type != "aws_route53_resolver_firewall_config" {
continue
}

config, err := finder.FirewallConfigByID(conn, rs.Primary.ID)

if tfresource.NotFound(err) {
continue
}

if err != nil {
return err
}

if aws.StringValue(config.FirewallFailOpen) == route53resolver.FirewallFailOpenStatusDisabled {
return nil
}

return fmt.Errorf("Route 53 Resolver DNS Firewall config still exists: %s", rs.Primary.ID)
}

return nil
}

func testAccCheckRoute53ResolverFirewallConfigExists(n string, v *route53resolver.FirewallConfig) 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 Route 53 Resolver DNS Firewall config ID is set")
}

conn := testAccProvider.Meta().(*AWSClient).route53resolverconn

out, err := finder.FirewallConfigByID(conn, rs.Primary.ID)

if err != nil {
return err
}

*v = *out

return nil
}
}

func testAccRoute53ResolverFirewallConfigConfig(rName string) string {
return fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
tags = {
Name = %[1]q
}
}
resource "aws_route53_resolver_firewall_config" "test" {
resource_id = aws_vpc.test.id
firewall_fail_open = "ENABLED"
}
`, rName)
}
Loading

0 comments on commit 7564614

Please sign in to comment.