Skip to content

feat: add delegation_record to route53 resolver rule #43282

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

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
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
7 changes: 7 additions & 0 deletions .changelog/43282.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
data-source/aws_route53_resolver_rule: Add `delegation_record` argument
```

```release-note:enhancement
resource/aws_route53_resolver_rule: Add `delegation_record` argument
```
30 changes: 25 additions & 5 deletions internal/service/route53resolver/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,9 +51,17 @@ func resourceRule() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"delegation_record": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 256),
ConflictsWith: []string{names.AttrDomainName},
StateFunc: trimTrailingPeriod,
},
names.AttrDomainName: {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringLenBetween(1, 256),
StateFunc: trimTrailingPeriod,
Expand Down Expand Up @@ -125,11 +133,18 @@ func resourceRuleCreate(ctx context.Context, d *schema.ResourceData, meta any) d

input := &route53resolver.CreateResolverRuleInput{
CreatorRequestId: aws.String(id.PrefixedUniqueId("tf-r53-resolver-rule-")),
DomainName: aws.String(d.Get(names.AttrDomainName).(string)),
RuleType: awstypes.RuleTypeOption(d.Get("rule_type").(string)),
Tags: getTagsIn(ctx),
}

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

if v, ok := d.GetOk(names.AttrDomainName); ok {
input.DomainName = aws.String(v.(string))
}

if v, ok := d.GetOk(names.AttrName); ok {
input.Name = aws.String(v.(string))
}
Expand Down Expand Up @@ -174,9 +189,14 @@ func resourceRuleRead(ctx context.Context, d *schema.ResourceData, meta any) dia
}

d.Set(names.AttrARN, rule.Arn)
if rule.DelegationRecord != nil {
d.Set("delegation_record", trimTrailingPeriod(aws.ToString(rule.DelegationRecord)))
}
// To be consistent with other AWS services that do not accept a trailing period,
// we remove the suffix from the Domain Name returned from the API
d.Set(names.AttrDomainName, trimTrailingPeriod(aws.ToString(rule.DomainName)))
if rule.DomainName != nil {
d.Set(names.AttrDomainName, trimTrailingPeriod(aws.ToString(rule.DomainName)))
}
d.Set(names.AttrName, rule.Name)
d.Set(names.AttrOwnerID, rule.OwnerId)
d.Set("resolver_endpoint_id", rule.ResolverEndpointId)
Expand Down Expand Up @@ -415,8 +435,8 @@ func flattenRuleTargetIPs(targetAddresses []awstypes.TargetAddress) []any {
}

// trimTrailingPeriod is used to remove the trailing period
// of "name" or "domain name" attributes often returned from
// the Route53 API or provided as user input.
// of "name", "domain name" or "delegation_record" attributes
// often returned from the Route53 API or provided as user input.
// The single dot (".") domain name is returned as-is.
func trimTrailingPeriod(v any) string {
var str string
Expand Down
13 changes: 12 additions & 1 deletion internal/service/route53resolver/rule_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ func dataSourceRule() *schema.Resource {
Type: schema.TypeString,
Computed: true,
},
"delegation_record": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringLenBetween(1, 256),
},
names.AttrDomainName: {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -124,9 +130,14 @@ func dataSourceRuleRead(ctx context.Context, d *schema.ResourceData, meta any) d
d.SetId(aws.ToString(rule.Id))
arn := aws.ToString(rule.Arn)
d.Set(names.AttrARN, arn)
if rule.DelegationRecord != nil {
d.Set("delegation_record", trimTrailingPeriod(aws.ToString(rule.DelegationRecord)))
}
// To be consistent with other AWS services that do not accept a trailing period,
// we remove the suffix from the Domain Name returned from the API
d.Set(names.AttrDomainName, trimTrailingPeriod(aws.ToString(rule.DomainName)))
if rule.DomainName != nil {
d.Set(names.AttrDomainName, trimTrailingPeriod(aws.ToString(rule.DomainName)))
}
d.Set(names.AttrName, rule.Name)
d.Set(names.AttrOwnerID, rule.OwnerId)
d.Set("resolver_endpoint_id", rule.ResolverEndpointId)
Expand Down
63 changes: 63 additions & 0 deletions internal/service/route53resolver/rule_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,49 @@ func TestAccRoute53ResolverRuleDataSource_sharedWithMe(t *testing.T) {
})
}

func TestAccRoute53ResolverRuleDataSource_delegationRecord(t *testing.T) {
ctx := acctest.Context(t)
delegationRecord := acctest.RandomDomainName()
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_route53_resolver_rule.test"
ds1ResourceName := "data.aws_route53_resolver_rule.by_resolver_rule_id"
ds2ResourceName := "data.aws_route53_resolver_rule.by_name_and_rule_type"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.Route53ResolverServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
Steps: []resource.TestStep{
{
Config: testAccRuleDataSourceConfig_delegatationRecord(rName, delegationRecord),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttrPair(ds1ResourceName, names.AttrID, resourceName, names.AttrID),
resource.TestCheckResourceAttrPair(ds1ResourceName, names.AttrARN, resourceName, names.AttrARN),
resource.TestCheckResourceAttrPair(ds1ResourceName, "delegation_record", resourceName, "delegation_record"),
resource.TestCheckResourceAttrPair(ds1ResourceName, names.AttrName, resourceName, names.AttrName),
resource.TestCheckResourceAttrPair(ds1ResourceName, names.AttrOwnerID, resourceName, names.AttrOwnerID),
resource.TestCheckResourceAttrPair(ds1ResourceName, "resolver_endpoint_id", resourceName, "resolver_endpoint_id"),
resource.TestCheckResourceAttrPair(ds1ResourceName, "resolver_rule_id", resourceName, names.AttrID),
resource.TestCheckResourceAttrPair(ds1ResourceName, "rule_type", resourceName, "rule_type"),
resource.TestCheckResourceAttrPair(ds1ResourceName, "share_status", resourceName, "share_status"),
resource.TestCheckResourceAttrPair(ds1ResourceName, acctest.CtTagsPercent, resourceName, acctest.CtTagsPercent),

resource.TestCheckResourceAttrPair(ds2ResourceName, names.AttrID, resourceName, names.AttrID),
resource.TestCheckResourceAttrPair(ds2ResourceName, names.AttrARN, resourceName, names.AttrARN),
resource.TestCheckResourceAttrPair(ds2ResourceName, "delegation_record", resourceName, "delegation_record"),
resource.TestCheckResourceAttrPair(ds2ResourceName, names.AttrName, resourceName, names.AttrName),
resource.TestCheckResourceAttrPair(ds2ResourceName, names.AttrOwnerID, resourceName, names.AttrOwnerID),
resource.TestCheckResourceAttrPair(ds2ResourceName, "resolver_endpoint_id", resourceName, "resolver_endpoint_id"),
resource.TestCheckResourceAttrPair(ds2ResourceName, "resolver_rule_id", resourceName, names.AttrID),
resource.TestCheckResourceAttrPair(ds2ResourceName, "rule_type", resourceName, "rule_type"),
resource.TestCheckResourceAttrPair(ds2ResourceName, "share_status", resourceName, "share_status"),
resource.TestCheckResourceAttrPair(ds2ResourceName, acctest.CtTagsPercent, resourceName, acctest.CtTagsPercent),
),
},
},
})
}

func testAccRuleDataSourceConfig_basic(rName, domainName string) string {
return fmt.Sprintf(`
resource "aws_route53_resolver_rule" "test" {
Expand All @@ -203,6 +246,26 @@ data "aws_route53_resolver_rule" "by_name_and_rule_type" {
`, rName, domainName)
}

func testAccRuleDataSourceConfig_delegatationRecord(rName, delegationRecord string) string {
return acctest.ConfigCompose(testAccRuleConfig_resolverEndpointBase(rName), fmt.Sprintf(`
resource "aws_route53_resolver_rule" "test" {
delegation_record = %[2]q
rule_type = "DELEGATE"
name = %[1]q
resolver_endpoint_id = aws_route53_resolver_endpoint.test[1].id
}

data "aws_route53_resolver_rule" "by_resolver_rule_id" {
resolver_rule_id = aws_route53_resolver_rule.test.id
}

data "aws_route53_resolver_rule" "by_name_and_rule_type" {
name = aws_route53_resolver_rule.test.name
rule_type = aws_route53_resolver_rule.test.rule_type
}
`, rName, delegationRecord))
}

func testAccRuleDataSourceConfig_resolverEndpointIDTags(rName, domainName string) string {
return acctest.ConfigCompose(testAccRuleConfig_resolverEndpointBase(rName), fmt.Sprintf(`
resource "aws_route53_resolver_rule" "test" {
Expand Down
55 changes: 55 additions & 0 deletions internal/service/route53resolver/rule_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,50 @@ func TestAccRoute53ResolverRule_updateName(t *testing.T) {
})
}

func TestAccRoute53ResolverRule_delegationRecord(t *testing.T) {
ctx := acctest.Context(t)
var rule1 awstypes.ResolverRule
resourceName := "aws_route53_resolver_rule.test"
delegationRecord := acctest.RandomDomainName()
ep1ResourceName := "aws_route53_resolver_endpoint.test.0"
ep2ResourceName := "aws_route53_resolver_endpoint.test.1"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, names.Route53ResolverServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckRuleDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccRuleConfig_delegationRecord(rName, delegationRecord, 0),
Check: resource.ComposeTestCheckFunc(
testAccCheckRuleExists(ctx, resourceName, &rule1),
resource.TestCheckResourceAttr(resourceName, "delegation_record", delegationRecord),
resource.TestCheckResourceAttr(resourceName, names.AttrName, rName),
resource.TestCheckResourceAttr(resourceName, "rule_type", "DELEGATE"),
resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", ep1ResourceName, names.AttrID),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccRuleConfig_delegationRecord(rName, delegationRecord, 1),
Check: resource.ComposeTestCheckFunc(
testAccCheckRuleExists(ctx, resourceName, &rule1),
resource.TestCheckResourceAttr(resourceName, "delegation_record", delegationRecord),
resource.TestCheckResourceAttr(resourceName, names.AttrName, rName),
resource.TestCheckResourceAttr(resourceName, "rule_type", "DELEGATE"),
resource.TestCheckResourceAttrPair(resourceName, "resolver_endpoint_id", ep2ResourceName, names.AttrID),
),
},
},
})
}

