From d50f3b9d20e200f7289ae38ef13822a8ab2b562f Mon Sep 17 00:00:00 2001
From: mikutas <23391543+mikutas@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:02:46 +0900
Subject: [PATCH 1/2] Add WAFv2ACLArn field to IngressClassParams

---
 apis/elbv2/v1beta1/ingressclassparams_types.go        |  4 ++++
 .../crd/bases/elbv2.k8s.aws_ingressclassparams.yaml   |  3 +++
 config/webhook/manifests.yaml                         |  1 -
 docs/guide/ingress/ingress_class.md                   | 11 +++++++++--
 helm/aws-load-balancer-controller/crds/crds.yaml      |  3 +++
 pkg/ingress/model_build_load_balancer_addons.go       |  5 +++++
 6 files changed, 24 insertions(+), 3 deletions(-)

diff --git a/apis/elbv2/v1beta1/ingressclassparams_types.go b/apis/elbv2/v1beta1/ingressclassparams_types.go
index 4fc9216946..cb7ab8a046 100644
--- a/apis/elbv2/v1beta1/ingressclassparams_types.go
+++ b/apis/elbv2/v1beta1/ingressclassparams_types.go
@@ -156,6 +156,10 @@ type IngressClassParamsSpec struct {
 	// MinimumLoadBalancerCapacity define the capacity reservation for LoadBalancers for all Ingress that belong to IngressClass with this IngressClassParams.
 	// +optional
 	MinimumLoadBalancerCapacity *MinimumLoadBalancerCapacity `json:"minimumLoadBalancerCapacity,omitempty"`
+
+	// WAFv2ACLArn specifies ARN for the Amazon WAFv2 web ACL.
+	// +optional
+	WAFv2ACLArn string `json:"wafv2AclArn"`
 }
 
 // +kubebuilder:object:root=true
diff --git a/config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml b/config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml
index 7f65f28ad7..4a7148db42 100644
--- a/config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml
+++ b/config/crd/bases/elbv2.k8s.aws_ingressclassparams.yaml
@@ -246,6 +246,9 @@ spec:
                   - value
                   type: object
                 type: array
+              wafv2AclArn:
+                description: WAFv2ACLArn specifies ARN for the Amazon WAFv2 web ACL.
+                type: string
             type: object
         type: object
     served: true
diff --git a/config/webhook/manifests.yaml b/config/webhook/manifests.yaml
index 0b1a24bfed..1493d5386a 100644
--- a/config/webhook/manifests.yaml
+++ b/config/webhook/manifests.yaml
@@ -1,4 +1,3 @@
----
 apiVersion: admissionregistration.k8s.io/v1
 kind: MutatingWebhookConfiguration
 metadata:
diff --git a/docs/guide/ingress/ingress_class.md b/docs/guide/ingress/ingress_class.md
index fd5d6ee954..51f811d9e2 100644
--- a/docs/guide/ingress/ingress_class.md
+++ b/docs/guide/ingress/ingress_class.md
@@ -187,8 +187,9 @@ Cluster administrators can use the optional `inboundCIDRs` field to specify the
 If the field is specified, LBC will ignore the `alb.ingress.kubernetes.io/inbound-cidrs` annotation.
 
 #### spec.certificateArn
+
 Cluster administrators can use the optional `certificateARN` field to specify the ARN of the certificates for all Ingresses that belong to IngressClass with this IngressClassParams.
-    
+
 If the field is specified, LBC will ignore the `alb.ingress.kubernetes.io/certificate-arn` annotation.
 
 #### spec.sslPolicy
@@ -251,4 +252,10 @@ They may specify `capacityUnits`. If the field is specified, LBC will ignore the
 
 ##### spec.minimumLoadBalancerCapacity.capacityUnits
 
-If `capacityUnits` is specified, it must be to valid positive value greater than 0. If set to 0, the LBC will reset the capacity reservation for the load balancer.
\ No newline at end of file
+If `capacityUnits` is specified, it must be to valid positive value greater than 0. If set to 0, the LBC will reset the capacity reservation for the load balancer.
+
+#### spec.wafv2AclArn
+
+Cluster administrators can use the optional `wafv2AclArn` field to specify ARN for the Amazon WAFv2 web ACL.
+Only Regional WAFv2 is supported.
+When this annotation is absent or empty, the controller will keep LoadBalancer WAFv2 settings unchanged. To disable WAFv2, explicitly set the annotation value to 'none'.
diff --git a/helm/aws-load-balancer-controller/crds/crds.yaml b/helm/aws-load-balancer-controller/crds/crds.yaml
index b72e687892..3b1048c677 100644
--- a/helm/aws-load-balancer-controller/crds/crds.yaml
+++ b/helm/aws-load-balancer-controller/crds/crds.yaml
@@ -245,6 +245,9 @@ spec:
                   - value
                   type: object
                 type: array
+              wafv2AclArn:
+                description: WAFv2ACLArn specifies ARN for the Amazon WAFv2 web ACL.
+                type: string
             type: object
         type: object
     served: true
