Skip to content

Commit

Permalink
Merge pull request #33767 from evan-cleary/f-aws_lb-enforce_security_…
Browse files Browse the repository at this point in the history
…group_inbound_rules_on_private_link_traffic

r/aws_lb: Add enforce_security_group_inbound_rules_on_private_link_traffic
  • Loading branch information
ewbankkit authored Dec 6, 2023
2 parents 754ca2c + e2b4362 commit fabea86
Show file tree
Hide file tree
Showing 6 changed files with 150 additions and 21 deletions.
7 changes: 7 additions & 0 deletions .changelog/33767.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
resource/aws_lb: Add `enforce_security_group_inbound_rules_on_private_link_traffic` argument
```

```release-note:enhancement
data-source/aws_lb: Add `enforce_security_group_inbound_rules_on_private_link_traffic` attribute
```
28 changes: 20 additions & 8 deletions internal/service/elbv2/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import ( // nosemgrep:ci.semgrep.aws.multiple-service-imports
"github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag"
"github.com/hashicorp/terraform-provider-aws/internal/flex"
tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/internal/verify"
Expand Down Expand Up @@ -170,6 +171,13 @@ func ResourceLoadBalancer() *schema.Resource {
Default: false,
DiffSuppressFunc: suppressIfLBTypeNot(elbv2.LoadBalancerTypeEnumApplication),
},
"enforce_security_group_inbound_rules_on_private_link_traffic": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ValidateFunc: validation.StringInSlice(elbv2.EnforceSecurityGroupInboundRulesOnPrivateLinkTrafficEnum_Values(), false),
DiffSuppressFunc: suppressIfLBTypeNot(elbv2.LoadBalancerTypeEnumNetwork),
},
"idle_timeout": {
Type: schema.TypeInt,
Optional: true,
Expand Down Expand Up @@ -595,13 +603,20 @@ func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, met
}
}

if d.HasChange("security_groups") {
if d.HasChanges("enforce_security_group_inbound_rules_on_private_link_traffic", "security_groups") {
sgs := flex.ExpandStringSet(d.Get("security_groups").(*schema.Set))

params := &elbv2.SetSecurityGroupsInput{
LoadBalancerArn: aws.String(d.Id()),
SecurityGroups: sgs,
}

if v := d.Get("load_balancer_type"); v == elbv2.LoadBalancerTypeEnumNetwork {
if v, ok := d.GetOk("enforce_security_group_inbound_rules_on_private_link_traffic"); ok {
params.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic = aws.String(v.(string))
}
}

_, err := conn.SetSecurityGroupsWithContext(ctx, params)
if err != nil {
return sdkdiag.AppendErrorf(diags, "failure Setting LB Security Groups: %s", err)
Expand Down Expand Up @@ -889,14 +904,10 @@ func getLBNameFromARN(arn string) (string, error) {
return matches[1], nil
}

// flattenSubnetsFromAvailabilityZones creates a slice of strings containing the subnet IDs
// for the ALB based on the AvailabilityZones structure returned by the API.
func flattenSubnetsFromAvailabilityZones(availabilityZones []*elbv2.AvailabilityZone) []string {
var result []string
for _, az := range availabilityZones {
result = append(result, aws.StringValue(az.SubnetId))
}
return result
return tfslices.ApplyToAll(availabilityZones, func(v *elbv2.AvailabilityZone) string {
return aws.StringValue(v.SubnetId)
})
}

func flattenSubnetMappingsFromAvailabilityZones(availabilityZones []*elbv2.AvailabilityZone) []map[string]interface{} {
Expand Down Expand Up @@ -939,6 +950,7 @@ func flattenResource(ctx context.Context, d *schema.ResourceData, meta interface
d.Set("arn_suffix", SuffixFromARN(lb.LoadBalancerArn))
d.Set("customer_owned_ipv4_pool", lb.CustomerOwnedIpv4Pool)
d.Set("dns_name", lb.DNSName)
d.Set("enforce_security_group_inbound_rules_on_private_link_traffic", lb.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic)
d.Set("internal", aws.StringValue(lb.Scheme) == elbv2.LoadBalancerSchemeEnumInternal)
d.Set("ip_address_type", lb.IpAddressType)
d.Set("load_balancer_type", lb.Type)
Expand Down
27 changes: 14 additions & 13 deletions internal/service/elbv2/load_balancer_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,10 @@ func DataSourceLoadBalancer() *schema.Resource {
Type: schema.TypeBool,
Computed: true,
},
"enforce_security_group_inbound_rules_on_private_link_traffic": {
Type: schema.TypeString,
Computed: true,
},
"idle_timeout": {
Type: schema.TypeInt,
Computed: true,
Expand Down Expand Up @@ -234,28 +238,25 @@ func dataSourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, met
}

lb := results[0]

d.SetId(aws.StringValue(lb.LoadBalancerArn))

d.Set("arn", lb.LoadBalancerArn)
d.Set("arn_suffix", SuffixFromARN(lb.LoadBalancerArn))
d.Set("name", lb.LoadBalancerName)
d.Set("internal", lb.Scheme != nil && aws.StringValue(lb.Scheme) == "internal")
d.Set("security_groups", flex.FlattenStringList(lb.SecurityGroups))
d.Set("vpc_id", lb.VpcId)
d.Set("zone_id", lb.CanonicalHostedZoneId)
d.Set("customer_owned_ipv4_pool", lb.CustomerOwnedIpv4Pool)
d.Set("dns_name", lb.DNSName)
d.Set("enforce_security_group_inbound_rules_on_private_link_traffic", lb.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic)
d.Set("ip_address_type", lb.IpAddressType)
d.Set("name", lb.LoadBalancerName)
d.Set("internal", aws.StringValue(lb.Scheme) == "internal")
d.Set("load_balancer_type", lb.Type)
d.Set("customer_owned_ipv4_pool", lb.CustomerOwnedIpv4Pool)

if err := d.Set("subnets", flattenSubnetsFromAvailabilityZones(lb.AvailabilityZones)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting subnets: %s", err)
}

d.Set("security_groups", aws.StringValueSlice(lb.SecurityGroups))
if err := d.Set("subnet_mapping", flattenSubnetMappingsFromAvailabilityZones(lb.AvailabilityZones)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting subnet_mapping: %s", err)
}
if err := d.Set("subnets", flattenSubnetsFromAvailabilityZones(lb.AvailabilityZones)); err != nil {
return sdkdiag.AppendErrorf(diags, "setting subnets: %s", err)
}
d.Set("vpc_id", lb.VpcId)
d.Set("zone_id", lb.CanonicalHostedZoneId)

attributesResp, err := conn.DescribeLoadBalancerAttributesWithContext(ctx, &elbv2.DescribeLoadBalancerAttributesInput{
LoadBalancerArn: aws.String(d.Id()),
Expand Down
3 changes: 3 additions & 0 deletions internal/service/elbv2/load_balancer_data_source_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func TestAccELBV2LoadBalancerDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName, "ip_address_type", resourceName, "ip_address_type"),
resource.TestCheckResourceAttrPair(dataSourceName, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName, "desync_mitigation_mode", resourceName, "desync_mitigation_mode"),
resource.TestCheckResourceAttrPair(dataSourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic"),
resource.TestCheckResourceAttrPair(dataSourceName2, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName2, "internal", resourceName, "internal"),
resource.TestCheckResourceAttrPair(dataSourceName2, "subnets.#", resourceName, "subnets.#"),
Expand All @@ -61,6 +62,7 @@ func TestAccELBV2LoadBalancerDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName2, "ip_address_type", resourceName, "ip_address_type"),
resource.TestCheckResourceAttrPair(dataSourceName2, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "desync_mitigation_mode", resourceName, "desync_mitigation_mode"),
resource.TestCheckResourceAttrPair(dataSourceName2, "enforce_security_group_inbound_rules_on_private_link_traffic", resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic"),
resource.TestCheckResourceAttrPair(dataSourceName3, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName3, "internal", resourceName, "internal"),
resource.TestCheckResourceAttrPair(dataSourceName3, "subnets.#", resourceName, "subnets.#"),
Expand All @@ -77,6 +79,7 @@ func TestAccELBV2LoadBalancerDataSource_basic(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName3, "ip_address_type", resourceName, "ip_address_type"),
resource.TestCheckResourceAttrPair(dataSourceName3, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName3, "desync_mitigation_mode", resourceName, "desync_mitigation_mode"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enforce_security_group_inbound_rules_on_private_link_traffic", resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_tls_version_and_cipher_suite_headers", resourceName, "enable_tls_version_and_cipher_suite_headers"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_xff_client_port", resourceName, "enable_xff_client_port"),
resource.TestCheckResourceAttrPair(dataSourceName3, "xff_header_processing_mode", resourceName, "xff_header_processing_mode"),
Expand Down
105 changes: 105 additions & 0 deletions internal/service/elbv2/load_balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -915,13 +915,15 @@ func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_updatedSecurityGroups(t *t
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &pre),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
),
},
{
Config: testAccLoadBalancerConfig_albUpdateSecurityGroups(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &post),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "2"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
testAccCheckLoadBalancerNotRecreated(&pre, &post),
),
},
Expand Down Expand Up @@ -1389,6 +1391,7 @@ func TestAccELBV2LoadBalancer_NetworkLoadBalancer_updateSecurityGroups(t *testin
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "0"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
),
},
{
Expand All @@ -1397,6 +1400,7 @@ func TestAccELBV2LoadBalancer_NetworkLoadBalancer_updateSecurityGroups(t *testin
testAccCheckLoadBalancerExists(ctx, resourceName, &lb2),
testAccCheckLoadBalancerRecreated(&lb2, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
),
},
{
Expand All @@ -1405,6 +1409,7 @@ func TestAccELBV2LoadBalancer_NetworkLoadBalancer_updateSecurityGroups(t *testin
testAccCheckLoadBalancerExists(ctx, resourceName, &lb3),
testAccCheckLoadBalancerNotRecreated(&lb3, &lb2),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "2"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
),
},
{
Expand All @@ -1413,6 +1418,67 @@ func TestAccELBV2LoadBalancer_NetworkLoadBalancer_updateSecurityGroups(t *testin
testAccCheckLoadBalancerExists(ctx, resourceName, &lb4),
testAccCheckLoadBalancerRecreated(&lb4, &lb3),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "0"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", ""),
),
},
},
})
}

func TestAccELBV2LoadBalancer_NetworkLoadBalancer_enforcePrivateLink(t *testing.T) {
ctx := acctest.Context(t)
var lb1 elbv2.LoadBalancer
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_lb.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(ctx, t) },
ErrorCheck: acctest.ErrorCheck(t, elbv2.EndpointsID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckLoadBalancerDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccLoadBalancerConfig_nlbSecurityGroupsEnforcePrivateLink(rName, 1, "off"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", "off")),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccLoadBalancerConfig_nlbSecurityGroups(rName, 1),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", "off"),
),
},
{
Config: testAccLoadBalancerConfig_nlbSecurityGroupsEnforcePrivateLink(rName, 1, "on"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", "on"),
),
},
{
Config: testAccLoadBalancerConfig_nlbSecurityGroupsEnforcePrivateLink(rName, 1, "off"),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", "off"),
),
},
{
Config: testAccLoadBalancerConfig_nlbSecurityGroups(rName, 1),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(ctx, resourceName, &lb1),
resource.TestCheckResourceAttr(resourceName, "security_groups.#", "1"),
resource.TestCheckResourceAttr(resourceName, "enforce_security_group_inbound_rules_on_private_link_traffic", "off"),
),
},
},
Expand Down Expand Up @@ -2656,6 +2722,45 @@ resource "aws_lb" "test" {
`, rName, n))
}