func TestAccRoute53ResolverRule_forward(t *testing.T) {
ctx := acctest.Context(t)
var rule1, rule2, rule3 awstypes.ResolverRule
Expand Down Expand Up @@ -670,6 +714,17 @@ resource "aws_route53_resolver_rule" "test" {
`, rName, domainName)
}

func testAccRuleConfig_delegationRecord(rName, delegationRecord string, resolverEndpointId int) string {
return acctest.ConfigCompose(testAccRuleConfig_resolverEndpointBase(rName), fmt.Sprintf(`
resource "aws_route53_resolver_rule" "test" {
delegation_record = %[2]q
rule_type = "DELEGATE"
name = %[1]q

resolver_endpoint_id = aws_route53_resolver_endpoint.test[%[3]d].id
}
`, rName, delegationRecord, resolverEndpointId))
}
func testAccRuleConfig_forward(rName, domainName string) string {
return acctest.ConfigCompose(testAccRuleConfig_resolverEndpointBase(rName), fmt.Sprintf(`
resource "aws_route53_resolver_rule" "test" {
Expand Down
3 changes: 2 additions & 1 deletion website/docs/d/route53_resolver_rule.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,12 @@ data "aws_route53_resolver_rule" "example" {
This data source supports the following arguments:

* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
* `delegation_record` - (Optional) DNS queries with the delegation records that match this domain name are forwarded to the resolvers on your network.
* `domain_name` - (Optional) Domain name the desired resolver rule forwards DNS queries for. Conflicts with `resolver_rule_id`.
* `name` - (Optional) Friendly name of the desired resolver rule. Conflicts with `resolver_rule_id`.
* `resolver_endpoint_id` (Optional) ID of the outbound resolver endpoint of the desired resolver rule. Conflicts with `resolver_rule_id`.
* `resolver_rule_id` (Optional) ID of the desired resolver rule. Conflicts with `domain_name`, `name`, `resolver_endpoint_id` and `rule_type`.
* `rule_type` - (Optional) Rule type of the desired resolver rule. Valid values are `FORWARD`, `SYSTEM` and `RECURSIVE`. Conflicts with `resolver_rule_id`.
* `rule_type` - (Optional) Rule type of the desired resolver rule. Valid values are `DELEGATE`, `FORWARD`, `SYSTEM` and `RECURSIVE`. Conflicts with `resolver_rule_id`.

## Attribute Reference

Expand Down
5 changes: 3 additions & 2 deletions website/docs/r/route53_resolver_rule.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,9 @@ resource "aws_route53_resolver_rule" "fwd" {
This resource supports the following arguments:

* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
* `domain_name` - (Required) DNS queries for this domain name are forwarded to the IP addresses that are specified using `target_ip`.
* `rule_type` - (Required) Rule type. Valid values are `FORWARD`, `SYSTEM` and `RECURSIVE`.
* `delegation_record` - (Optional) DNS queries with the delegation records that match this domain name are forwarded to the resolvers on your network.
* `domain_name` - (Optional) DNS queries for this domain name are forwarded to the IP addresses that are specified using `target_ip`.
* `rule_type` - (Required) Rule type. Valid values are `DELEGATE`, `FORWARD`, `SYSTEM` and `RECURSIVE`.
* `name` - (Optional) Friendly name that lets you easily find a rule in the Resolver dashboard in the Route 53 console.
* `resolver_endpoint_id` (Optional) ID of the outbound resolver endpoint that you want to use to route DNS queries to the IP addresses that you specify using `target_ip`.
This argument should only be specified for `FORWARD` type rules.
Expand Down
Loading