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

ec2: fix aws_vpc_endpoint missing exposed dns_option #31873

Merged
merged 14 commits into from
Jun 12, 2023
Merged
Show file tree
Hide file tree
Changes from 3 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/31873.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_vpc_endpoint: Add private_dns_only_for_inbound_resolver_endpoint argument for dns_options
```
28 changes: 20 additions & 8 deletions internal/service/ec2/vpc_endpoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ func ResourceVPCEndpoint() *schema.Resource {
Optional: true,
ValidateFunc: validation.StringInSlice(ec2.DnsRecordIpType_Values(), false),
},
"private_dns_only_for_inbound_resolver_endpoint": {
Type: schema.TypeBool,
Optional: true,
},
},
},
},
Expand Down Expand Up @@ -198,7 +202,7 @@ func resourceVPCEndpointCreate(ctx context.Context, d *schema.ResourceData, meta
}

if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{}))
input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{}), input.PrivateDnsEnabled)
}

if v, ok := d.GetOk("ip_address_type"); ok {
Expand Down Expand Up @@ -368,12 +372,6 @@ func resourceVPCEndpointUpdate(ctx context.Context, d *schema.ResourceData, meta
VpcEndpointId: aws.String(d.Id()),
}

if d.HasChange("dns_options") {
if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{}))
}
}

if d.HasChange("ip_address_type") {
input.IpAddressType = aws.String(d.Get("ip_address_type").(string))
}
Expand All @@ -382,6 +380,12 @@ func resourceVPCEndpointUpdate(ctx context.Context, d *schema.ResourceData, meta
input.PrivateDnsEnabled = aws.Bool(d.Get("private_dns_enabled").(bool))
}

if d.HasChange("dns_options") {
if v, ok := d.GetOk("dns_options"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil {
input.DnsOptions = expandDNSOptionsSpecification(v.([]interface{})[0].(map[string]interface{}), input.PrivateDnsEnabled)
}
}

input.AddRouteTableIds, input.RemoveRouteTableIds = flattenAddAndRemoveStringLists(d, "route_table_ids")
input.AddSecurityGroupIds, input.RemoveSecurityGroupIds = flattenAddAndRemoveStringLists(d, "security_group_ids")
input.AddSubnetIds, input.RemoveSubnetIds = flattenAddAndRemoveStringLists(d, "subnet_ids")
Expand Down Expand Up @@ -471,7 +475,7 @@ func vpcEndpointAccept(ctx context.Context, conn *ec2.EC2, vpceID, serviceName s
return nil
}

func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptionsSpecification {
func expandDNSOptionsSpecification(tfMap map[string]interface{}, privateDnsEnabled *bool) *ec2.DnsOptionsSpecification {
if tfMap == nil {
return nil
}
Expand All @@ -482,6 +486,10 @@ func expandDNSOptionsSpecification(tfMap map[string]interface{}) *ec2.DnsOptions
apiObject.DnsRecordIpType = aws.String(v)
}

if v, ok := tfMap["private_dns_only_for_inbound_resolver_endpoint"].(bool); ok && privateDnsEnabled != nil && *privateDnsEnabled {
apiObject.PrivateDnsOnlyForInboundResolverEndpoint = aws.Bool(v)
}

return apiObject
}

Expand Down Expand Up @@ -532,6 +540,10 @@ func flattenDNSOptions(apiObject *ec2.DnsOptions) map[string]interface{} {
tfMap["dns_record_ip_type"] = aws.StringValue(v)
}

if v := apiObject.PrivateDnsOnlyForInboundResolverEndpoint; v != nil {
tfMap["private_dns_only_for_inbound_resolver_endpoint"] = aws.BoolValue(v)
}

return tfMap
}

Expand Down
78 changes: 78 additions & 0 deletions internal/service/ec2/vpc_endpoint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,56 @@ func TestAccVPCEndpoint_interfaceBasic(t *testing.T) {
})
}

func TestAccVPCEndpoint_interfacePrivateDNS(t *testing.T) {
ctx := acctest.Context(t)
var endpoint ec2.VpcEndpoint
resourceName := "aws_vpc_endpoint.test"
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckVPCEndpointDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccVPCEndpointConfig_interfacePrivateDNS(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckVPCEndpointExists(ctx, resourceName, &endpoint),
acctest.MatchResourceAttrRegionalARN(resourceName, "arn", "ec2", regexp.MustCompile(`vpc-endpoint/vpce-.+`)),
resource.TestCheckResourceAttrWith(resourceName, "cidr_blocks.#", func(value string) error {
if value == "0" {
return fmt.Errorf("need non-zero cidr_blocks")
}
return nil
}),
resource.TestCheckResourceAttr(resourceName, "dns_entry.#", "0"),
resource.TestCheckResourceAttr(resourceName, "dns_options.#", "1"),
resource.TestCheckResourceAttr(resourceName, "dns_options.0.dns_record_ip_type", "ipv4"),
resource.TestCheckResourceAttr(resourceName, "dns_options.0.private_dns_only_for_inbound_resolver_endpoint", "false"),
resource.TestCheckResourceAttr(resourceName, "ip_address_type", "ipv4"),
resource.TestCheckResourceAttr(resourceName, "network_interface_ids.#", "0"),
acctest.CheckResourceAttrAccountID(resourceName, "owner_id"),
resource.TestCheckResourceAttrSet(resourceName, "policy"),
resource.TestCheckResourceAttrSet(resourceName, "prefix_list_id"),
resource.TestCheckResourceAttr(resourceName, "private_dns_enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "requester_managed", "false"),
resource.TestCheckResourceAttr(resourceName, "route_table_ids.#", "0"),
resource.TestCheckResourceAttr(resourceName, "security_group_ids.#", "1"), // Default SG.
resource.TestCheckResourceAttr(resourceName, "subnet_ids.#", "0"),
resource.TestCheckResourceAttr(resourceName, "tags.%", "0"),
resource.TestCheckResourceAttr(resourceName, "vpc_endpoint_type", "Interface"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func TestAccVPCEndpoint_disappears(t *testing.T) {
ctx := acctest.Context(t)
var endpoint ec2.VpcEndpoint
Expand Down Expand Up @@ -694,6 +744,34 @@ resource "aws_vpc_endpoint" "test" {
`, rName)
}

