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 1 commit
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
5 changes: 5 additions & 0 deletions aws/data_source_aws_lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,11 @@ func dataSourceAwsLb() *schema.Resource {
Computed: true,
},

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

"idle_timeout": {
Type: schema.TypeInt,
Computed: true,
Expand Down
8 changes: 5 additions & 3 deletions aws/data_source_aws_lb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ func TestAccDataSourceAWSLB_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_http2"),

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resource name doesn't seem right

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops, thank you!

resource.TestCheckResourceAttrPair(dataSourceName1, "access_logs.#", resourceName, "access_logs.#"),
resource.TestCheckResourceAttrPair(dataSourceName2, "name", resourceName, "name"),
resource.TestCheckResourceAttrPair(dataSourceName2, "internal", resourceName, "internal"),
Expand All @@ -132,9 +133,10 @@ func TestAccDataSourceAWSLB_BackwardsCompatibility(t *testing.T) {
resource.TestCheckResourceAttrPair(dataSourceName2, "arn", resourceName, "arn"),
resource.TestCheckResourceAttrPair(dataSourceName2, "ip_address_type", resourceName, "ip_address_type"),
resource.TestCheckResourceAttrPair(dataSourceName2, "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, "access_logs.#", resourceName, "access_logs.#"),
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.#"),
),
},
},
Expand Down
19 changes: 19 additions & 0 deletions aws/resource_aws_lb.go
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,13 @@ func resourceAwsLb() *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 @@ -411,13 +418,21 @@ func resourceAwsLbUpdate(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 @@ -764,6 +779,10 @@ func flattenAwsLbResource(d *schema.ResourceData, meta interface{}, lb *elbv2.Lo
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
112 changes: 112 additions & 0 deletions aws/resource_aws_lb_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,6 +187,7 @@ func TestAccAWSLB_LoadBalancerType_Gateway(t *testing.T) {
ImportStateVerifyIgnore: []string{
"drop_invalid_header_fields",
"enable_http2",
"enable_waf_fail_open",
"idle_timeout",
},
},
Expand Down Expand Up @@ -220,6 +221,7 @@ func TestAccAWSLB_LoadBalancerType_Gateway_EnableCrossZoneLoadBalancing(t *testi
ImportStateVerifyIgnore: []string{
"drop_invalid_header_fields",
"enable_http2",
"enable_waf_fail_open",
"idle_timeout",
},
},
Expand Down Expand Up @@ -555,6 +557,47 @@ func TestAccAWSLB_applicationLoadBalancer_updateHttp2(t *testing.T) {
})
}

func TestAccAWSLB_applicationLoadBalancer_updateWafFailOpen(t *testing.T) {
var pre, mid, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testaccawsalb-waf-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
resourceName := "aws_lb.lb_test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
IDRefreshName: resourceName,
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSLBDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSLBConfig_enableWafFailOpen(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists(resourceName, &pre),
testAccCheckAWSLBAttribute(resourceName, "waf.fail_open.enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "false"),
),
},
{
Config: testAccAWSLBConfig_enableWafFailOpen(lbName, true),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists(resourceName, &mid),
testAccCheckAWSLBAttribute(resourceName, "waf.fail_open.enabled", "true"),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "true"),
testAccCheckAWSlbARNs(&pre, &mid),
),
},
{
Config: testAccAWSLBConfig_enableWafFailOpen(lbName, false),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckAWSLBExists(resourceName, &post),
testAccCheckAWSLBAttribute(resourceName, "waf.fail_open.enabled", "false"),
resource.TestCheckResourceAttr(resourceName, "enable_waf_fail_open", "false"),
testAccCheckAWSlbARNs(&mid, &post),
),
},
},
})
}

func TestAccAWSLB_applicationLoadBalancer_updateDropInvalidHeaderFields(t *testing.T) {
var pre, mid, post elbv2.LoadBalancer
lbName := fmt.Sprintf("testaccawsalb-headers-%s", acctest.RandStringFromCharSet(10, acctest.CharSetAlphaNum))
Expand Down Expand Up @@ -1685,6 +1728,75 @@ resource "aws_security_group" "alb_test" {
`, lbName, http2))
}

func testAccAWSLBConfig_enableWafFailOpen(lbName string, wafFailOpen bool) string {
return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_lb" "lb_test" {
name = "%s"
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 = %t

tags = {
Name = "TestAccAWSALB_basic"
}
}

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

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 testAccAWSLBConfig_enableDropInvalidHeaderFields(lbName string, dropInvalid bool) string {
return composeConfig(testAccAvailableAZsNoOptInConfig(), fmt.Sprintf(`
resource "aws_lb" "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 @@ -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.
Expand Down