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

resource/aws_route53_resolver_firewall_config: Add new resource #18733

Merged
merged 5 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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