Repository: kubernetes-sigs/aws-alb-ingress-controller
Pull request #1136 (2020-01-17 00:23:10)

Add ALB attribute to configure dropping invalid headers
This adds an attribute to the ALB to configure dropping invalid headers. Please let me know if there's anything else required to get this merged.

AWS documentation for this feature is [here](https://docs.aws.amazon.com/elasticloadbalancing/latest/APIReference/API_LoadBalancerAttribute.html).

Thanks!


Patch:
diff --git a/internal/alb/lb/attributes.go b/internal/alb/lb/attributes.go
index a11329022..170e17250 100644
--- a/internal/alb/lb/attributes.go
+++ b/internal/alb/lb/attributes.go
@@ -13,19 +13,21 @@ import (
 )
 
 const (
-	DeletionProtectionEnabledKey = "deletion_protection.enabled"
-	AccessLogsS3EnabledKey       = "access_logs.s3.enabled"
-	AccessLogsS3BucketKey        = "access_logs.s3.bucket"
-	AccessLogsS3PrefixKey        = "access_logs.s3.prefix"
-	IdleTimeoutTimeoutSecondsKey = "idle_timeout.timeout_seconds"
-	RoutingHTTP2EnabledKey       = "routing.http2.enabled"
-
-	DeletionProtectionEnabled = false
-	AccessLogsS3Enabled       = false
-	AccessLogsS3Bucket        = ""
-	AccessLogsS3Prefix        = ""
-	IdleTimeoutTimeoutSeconds = 60
-	RoutingHTTP2Enabled       = true
+	DeletionProtectionEnabledKey      = "deletion_protection.enabled"
+	AccessLogsS3EnabledKey            = "access_logs.s3.enabled"
+	AccessLogsS3BucketKey             = "access_logs.s3.bucket"
+	AccessLogsS3PrefixKey             = "access_logs.s3.prefix"
+	IdleTimeoutTimeoutSecondsKey      = "idle_timeout.timeout_seconds"
+	RoutingHTTP2EnabledKey            = "routing.http2.enabled"
+	DropInvalidHeaderFieldsEnabledKey = "routing.http.drop_invalid_header_fields.enabled"
+
+	DeletionProtectionEnabled      = false
+	AccessLogsS3Enabled            = false
+	AccessLogsS3Bucket             = ""
+	AccessLogsS3Prefix             = ""
+	IdleTimeoutTimeoutSeconds      = 60
+	RoutingHTTP2Enabled            = true
+	DropInvalidHeaderFieldsEnabled = false
 )
 
 // Attributes represents the desired state of attributes for a load balancer.
@@ -55,16 +57,21 @@ type Attributes struct {
 	// RoutingHTTP2Enabled: routing.http2.enabled - Indicates whether HTTP/2 is enabled. The value
 	// is true or false. The default is true.
 	RoutingHTTP2Enabled bool
+
+	// DropInvalidHeaderFieldsEnabled: routing.http.drop_invalid_header_fields.enabled - Indicates if
+	// invalid headers will be dropped. The default is false.
+	DropInvalidHeaderFieldsEnabled bool
 }
 
 func NewAttributes(attrs []*elbv2.LoadBalancerAttribute) (a *Attributes, err error) {
 	a = &Attributes{
-		DeletionProtectionEnabled: DeletionProtectionEnabled,
-		AccessLogsS3Enabled:       AccessLogsS3Enabled,
-		AccessLogsS3Bucket:        AccessLogsS3Bucket,
-		AccessLogsS3Prefix:        AccessLogsS3Prefix,
-		IdleTimeoutTimeoutSeconds: IdleTimeoutTimeoutSeconds,
-		RoutingHTTP2Enabled:       RoutingHTTP2Enabled,
+		DeletionProtectionEnabled:      DeletionProtectionEnabled,
+		AccessLogsS3Enabled:            AccessLogsS3Enabled,
+		AccessLogsS3Bucket:             AccessLogsS3Bucket,
+		AccessLogsS3Prefix:             AccessLogsS3Prefix,
+		IdleTimeoutTimeoutSeconds:      IdleTimeoutTimeoutSeconds,
+		RoutingHTTP2Enabled:            RoutingHTTP2Enabled,
+		DropInvalidHeaderFieldsEnabled: DropInvalidHeaderFieldsEnabled,
 	}
 	var e error
 	for _, attr := range attrs {
@@ -97,6 +104,11 @@ func NewAttributes(attrs []*elbv2.LoadBalancerAttribute) (a *Attributes, err err
 			if err != nil {
 				return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
 			}
+		case DropInvalidHeaderFieldsEnabledKey:
+			a.DropInvalidHeaderFieldsEnabled, err = strconv.ParseBool(attrValue)
+			if err != nil {
+				return a, fmt.Errorf("invalid load balancer attribute value %s=%s", attrKey, attrValue)
+			}
 		default:
 			e = NewInvalidAttribute(attrKey)
 		}
@@ -184,6 +196,10 @@ func attributesChangeSet(current, desired *Attributes) (changeSet []*elbv2.LoadB
 		changeSet = append(changeSet, lbAttribute(RoutingHTTP2EnabledKey, fmt.Sprintf("%v", desired.RoutingHTTP2Enabled)))
 	}
 
+	if current.DropInvalidHeaderFieldsEnabled != desired.DropInvalidHeaderFieldsEnabled {
+		changeSet = append(changeSet, lbAttribute(DropInvalidHeaderFieldsEnabledKey, fmt.Sprintf("%v", desired.DropInvalidHeaderFieldsEnabled)))
+	}
+
 	return
 }
 


Test patch:
diff --git a/internal/alb/lb/attributes_test.go b/internal/alb/lb/attributes_test.go
index a4074989e..9c7d7f67d 100644
--- a/internal/alb/lb/attributes_test.go
+++ b/internal/alb/lb/attributes_test.go
@@ -63,6 +63,11 @@ func Test_NewAttributes(t *testing.T) {
 			ok:         false,
 			attributes: []*elbv2.LoadBalancerAttribute{lbAttribute(RoutingHTTP2EnabledKey, "falfadssdfdsse")},
 		},
+		{
+			name:       fmt.Sprintf("%v is invalid", DropInvalidHeaderFieldsEnabledKey),
+			ok:         false,
+			attributes: []*elbv2.LoadBalancerAttribute{lbAttribute(DropInvalidHeaderFieldsEnabledKey, "falfadssdfdsse")},
+		},
 		{
 			name:       fmt.Sprintf("undefined attribute"),
 			ok:         false,
@@ -78,14 +83,16 @@ func Test_NewAttributes(t *testing.T) {
 				lbAttribute(AccessLogsS3PrefixKey, "prefix"),
 				lbAttribute(IdleTimeoutTimeoutSecondsKey, "45"),
 				lbAttribute(RoutingHTTP2EnabledKey, "false"),
+				lbAttribute(DropInvalidHeaderFieldsEnabledKey, "true"),
 			},
 			output: &Attributes{
-				DeletionProtectionEnabled: true,
-				AccessLogsS3Enabled:       true,
-				AccessLogsS3Bucket:        "bucket name",
-				AccessLogsS3Prefix:        "prefix",
-				IdleTimeoutTimeoutSeconds: 45,
-				RoutingHTTP2Enabled:       false,
+				DeletionProtectionEnabled:      true,
+				AccessLogsS3Enabled:            true,
+				AccessLogsS3Bucket:             "bucket name",
+				AccessLogsS3Prefix:             "prefix",
+				IdleTimeoutTimeoutSeconds:      45,
+				RoutingHTTP2Enabled:            false,
+				DropInvalidHeaderFieldsEnabled: true,
 			},
 		},
 	} {
@@ -155,6 +162,12 @@ func Test_attributesChangeSet(t *testing.T) {
 			b:         MustNewAttributes([]*elbv2.LoadBalancerAttribute{lbAttribute(RoutingHTTP2EnabledKey, "false")}),
 			changeSet: []*elbv2.LoadBalancerAttribute{lbAttribute(RoutingHTTP2EnabledKey, "false")},
 		},
+		{
+			name:      fmt.Sprintf("a contains default, b contains non-default DropInvalidHeaderFieldsEnabledKey, make a change"),
+			a:         MustNewAttributes(nil),
+			b:         MustNewAttributes([]*elbv2.LoadBalancerAttribute{lbAttribute(DropInvalidHeaderFieldsEnabledKey, "true")}),
+			changeSet: []*elbv2.LoadBalancerAttribute{lbAttribute(DropInvalidHeaderFieldsEnabledKey, "true")},
+		},
 	} {
 		t.Run(tc.name, func(t *testing.T) {
 			changeSet := attributesChangeSet(tc.a, tc.b)
@@ -188,6 +201,7 @@ func defaultAttributes() []*elbv2.LoadBalancerAttribute {
 		lbAttribute(AccessLogsS3PrefixKey, ""),
 		lbAttribute(IdleTimeoutTimeoutSecondsKey, "60"),
 		lbAttribute(RoutingHTTP2EnabledKey, "true"),
+		lbAttribute(DropInvalidHeaderFieldsEnabledKey, "false"),
 	}
 }