func testAccLoadBalancerConfig_nlbSecurityGroupsEnforcePrivateLink(rName string, n int, enforcePrivateLink string) string {
return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, 2), fmt.Sprintf(`
resource "aws_security_group" "test" {
count = 3
name = "%[1]s-${count.index}"
vpc_id = aws_vpc.test.id
ingress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
tags = {
Name = %[1]q
}
}
resource "aws_lb" "test" {
internal = true
load_balancer_type = "network"
name = %[1]q
subnets = aws_subnet.test[*].id
security_groups = slice(aws_security_group.test[*].id, 0, %[2]d)
enforce_security_group_inbound_rules_on_private_link_traffic = %[3]q
}
`, rName, n, enforcePrivateLink))
}

func testAccLoadBalancerConfig_nlbSubnets(rName string, subnetCount int) string {
return acctest.ConfigCompose(acctest.ConfigVPCWithSubnets(rName, subnetCount), fmt.Sprintf(`
resource "aws_lb" "test" {
Expand Down
1 change: 1 addition & 0 deletions website/docs/r/lb.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@ This resource supports the following arguments:
* `enable_tls_version_and_cipher_suite_headers` - (Optional) Indicates whether the two headers (`x-amzn-tls-version` and `x-amzn-tls-cipher-suite`), which contain information about the negotiated TLS version and cipher suite, are added to the client request before sending it to the target. Only valid for Load Balancers of type `application`. Defaults to `false`
* `enable_xff_client_port` - (Optional) Indicates whether the X-Forwarded-For header should preserve the source port that the client used to connect to the load balancer in `application` load balancers. Defaults to `false`.
* `enable_waf_fail_open` - (Optional) Indicates whether to allow a WAF-enabled load balancer to route requests to targets if it is unable to forward the request to AWS WAF. Defaults to `false`.
* `enforce_security_group_inbound_rules_on_private_link_traffic` - (Optional) Indicates whether inbound security group rules are enforced for traffic originating from a PrivateLink. Only valid for Load Balancers of type `network`. The possible values are `on` and `off`.
* `idle_timeout` - (Optional) The time in seconds that the connection is allowed to be idle. Only valid for Load Balancers of type `application`. Default: 60.
* `internal` - (Optional) If true, the LB will be internal. Defaults to `false`.
* `ip_address_type` - (Optional) The type of IP addresses used by the subnets for your load balancer. The possible values are `ipv4` and `dualstack`.
Expand Down

0 comments on commit fabea86

Please sign in to comment.