diff --git a/pkg/ingress/model_build_load_balancer_addons.go b/pkg/ingress/model_build_load_balancer_addons.go
index dde8c7595c..f8bca68c14 100644
--- a/pkg/ingress/model_build_load_balancer_addons.go
+++ b/pkg/ingress/model_build_load_balancer_addons.go
@@ -2,6 +2,7 @@ package ingress
 
 import (
 	"context"
+
 	"github.com/pkg/errors"
 	"k8s.io/apimachinery/pkg/util/sets"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/annotations"
@@ -39,6 +40,10 @@ func (t *defaultModelBuildTask) buildWAFv2WebACLAssociation(_ context.Context, l
 		if rawWebACLARN != "" {
 			explicitWebACLARNs.Insert(rawWebACLARN)
 		}
+		params := member.IngClassConfig.IngClassParams
+		if params != nil && params.Spec.WAFv2ACLArn != "" {
+			explicitWebACLARNs.Insert(params.Spec.WAFv2ACLArn)
+		}
 	}
 	if len(explicitWebACLARNs) == 0 {
 		return nil, nil

From a64780e98dfe8cc9210f294a9100394a12d1683d Mon Sep 17 00:00:00 2001
From: mikutas <23391543+mikutas@users.noreply.github.com>
Date: Thu, 28 Nov 2024 22:27:56 +0900
Subject: [PATCH 2/2] Add a test

---
 pkg/ingress/model_builder_test.go | 108 +++++++++++++++++++++++++++++-
 1 file changed, 106 insertions(+), 2 deletions(-)

diff --git a/pkg/ingress/model_builder_test.go b/pkg/ingress/model_builder_test.go
index c9040a4b3e..21a9c3445d 100644
--- a/pkg/ingress/model_builder_test.go
+++ b/pkg/ingress/model_builder_test.go
@@ -3,11 +3,12 @@ package ingress
 import (
 	"context"
 	"encoding/json"
-	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
-	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
 	"testing"
 	"time"
 
+	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
+	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
+
 	awssdk "github.com/aws/aws-sdk-go-v2/aws"
 	jsonpatch "github.com/evanphx/json-patch"
 	"github.com/go-logr/logr"
@@ -2141,6 +2142,109 @@ func Test_defaultModelBuilder_Build(t *testing.T) {
 			"80:3": null
 		}
 	}
+}`,
+		},
+		{
+			name: "Ingress - wafv2AclArn in IngressClassParams",
+			env: env{
+				svcs: []*corev1.Service{ns_1_svc_1, ns_1_svc_2, ns_1_svc_3},
+			},
+			fields: fields{
+				resolveViaDiscoveryCalls: []resolveViaDiscoveryCall{resolveViaDiscoveryCallForInternalLB},
+				listLoadBalancersCalls:   []listLoadBalancersCall{listLoadBalancerCallForEmptyLB},
+				enableBackendSG:          true,
+			},
+			args: args{
+				ingGroup: Group{
+					ID: GroupID{Namespace: "ns-1", Name: "ing-1"},
+					Members: []ClassifiedIngress{
+						{
+							IngClassConfig: ClassConfiguration{
+								IngClassParams: &v1beta1.IngressClassParams{
+									Spec: v1beta1.IngressClassParamsSpec{
+										WAFv2ACLArn: "alb.ingress.kubernetes.io/wafv2-acl-arn: arn:aws:wafv2:us-west-2:xxxxx:regional/webacl/xxxxxxx/3ab78708-85b0-49d3-b4e1-7a9615a6613b",
+									},
+								},
+							},
+							Ing: &networking.Ingress{ObjectMeta: metav1.ObjectMeta{
+								Namespace: "ns-1",
+								Name:      "ing-1",
+							},
+								Spec: networking.IngressSpec{
+									Rules: []networking.IngressRule{
+										{
+											Host: "app-1.example.com",
+											IngressRuleValue: networking.IngressRuleValue{
+												HTTP: &networking.HTTPIngressRuleValue{
+													Paths: []networking.HTTPIngressPath{
+														{
+															Path: "/svc-1",
+															Backend: networking.IngressBackend{
+																Service: &networking.IngressServiceBackend{
+																	Name: ns_1_svc_1.Name,
+																	Port: networking.ServiceBackendPort{
+																		Name: "http",
+																	},
+																},
+															},
+														},
+														{
+															Path: "/svc-2",
+															Backend: networking.IngressBackend{
+																Service: &networking.IngressServiceBackend{
+																	Name: ns_1_svc_2.Name,
+																	Port: networking.ServiceBackendPort{
+																		Name: "http",
+																	},
+																},
+															},
+														},
+													},
+												},
+											},
+										},
+										{
+											Host: "app-2.example.com",
+											IngressRuleValue: networking.IngressRuleValue{
+												HTTP: &networking.HTTPIngressRuleValue{
+													Paths: []networking.HTTPIngressPath{
+														{
+															Path: "/svc-3",
+															Backend: networking.IngressBackend{
+																Service: &networking.IngressServiceBackend{
+																	Name: ns_1_svc_3.Name,
+																	Port: networking.ServiceBackendPort{
+																		Name: "https",
+																	},
+																},
+															},
+														},
+													},
+												},
+											},
+										},
+									},
+								},
+							},
+						},
+					},
+				},
+			},
+			wantStackPatch: `
+{
+    "id":"ns-1/ing-1",
+    "resources":{
+		"AWS::WAFv2::WebACLAssociation":{
+			"LoadBalancer":{
+				"spec":{
+					"resourceARN":{
+						"$ref":"#/resources/AWS::ElasticLoadBalancingV2::LoadBalancer/LoadBalancer/status/loadBalancerARN"
+					},
+					"webACLARN":"alb.ingress.kubernetes.io/wafv2-acl-arn: arn:aws:wafv2:us-west-2:xxxxx:regional/webacl/xxxxxxx/3ab78708-85b0-49d3-b4e1-7a9615a6613b"
+				}
+			}
+		}
+    }
 }`,
 		},
 		{