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

service/elbv2/load_balancer: Support WAF fail open #16393

Merged
merged 6 commits into from
Nov 19, 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
7 changes: 7 additions & 0 deletions .changelog/16393.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
```release-note:enhancement
data-source/aws_lb: Add `enable_waf_fail_open` attribute
```

```release-note:enhancement
resource/aws_lb: Add `enable_waf_fail_open` argument
```
19 changes: 19 additions & 0 deletions internal/service/elbv2/load_balancer.go
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,13 @@ func ResourceLoadBalancer() *schema.Resource {
DiffSuppressFunc: suppressIfLBType(elbv2.LoadBalancerTypeEnumNetwork),
},

"enable_waf_fail_open": {
Type: schema.TypeBool,
Optional: true,
Default: false,
DiffSuppressFunc: suppressIfLBType(elbv2.LoadBalancerTypeEnumNetwork),
},

"ip_address_type": {
Type: schema.TypeString,
Computed: true,
Expand Down Expand Up @@ -454,13 +461,21 @@ func resourceLoadBalancerUpdate(d *schema.ResourceData, meta interface{}) error
Value: aws.String(fmt.Sprintf("%d", d.Get("idle_timeout").(int))),
})
}

if d.HasChange("enable_http2") || d.IsNewResource() {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String("routing.http2.enabled"),
Value: aws.String(strconv.FormatBool(d.Get("enable_http2").(bool))),
})
}

if d.HasChange("enable_waf_fail_open") || d.IsNewResource() {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String("waf.fail_open.enabled"),
Value: aws.String(strconv.FormatBool(d.Get("enable_waf_fail_open").(bool))),
})
}

if d.HasChange("drop_invalid_header_fields") || d.IsNewResource() {
attributes = append(attributes, &elbv2.LoadBalancerAttribute{
Key: aws.String("routing.http.drop_invalid_header_fields.enabled"),
Expand Down Expand Up @@ -801,6 +816,10 @@ func flattenResource(d *schema.ResourceData, meta interface{}, lb *elbv2.LoadBal
http2Enabled := aws.StringValue(attr.Value) == "true"
log.Printf("[DEBUG] Setting ALB HTTP/2 Enabled: %t", http2Enabled)
d.Set("enable_http2", http2Enabled)
case "waf.fail_open.enabled":
wafFailOpenEnabled := aws.StringValue(attr.Value) == "true"
log.Printf("[DEBUG] Setting ALB WAF fail open Enabled: %t", wafFailOpenEnabled)
d.Set("enable_waf_fail_open", wafFailOpenEnabled)
case "load_balancing.cross_zone.enabled":
crossZoneLbEnabled := aws.StringValue(attr.Value) == "true"
log.Printf("[DEBUG] Setting NLB Cross Zone Load Balancing Enabled: %t", crossZoneLbEnabled)
Expand Down
8 changes: 8 additions & 0 deletions internal/service/elbv2/load_balancer_data_source.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,11 @@ func DataSourceLoadBalancer() *schema.Resource {
Computed: true,
},

"enable_waf_fail_open": {
Type: schema.TypeBool,
Computed: true,
},

"idle_timeout": {
Type: schema.TypeInt,
Computed: true,
Expand Down Expand Up @@ -287,6 +292,9 @@ func dataSourceLoadBalancerRead(d *schema.ResourceData, meta interface{}) error
case "routing.http2.enabled":
http2Enabled := aws.StringValue(attr.Value) == "true"
d.Set("enable_http2", http2Enabled)
case "waf.fail_open.enabled":
wafFailOpenEnabled := aws.StringValue(attr.Value) == "true"
d.Set("enable_waf_fail_open", wafFailOpenEnabled)
case "load_balancing.cross_zone.enabled":
crossZoneLbEnabled := aws.StringValue(attr.Value) == "true"
d.Set("enable_cross_zone_load_balancing", crossZoneLbEnabled)
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 @@ -143,6 +143,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName1, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName1, "drop_invalid_header_fields", resourceName, "drop_invalid_header_fields"),
resource.TestCheckResourceAttrPair(dataSourceName1, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName1, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName1, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName2, "internal", resourceName, "internal"),
Expand All @@ -161,6 +162,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName2, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "drop_invalid_header_fields", resourceName, "drop_invalid_header_fields"),
resource.TestCheckResourceAttrPair(dataSourceName2, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName2, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName2, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName3, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName3, "internal", resourceName, "internal"),
Expand All @@ -179,6 +181,7 @@ func TestAccELBV2LoadBalancerDataSource_backwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName3, "subnet_mapping.#", resourceName, "subnet_mapping.#"),
resource.TestCheckResourceAttrPair(dataSourceName3, "drop_invalid_header_fields", resourceName, "drop_invalid_header_fields"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_http2", resourceName, "enable_http2"),
resource.TestCheckResourceAttrPair(dataSourceName3, "enable_waf_fail_open", resourceName, "enable_waf_fail_open"),
resource.TestCheckResourceAttrPair(dataSourceName3, "access_logs.#", resourceName, "access_logs.#"),
),
},
Expand Down
121 changes: 121 additions & 0 deletions internal/service/elbv2/load_balancer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ func TestAccELBV2LoadBalancer_LoadBalancerType_gateway(t *testing.T) {
ImportStateVerifyIgnore: []string{
"drop_invalid_header_fields",
"enable_http2",
"enable_waf_fail_open",
"idle_timeout",
},
},
Expand Down Expand Up @@ -225,6 +226,7 @@ func TestAccELBV2LoadBalancer_LoadBalancerTypeGateway_enableCrossZoneLoadBalanci
ImportStateVerifyIgnore: []string{
"drop_invalid_header_fields",
"enable_http2",
"enable_waf_fail_open",
"idle_timeout",
},
},
Expand Down Expand Up @@ -642,6 +644,54 @@ func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_updateDeletionProtection(t
})
}