func testAccVPCEndpointConfig_interfacePrivateDNS(rName string) string {
return fmt.Sprintf(`
resource "aws_vpc" "test" {
cidr_block = "10.0.0.0/16"
enable_dns_support = true
enable_dns_hostnames = true

tags = {
Name = %[1]q
}
}

data "aws_region" "current" {}

resource "aws_vpc_endpoint" "test" {
vpc_id = aws_vpc.test.id
service_name = "com.amazonaws.${data.aws_region.current.name}.s3"
private_dns_enabled = true
vpc_endpoint_type = "Interface"
ip_address_type = "ipv4"
dns_options {
dns_record_ip_type = "ipv4"
private_dns_only_for_inbound_resolver_endpoint = false
}
}
`, rName)
}

func testAccVPCEndpointConfig_ipAddressType(rName, addressType string) string {
return acctest.ConfigCompose(testAccVPCEndpointServiceConfig_baseSupportedIPAddressTypes(rName), fmt.Sprintf(`
resource "aws_vpc_endpoint_service" "test" {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/vpc_endpoint.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,7 @@ If no security groups are specified, the VPC's [default security group](https://
### dns_options

* `dns_record_ip_type` - (Optional) The DNS records created for the endpoint. Valid values are `ipv4`, `dualstack`, `service-defined`, and `ipv6`.
* `private_dns_only_for_inbound_resolver_endpoint` - (Optional) Indicates whether to enable private DNS only for inbound endpoints. This option is available only for services that support both gateway and interface endpoints. It routes traffic that originates from the VPC to the gateway endpoint and traffic that originates from on-premises to the interface endpoint.

## Timeouts

Expand Down