func TestAccELBV2LoadBalancer_ApplicationLoadBalancer_updateWafFailOpen(t *testing.T) {
var pre, mid, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testAccAWSalb-basic-%s", sdkacctest.RandString(10))
resourceName := "aws_lb.lb_test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, elbv2.EndpointsID),
Providers: acctest.Providers,
CheckDestroy: testAccCheckLoadBalancerDestroy,
Steps: []resource.TestStep{
{
Config: testAccLBConfig_enableWafFailOpen(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(resourceName, &pre),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "false"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccLBConfig_enableWafFailOpen(lbName, true),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(resourceName, &mid),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "true"),
testAccChecklbARNs(&pre, &mid),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
{
Config: testAccLBConfig_enableWafFailOpen(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckLoadBalancerExists(resourceName, &post),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "false"),
testAccChecklbARNs(&mid, &post),
),
},
},
})
}

func TestAccELBV2LoadBalancer_updatedSecurityGroups(t *testing.T) {
var pre, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testAccAWSlb-basic-%s", sdkacctest.RandString(10))
Expand Down Expand Up @@ -1820,6 +1870,77 @@ resource "aws_security_group" "alb_test" {
`, lbName, deletion_protection))
}

func testAccLBConfig_enableWafFailOpen(lbName string, wafFailOpen bool) string {
return acctest.ConfigCompose(
acctest.ConfigAvailableAZsNoOptIn(),
fmt.Sprintf(`
resource "aws_lb" "lb_test" {
name = %[1]q
internal = true
security_groups = [aws_security_group.alb_test.id]
subnets = aws_subnet.alb_test.*.id

idle_timeout = 30
enable_deletion_protection = false

enable_waf_fail_open = %[2]t

tags = {
Name = "TestAccAWSALB_basic"
}
}

variable "subnets" {
default = ["10.0.1.0/24", "10.0.2.0/24"]
type = list(string)
}

resource "aws_vpc" "alb_test" {
cidr_block = "10.0.0.0/16"

tags = {
Name = "terraform-testacc-lb-basic"
}
}

resource "aws_subnet" "alb_test" {
count = 2
vpc_id = aws_vpc.alb_test.id
cidr_block = element(var.subnets, count.index)
map_public_ip_on_launch = true
availability_zone = element(data.aws_availability_zones.available.names, count.index)

tags = {
Name = "tf-acc-lb-basic-${count.index}"
}
}

resource "aws_security_group" "alb_test" {
name = "allow_all_alb_test"
description = "Used for ALB Testing"
vpc_id = aws_vpc.alb_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 = "TestAccAWSALB_basic"
}
}
`, lbName, wafFailOpen))
}

func testAccLoadBalancerConfig_networkLoadbalancer_subnets(lbName string) string {
return acctest.ConfigCompose(acctest.ConfigAvailableAZsNoOptIn(), fmt.Sprintf(`
resource "aws_vpc" "alb_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 @@ -120,6 +120,7 @@ for load balancers of type `network` will force a recreation of the resource.
* `enable_cross_zone_load_balancing` - (Optional) If true, cross-zone load balancing of the load balancer will be enabled.
This is a `network` load balancer feature. Defaults to `false`.
* `enable_http2` - (Optional) Indicates whether HTTP/2 is enabled in `application` load balancers. Defaults to `true`.
* `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`.
* `customer_owned_ipv4_pool` - (Optional) The ID of the customer owned ipv4 pool to use for this load balancer.
* `ip_address_type` - (Optional) The type of IP addresses used by the subnets for your load balancer. The possible values are `ipv4` and `dualstack`
* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
Expand Down