diff --git a/apis/gateway/v1beta1/loadbalancerconfig_types.go b/apis/gateway/v1beta1/loadbalancerconfig_types.go
index 076561bc59..c9a3e164a5 100644
--- a/apis/gateway/v1beta1/loadbalancerconfig_types.go
+++ b/apis/gateway/v1beta1/loadbalancerconfig_types.go
@@ -44,8 +44,8 @@ type ListenerAttribute struct {
 	Value string `json:"value"`
 }
 
-// Tag defines a AWS Tag on resources.
-type LoadBalancerTag struct {
+// AWSTag defines a AWS Tag on resources.
+type AWSTag struct {
 	// The key of the tag.
 	Key string `json:"key"`
 
@@ -183,10 +183,16 @@ type LoadBalancerConfigurationSpec struct {
 	// +optional
 	EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic *string `json:"enforceSecurityGroupInboundRulesOnPrivateLinkTraffic,omitempty"`
 
-	// customerOwnedIpv4Pool is the ID of the customer-owned address for Application Load Balancers on Outposts pool.
+	// customerOwnedIpv4Pool [Application LoadBalancer]
+	// is the ID of the customer-owned address for Application Load Balancers on Outposts pool.
 	// +optional
 	CustomerOwnedIpv4Pool *string `json:"customerOwnedIpv4Pool,omitempty"`
 
+	// IPv4IPAMPoolId [Application LoadBalancer]
+	// defines the IPAM pool ID used for IPv4 Addresses on the ALB.
+	// +optional
+	IPv4IPAMPoolId *string `json:"ipv4IPAMPoolId,omitempty"`
+
 	// loadBalancerSubnets is an optional list of subnet configurations to be used in the LB
 	// This value takes precedence over loadBalancerSubnetsSelector if both are selected.
 	// +optional
@@ -224,7 +230,19 @@ type LoadBalancerConfigurationSpec struct {
 
 	// Tags defines list of Tags on LB.
 	// +optional
-	Tags []LoadBalancerTag `json:"tags,omitempty"`
+	Tags []AWSTag `json:"tags,omitempty"`
+
+	// EnableICMP [Network LoadBalancer]
+	// enables the creation of security group rules to the managed security group
+	// to allow explicit ICMP traffic for Path MTU discovery for IPv4 and dual-stack VPCs
+	// +optional
+	EnableICMP bool `json:"enableICMP,omitempty"`
+
+	// ManageBackendSecurityGroupRules [Application / Network LoadBalancer]
+	// specifies whether you want the controller to configure security group rules on Node/Pod for traffic access
+	// when you specify securityGroups
+	// +optional
+	ManageBackendSecurityGroupRules bool `json:"manageBackendSecurityGroupRules,omitempty"`
 }
 
 // TODO -- these can be used to set what generation the gateway is currently on to track progress on reconcile.
diff --git a/apis/gateway/v1beta1/zz_generated.deepcopy.go b/apis/gateway/v1beta1/zz_generated.deepcopy.go
index 41bb66a02f..d4c9a325ab 100644
--- a/apis/gateway/v1beta1/zz_generated.deepcopy.go
+++ b/apis/gateway/v1beta1/zz_generated.deepcopy.go
@@ -25,6 +25,21 @@ import (
 	runtime "k8s.io/apimachinery/pkg/runtime"
 )
 
+// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
+func (in *AWSTag) DeepCopyInto(out *AWSTag) {
+	*out = *in
+}
+
+// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AWSTag.
+func (in *AWSTag) DeepCopy() *AWSTag {
+	if in == nil {
+		return nil
+	}
+	out := new(AWSTag)
+	in.DeepCopyInto(out)
+	return out
+}
+
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *HealthCheckConfiguration) DeepCopyInto(out *HealthCheckConfiguration) {
 	*out = *in
@@ -273,6 +288,11 @@ func (in *LoadBalancerConfigurationSpec) DeepCopyInto(out *LoadBalancerConfigura
 		*out = new(string)
 		**out = **in
 	}
+	if in.IPv4IPAMPoolId != nil {
+		in, out := &in.IPv4IPAMPoolId, &out.IPv4IPAMPoolId
+		*out = new(string)
+		**out = **in
+	}
 	if in.LoadBalancerSubnets != nil {
 		in, out := &in.LoadBalancerSubnets, &out.LoadBalancerSubnets
 		*out = new([]SubnetConfiguration)
@@ -354,7 +374,7 @@ func (in *LoadBalancerConfigurationSpec) DeepCopyInto(out *LoadBalancerConfigura
 	}
 	if in.Tags != nil {
 		in, out := &in.Tags, &out.Tags
-		*out = make([]LoadBalancerTag, len(*in))
+		*out = make([]AWSTag, len(*in))
 		copy(*out, *in)
 	}
 }
@@ -394,21 +414,6 @@ func (in *LoadBalancerConfigurationStatus) DeepCopy() *LoadBalancerConfiguration
 	return out
 }
 
-// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
-func (in *LoadBalancerTag) DeepCopyInto(out *LoadBalancerTag) {
-	*out = *in
-}
-
-// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new LoadBalancerTag.
-func (in *LoadBalancerTag) DeepCopy() *LoadBalancerTag {
-	if in == nil {
-		return nil
-	}
-	out := new(LoadBalancerTag)
-	in.DeepCopyInto(out)
-	return out
-}
-
 // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
 func (in *MutualAuthenticationAttributes) DeepCopyInto(out *MutualAuthenticationAttributes) {
 	*out = *in
diff --git a/config/crd/gateway/gateway-crds.yaml b/config/crd/gateway/gateway-crds.yaml
index 735b106b5e..846f287ce9 100644
--- a/config/crd/gateway/gateway-crds.yaml
+++ b/config/crd/gateway/gateway-crds.yaml
@@ -45,9 +45,16 @@ spec:
               LoadBalancerConfiguration
             properties:
               customerOwnedIpv4Pool:
-                description: customerOwnedIpv4Pool is the ID of the customer-owned
-                  address for Application Load Balancers on Outposts pool.
+                description: |-
+                  customerOwnedIpv4Pool [Application LoadBalancer]
+                  is the ID of the customer-owned address for Application Load Balancers on Outposts pool.
                 type: string
+              enableICMP:
+                description: |-
+                  EnableICMP [Network LoadBalancer]
+                  enables the creation of security group rules to the managed security group
+                  to allow explicit ICMP traffic for Path MTU discovery for IPv4 and dual-stack VPCs
+                type: boolean
               enforceSecurityGroupInboundRulesOnPrivateLinkTraffic:
                 description: enforceSecurityGroupInboundRulesOnPrivateLinkTraffic
                   Indicates whether to evaluate inbound security group rules for traffic
@@ -61,6 +68,11 @@ spec:
                 - dualstack
                 - dualstack-without-public-ipv4
                 type: string
+              ipv4IPAMPoolId:
+                description: |-
+                  IPv4IPAMPoolId [Application LoadBalancer]
+                  defines the IPAM pool ID used for IPv4 Addresses on the ALB.
+                type: string
               listenerConfigurations:
                 description: listenerConfigurations is an optional list of configurations
                   for each listener on LB
@@ -212,6 +224,12 @@ spec:
                   tag specified in the map key contains one of the values in the corresponding
                   value list.
                 type: object
+              manageBackendSecurityGroupRules:
+                description: |-
+                  ManageBackendSecurityGroupRules [Application / Network LoadBalancer]
+                  specifies whether you want the controller to configure security group rules on Node/Pod for traffic access
+                  when you specify securityGroups
+                type: boolean
               scheme:
                 description: scheme defines the type of LB to provision. If unspecified,
                   it will be automatically inferred.
@@ -240,7 +258,7 @@ spec:
               tags:
                 description: Tags defines list of Tags on LB.
                 items:
-                  description: Tag defines a AWS Tag on resources.
+                  description: AWSTag defines a AWS Tag on resources.
                   properties:
                     key:
                       description: The key of the tag.
diff --git a/config/crd/gateway/gateway.k8s.aws_loadbalancerconfigurations.yaml b/config/crd/gateway/gateway.k8s.aws_loadbalancerconfigurations.yaml
index c858e905ce..f146a9eb99 100644
--- a/config/crd/gateway/gateway.k8s.aws_loadbalancerconfigurations.yaml
+++ b/config/crd/gateway/gateway.k8s.aws_loadbalancerconfigurations.yaml
@@ -46,9 +46,16 @@ spec:
               LoadBalancerConfiguration
             properties:
               customerOwnedIpv4Pool:
-                description: customerOwnedIpv4Pool is the ID of the customer-owned
-                  address for Application Load Balancers on Outposts pool.
+                description: |-
+                  customerOwnedIpv4Pool [Application LoadBalancer]
+                  is the ID of the customer-owned address for Application Load Balancers on Outposts pool.
                 type: string
+              enableICMP:
+                description: |-
+                  EnableICMP [Network LoadBalancer]
+                  enables the creation of security group rules to the managed security group
+                  to allow explicit ICMP traffic for Path MTU discovery for IPv4 and dual-stack VPCs
+                type: boolean
               enforceSecurityGroupInboundRulesOnPrivateLinkTraffic:
                 description: enforceSecurityGroupInboundRulesOnPrivateLinkTraffic
                   Indicates whether to evaluate inbound security group rules for traffic
@@ -62,6 +69,11 @@ spec:
                 - dualstack
                 - dualstack-without-public-ipv4
                 type: string
+              ipv4IPAMPoolId:
+                description: |-
+                  IPv4IPAMPoolId [Application LoadBalancer]
+                  defines the IPAM pool ID used for IPv4 Addresses on the ALB.
+                type: string
               listenerConfigurations:
                 description: listenerConfigurations is an optional list of configurations
                   for each listener on LB
@@ -213,6 +225,12 @@ spec:
                   tag specified in the map key contains one of the values in the corresponding
                   value list.
                 type: object
+              manageBackendSecurityGroupRules:
+                description: |-
+                  ManageBackendSecurityGroupRules [Application / Network LoadBalancer]
+                  specifies whether you want the controller to configure security group rules on Node/Pod for traffic access
+                  when you specify securityGroups
+                type: boolean
               scheme:
                 description: scheme defines the type of LB to provision. If unspecified,
                   it will be automatically inferred.
@@ -241,7 +259,7 @@ spec:
               tags:
                 description: Tags defines list of Tags on LB.
                 items:
-                  description: Tag defines a AWS Tag on resources.
+                  description: AWSTag defines a AWS Tag on resources.
                   properties:
                     key:
                       description: The key of the tag.
diff --git a/controllers/gateway/gateway_controller.go b/controllers/gateway/gateway_controller.go
index 6c91111124..01b4abbbbc 100644
--- a/controllers/gateway/gateway_controller.go
+++ b/controllers/gateway/gateway_controller.go
@@ -26,6 +26,7 @@ import (
 	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/networking"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	ctrl "sigs.k8s.io/controller-runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
 	"sigs.k8s.io/controller-runtime/pkg/controller"
@@ -46,19 +47,19 @@ var _ Reconciler = &gatewayReconciler{}
 
 // NewNLBGatewayReconciler constructs a gateway reconciler to handle specifically for NLB gateways
 func NewNLBGatewayReconciler(routeLoader routeutils.Loader, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileCounters *metricsutil.ReconcileCounters) Reconciler {
-	return newGatewayReconciler(constants.NLBGatewayController, elbv2model.LoadBalancerTypeNetwork, controllerConfig.NLBGatewayMaxConcurrentReconciles, constants.NLBGatewayTagPrefix, constants.NLBGatewayFinalizer, routeLoader, routeutils.L4RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementNLBGateway)
+	return newGatewayReconciler(constants.NLBGatewayController, elbv2model.LoadBalancerTypeNetwork, controllerConfig.NLBGatewayMaxConcurrentReconciles, constants.NLBGatewayTagPrefix, shared_constants.NLBGatewayFinalizer, routeLoader, routeutils.L4RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementNLBGateway)
 }
 
 // NewALBGatewayReconciler constructs a gateway reconciler to handle specifically for ALB gateways
 func NewALBGatewayReconciler(routeLoader routeutils.Loader, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileCounters *metricsutil.ReconcileCounters) Reconciler {
-	return newGatewayReconciler(constants.ALBGatewayController, elbv2model.LoadBalancerTypeApplication, controllerConfig.ALBGatewayMaxConcurrentReconciles, constants.ALBGatewayTagPrefix, constants.ALBGatewayFinalizer, routeLoader, routeutils.L7RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementALBGateway)
+	return newGatewayReconciler(constants.ALBGatewayController, elbv2model.LoadBalancerTypeApplication, controllerConfig.ALBGatewayMaxConcurrentReconciles, constants.ALBGatewayTagPrefix, shared_constants.ALBGatewayFinalizer, routeLoader, routeutils.L7RouteFilter, cloud, k8sClient, eventRecorder, controllerConfig, finalizerManager, networkingSGReconciler, networkingSGManager, elbv2TaggingManager, subnetResolver, vpcInfoProvider, backendSGProvider, sgResolver, logger, metricsCollector, reconcileCounters.IncrementALBGateway)
 }
 
 // newGatewayReconciler constructs a reconciler that responds to gateway object changes
 func newGatewayReconciler(controllerName string, lbType elbv2model.LoadBalancerType, maxConcurrentReconciles int, gatewayTagPrefix string, finalizer string, routeLoader routeutils.Loader, routeFilter routeutils.LoadRouteFilter, cloud services.Cloud, k8sClient client.Client, eventRecorder record.EventRecorder, controllerConfig config.ControllerConfig, finalizerManager k8s.FinalizerManager, networkingSGReconciler networking.SecurityGroupReconciler, networkingSGManager networking.SecurityGroupManager, elbv2TaggingManager elbv2deploy.TaggingManager, subnetResolver networking.SubnetsResolver, vpcInfoProvider networking.VPCInfoProvider, backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, logger logr.Logger, metricsCollector lbcmetrics.MetricCollector, reconcileTracker func(namespaceName types.NamespacedName)) Reconciler {
 
 	trackingProvider := tracking.NewDefaultProvider(gatewayTagPrefix, controllerConfig.ClusterName)
-	modelBuilder := gatewaymodel.NewModelBuilder(subnetResolver, vpcInfoProvider, cloud.VpcID(), lbType, trackingProvider, elbv2TaggingManager, cloud.EC2(), controllerConfig.FeatureGates, controllerConfig.ClusterName, controllerConfig.DefaultTags, sets.New(controllerConfig.ExternalManagedTags...), controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, controllerConfig.DefaultLoadBalancerScheme, backendSGProvider, sgResolver, controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, logger)
+	modelBuilder := gatewaymodel.NewModelBuilder(subnetResolver, vpcInfoProvider, cloud.VpcID(), lbType, trackingProvider, elbv2TaggingManager, controllerConfig, cloud.EC2(), controllerConfig.FeatureGates, controllerConfig.ClusterName, controllerConfig.DefaultTags, sets.New(controllerConfig.ExternalManagedTags...), controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, controllerConfig.DefaultLoadBalancerScheme, backendSGProvider, sgResolver, controllerConfig.EnableBackendSecurityGroup, controllerConfig.DisableRestrictedSGRules, logger)
 
 	stackMarshaller := deploy.NewDefaultStackMarshaller()
 	stackDeployer := deploy.NewDefaultStackDeployer(cloud, k8sClient, networkingSGManager, networkingSGReconciler, elbv2TaggingManager, controllerConfig, gatewayTagPrefix, logger, metricsCollector, controllerName)
diff --git a/controllers/service/service_controller.go b/controllers/service/service_controller.go
index 6aa7383dfd..2357ba4deb 100644
--- a/controllers/service/service_controller.go
+++ b/controllers/service/service_controller.go
@@ -3,6 +3,7 @@ package service
 import (
 	"context"
 	"fmt"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 
 	"sigs.k8s.io/controller-runtime/pkg/reconcile"
 
@@ -33,7 +34,6 @@ import (
 )
 
 const (
-	serviceFinalizer        = "service.k8s.aws/resources"
 	serviceTagPrefix        = "service.k8s.aws"
 	serviceAnnotationPrefix = "service.beta.kubernetes.io"
 	controllerName          = "service"
@@ -47,7 +47,7 @@ func NewServiceReconciler(cloud services.Cloud, k8sClient client.Client, eventRe
 
 	annotationParser := annotations.NewSuffixAnnotationParser(serviceAnnotationPrefix)
 	trackingProvider := tracking.NewDefaultProvider(serviceTagPrefix, controllerConfig.ClusterName)
-	serviceUtils := service.NewServiceUtils(annotationParser, serviceFinalizer, controllerConfig.ServiceConfig.LoadBalancerClass, controllerConfig.FeatureGates)
+	serviceUtils := service.NewServiceUtils(annotationParser, shared_constants.ServiceFinalizer, controllerConfig.ServiceConfig.LoadBalancerClass, controllerConfig.FeatureGates)
 	modelBuilder := service.NewDefaultModelBuilder(annotationParser, subnetsResolver, vpcInfoProvider, cloud.VpcID(), trackingProvider,
 		elbv2TaggingManager, cloud.EC2(), controllerConfig.FeatureGates, controllerConfig.ClusterName, controllerConfig.DefaultTags, controllerConfig.ExternalManagedTags,
 		controllerConfig.DefaultSSLPolicy, controllerConfig.DefaultTargetType, controllerConfig.DefaultLoadBalancerScheme, controllerConfig.FeatureGates.Enabled(config.EnableIPTargetType), serviceUtils,
@@ -170,7 +170,7 @@ func (r *serviceReconciler) reconcileLoadBalancerResources(ctx context.Context,
 
 	var err error
 	addFinalizersFn := func() {
-		err = r.finalizerManager.AddFinalizers(ctx, svc, serviceFinalizer)
+		err = r.finalizerManager.AddFinalizers(ctx, svc, shared_constants.ServiceFinalizer)
 	}
 	r.metricsCollector.ObserveControllerReconcileLatency(controllerName, "add_finalizers", addFinalizersFn)
 	if err != nil {
@@ -214,7 +214,7 @@ func (r *serviceReconciler) reconcileLoadBalancerResources(ctx context.Context,
 }
 
 func (r *serviceReconciler) cleanupLoadBalancerResources(ctx context.Context, svc *corev1.Service, stack core.Stack) error {
-	if k8s.HasFinalizer(svc, serviceFinalizer) {
+	if k8s.HasFinalizer(svc, shared_constants.ServiceFinalizer) {
 		err := r.deployModel(ctx, svc, stack)
 		if err != nil {
 			return err
@@ -226,7 +226,7 @@ func (r *serviceReconciler) cleanupLoadBalancerResources(ctx context.Context, sv
 			r.eventRecorder.Event(svc, corev1.EventTypeWarning, k8s.ServiceEventReasonFailedCleanupStatus, fmt.Sprintf("Failed update status due to %v", err))
 			return err
 		}
-		if err := r.finalizerManager.RemoveFinalizers(ctx, svc, serviceFinalizer); err != nil {
+		if err := r.finalizerManager.RemoveFinalizers(ctx, svc, shared_constants.ServiceFinalizer); err != nil {
 			r.eventRecorder.Event(svc, corev1.EventTypeWarning, k8s.ServiceEventReasonFailedRemoveFinalizer, fmt.Sprintf("Failed remove finalizer due to %v", err))
 			return err
 		}
diff --git a/main.go b/main.go
index f0f1250dfc..e57c640037 100644
--- a/main.go
+++ b/main.go
@@ -148,6 +148,8 @@ func main() {
 		os.Exit(1)
 	}
 
+	nlbGatewayEnabled := controllerCFG.FeatureGates.Enabled(config.NLBGatewayAPI)
+	albGatewayEnabled := controllerCFG.FeatureGates.Enabled(config.ALBGatewayAPI)
 	podInfoRepo := k8s.NewDefaultPodInfoRepo(clientSet.CoreV1().RESTClient(), controllerCFG.RuntimeConfig.WatchNamespace, ctrl.Log)
 	finalizerManager := k8s.NewDefaultFinalizerManager(mgr.GetClient(), ctrl.Log)
 	sgManager := networking.NewDefaultSecurityGroupManager(cloud.EC2(), ctrl.Log)
@@ -165,7 +167,7 @@ func main() {
 		cloud.VpcID(), controllerCFG.ClusterName, controllerCFG.FeatureGates.Enabled(config.EndpointsFailOpen), controllerCFG.EnableEndpointSlices, controllerCFG.DisableRestrictedSGRules,
 		controllerCFG.ServiceTargetENISGTags, mgr.GetEventRecorderFor("targetGroupBinding"), ctrl.Log)
 	backendSGProvider := networking.NewBackendSGProvider(controllerCFG.ClusterName, controllerCFG.BackendSecurityGroup,
-		cloud.VpcID(), cloud.EC2(), mgr.GetClient(), controllerCFG.DefaultTags, ctrl.Log.WithName("backend-sg-provider"))
+		cloud.VpcID(), cloud.EC2(), mgr.GetClient(), controllerCFG.DefaultTags, nlbGatewayEnabled || albGatewayEnabled, ctrl.Log.WithName("backend-sg-provider"))
 	sgResolver := networking.NewDefaultSecurityGroupResolver(cloud.EC2(), cloud.VpcID())
 	elbv2TaggingManager := elbv2deploy.NewDefaultTaggingManager(cloud.ELBV2(), cloud.VpcID(), controllerCFG.FeatureGates, cloud.RGT(), ctrl.Log)
 	ingGroupReconciler := ingress.NewGroupReconciler(cloud, mgr.GetClient(), mgr.GetEventRecorderFor("ingress"),
@@ -221,7 +223,7 @@ func main() {
 		}
 
 		// Setup NLB Gateway controller if enabled
-		if controllerCFG.FeatureGates.Enabled(config.NLBGatewayAPI) {
+		if nlbGatewayEnabled {
 			gwControllerConfig.routeLoader = routeutils.NewLoader(mgr.GetClient())
 			if err := setupGatewayController(ctx, mgr, gwControllerConfig, constants.NLBGatewayController); err != nil {
 				setupLog.Error(err, "failed to setup NLB Gateway controller")
@@ -230,7 +232,7 @@ func main() {
 		}
 
 		// Setup ALB Gateway controller if enabled
-		if controllerCFG.FeatureGates.Enabled(config.ALBGatewayAPI) {
+		if albGatewayEnabled {
 			if gwControllerConfig.routeLoader == nil {
 				gwControllerConfig.routeLoader = routeutils.NewLoader(mgr.GetClient())
 			}
diff --git a/pkg/config/controller_config.go b/pkg/config/controller_config.go
index 1f0903af8a..3aa091c4fc 100644
--- a/pkg/config/controller_config.go
+++ b/pkg/config/controller_config.go
@@ -1,6 +1,7 @@
 package config
 
 import (
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"strings"
 	"time"
 
@@ -45,12 +46,16 @@ const (
 
 var (
 	trackingTagKeys = sets.NewString(
-		"elbv2.k8s.aws/cluster",
-		"elbv2.k8s.aws/resource",
+		shared_constants.TagKeyK8sCluster,
+		shared_constants.TagKeyResource,
 		"ingress.k8s.aws/stack",
 		"ingress.k8s.aws/resource",
 		"service.k8s.aws/stack",
 		"service.k8s.aws/resource",
+		"gateway.k8s.aws.nlb/resource",
+		"gateway.k8s.aws.alb/resource",
+		"gateway.k8s.aws.nlb/stack",
+		"gateway.k8s.aws.alb/stack",
 	)
 )
 
diff --git a/pkg/config/controller_config_test.go b/pkg/config/controller_config_test.go
index 0351ded53f..74ec7ae382 100644
--- a/pkg/config/controller_config_test.go
+++ b/pkg/config/controller_config_test.go
@@ -3,6 +3,7 @@ package config
 import (
 	"github.com/pkg/errors"
 	"github.com/stretchr/testify/assert"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"testing"
 )
 
@@ -28,7 +29,7 @@ func TestControllerConfig_validateDefaultTagsCollisionWithTrackingTags(t *testin
 			name: "default tags and tracking tags have collision",
 			fields: fields{
 				DefaultTags: map[string]string{
-					"elbv2.k8s.aws/cluster": "value-a",
+					shared_constants.TagKeyK8sCluster: "value-a",
 				},
 			},
 			wantErr: errors.New("tag key elbv2.k8s.aws/cluster cannot be specified in default-tags flag"),
@@ -75,7 +76,7 @@ func TestControllerConfig_validateExternalManagedTagsCollisionWithTrackingTags(t
 		{
 			name: "external managed tags and tracking tags have collision",
 			fields: fields{
-				ExternalManagedTags: []string{"elbv2.k8s.aws/cluster"},
+				ExternalManagedTags: []string{shared_constants.TagKeyK8sCluster},
 			},
 			wantErr: errors.New("tag key elbv2.k8s.aws/cluster cannot be specified in external-managed-tags flag"),
 		},
diff --git a/pkg/deploy/elbv2/load_balancer_synthesizer.go b/pkg/deploy/elbv2/load_balancer_synthesizer.go
index 629071cce8..aee7c696fb 100644
--- a/pkg/deploy/elbv2/load_balancer_synthesizer.go
+++ b/pkg/deploy/elbv2/load_balancer_synthesizer.go
@@ -14,13 +14,10 @@ import (
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
 	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"strings"
 )
 
-const (
-	lbAttrsDeletionProtectionEnabled = "deletion_protection.enabled"
-)
-
 // NewLoadBalancerSynthesizer constructs loadBalancerSynthesizer
 func NewLoadBalancerSynthesizer(elbv2Client services.ELBV2, trackingProvider tracking.Provider, taggingManager TaggingManager,
 	lbManager LoadBalancerManager, logger logr.Logger, featureGates config.FeatureGates, controllerConfig config.ControllerConfig, stack core.Stack) *loadBalancerSynthesizer {
@@ -116,7 +113,7 @@ func (s *loadBalancerSynthesizer) disableDeletionProtection(ctx context.Context,
 	input := &elbv2sdk.ModifyLoadBalancerAttributesInput{
 		Attributes: []elbv2types.LoadBalancerAttribute{
 			{
-				Key:   awssdk.String(lbAttrsDeletionProtectionEnabled),
+				Key:   awssdk.String(shared_constants.LBAttributeDeletionProtection),
 				Value: awssdk.String("false"),
 			},
 		},
diff --git a/pkg/deploy/tracking/provider.go b/pkg/deploy/tracking/provider.go
index 32194e5b3d..7545fabfc4 100644
--- a/pkg/deploy/tracking/provider.go
+++ b/pkg/deploy/tracking/provider.go
@@ -4,8 +4,11 @@ import (
 	"fmt"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/algorithm"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 )
 
+// TODO(ztn) - Add Gateway documentation here?
+
 //we use AWS tags and K8s labels to track resources we have created.
 //
 //For AWS resources created by this controller, the tagging strategy is as follows:
@@ -32,9 +35,6 @@ import (
 //    * `service.k8s.aws/stack-namespace: namespace`
 //    * `service.k8s.aws/stack-name: serviceName`
 
-// AWS TagKey for cluster resources.
-const clusterNameTagKey = "elbv2.k8s.aws/cluster"
-
 // Legacy AWS TagKey for cluster resources, which is used by AWSALBIngressController(v1.1.3+)
 const clusterNameTagKeyLegacy = "ingress.k8s.aws/cluster"
 
@@ -85,8 +85,8 @@ func (p *defaultProvider) ResourceIDTagKey() string {
 func (p *defaultProvider) StackTags(stack core.Stack) map[string]string {
 	stackID := stack.StackID()
 	return map[string]string{
-		clusterNameTagKey:              p.clusterName,
-		p.prefixedTrackingKey("stack"): stackID.String(),
+		shared_constants.TagKeyK8sCluster: p.clusterName,
+		p.prefixedTrackingKey("stack"):    stackID.String(),
 	}
 }
 
diff --git a/pkg/deploy/tracking/provider_test.go b/pkg/deploy/tracking/provider_test.go
index 2d1e926682..4ce75e6d11 100644
--- a/pkg/deploy/tracking/provider_test.go
+++ b/pkg/deploy/tracking/provider_test.go
@@ -3,6 +3,7 @@ package tracking
 import (
 	"github.com/stretchr/testify/assert"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"testing"
 )
 
@@ -46,8 +47,8 @@ func Test_defaultProvider_StackTags(t *testing.T) {
 			provider: NewDefaultProvider("ingress.k8s.aws", "cluster-name"),
 			args:     args{stack: core.NewDefaultStack(core.StackID{Namespace: "", Name: "awesome-group"})},
 			want: map[string]string{
-				"elbv2.k8s.aws/cluster": "cluster-name",
-				"ingress.k8s.aws/stack": "awesome-group",
+				shared_constants.TagKeyK8sCluster: "cluster-name",
+				"ingress.k8s.aws/stack":           "awesome-group",
 			},
 		},
 		{
@@ -55,8 +56,8 @@ func Test_defaultProvider_StackTags(t *testing.T) {
 			provider: NewDefaultProvider("ingress.k8s.aws", "cluster-name"),
 			args:     args{stack: core.NewDefaultStack(core.StackID{Namespace: "namespace", Name: "ingressName"})},
 			want: map[string]string{
-				"elbv2.k8s.aws/cluster": "cluster-name",
-				"ingress.k8s.aws/stack": "namespace/ingressName",
+				shared_constants.TagKeyK8sCluster: "cluster-name",
+				"ingress.k8s.aws/stack":           "namespace/ingressName",
 			},
 		},
 		{
@@ -64,8 +65,8 @@ func Test_defaultProvider_StackTags(t *testing.T) {
 			provider: NewDefaultProvider("service.k8s.aws", "cluster-name"),
 			args:     args{stack: core.NewDefaultStack(core.StackID{Namespace: "namespace", Name: "serviceName"})},
 			want: map[string]string{
-				"elbv2.k8s.aws/cluster": "cluster-name",
-				"service.k8s.aws/stack": "namespace/serviceName",
+				shared_constants.TagKeyK8sCluster: "cluster-name",
+				"service.k8s.aws/stack":           "namespace/serviceName",
 			},
 		},
 	}
@@ -100,9 +101,9 @@ func Test_defaultProvider_ResourceTags(t *testing.T) {
 				res:   fakeRes,
 			},
 			want: map[string]string{
-				"elbv2.k8s.aws/cluster":    "cluster-name",
-				"ingress.k8s.aws/stack":    "namespace/ingressName",
-				"ingress.k8s.aws/resource": "fake-id",
+				shared_constants.TagKeyK8sCluster: "cluster-name",
+				"ingress.k8s.aws/stack":           "namespace/ingressName",
+				"ingress.k8s.aws/resource":        "fake-id",
 			},
 		},
 	}
diff --git a/pkg/gateway/constants/controller_constants.go b/pkg/gateway/constants/controller_constants.go
index 194a0373fa..cac44acb3b 100644
--- a/pkg/gateway/constants/controller_constants.go
+++ b/pkg/gateway/constants/controller_constants.go
@@ -25,9 +25,6 @@ const (
 
 	// NLBRouteResourceGroupVersion the groupVersion used by TCPRoute and UDPRoute
 	NLBRouteResourceGroupVersion = "gateway.networking.k8s.io/v1alpha2"
-
-	// NLBGatewayFinalizer the finalizer we attach the NLB Gateway object
-	NLBGatewayFinalizer = "gateway.k8s.aws/nlb-finalizer"
 )
 
 /*
@@ -43,7 +40,4 @@ const (
 
 	// ALBRouteResourceGroupVersion the groupVersion used by HTTPRoute and GRPCRoute
 	ALBRouteResourceGroupVersion = "gateway.networking.k8s.io/v1"
-
-	// ALBGatewayFinalizer the finalizer we attach the ALB Gateway object
-	ALBGatewayFinalizer = "gateway.k8s.aws/alb-finalizer"
 )
diff --git a/pkg/gateway/model/base_model_builder.go b/pkg/gateway/model/base_model_builder.go
index 83f22b266e..78245db66d 100644
--- a/pkg/gateway/model/base_model_builder.go
+++ b/pkg/gateway/model/base_model_builder.go
@@ -15,6 +15,7 @@ import (
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
 	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/networking"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 	"strconv"
 )
@@ -28,15 +29,24 @@ type Builder interface {
 // NewModelBuilder construct a new baseModelBuilder
 func NewModelBuilder(subnetsResolver networking.SubnetsResolver,
 	vpcInfoProvider networking.VPCInfoProvider, vpcID string, loadBalancerType elbv2model.LoadBalancerType, trackingProvider tracking.Provider,
-	elbv2TaggingManager elbv2deploy.TaggingManager, ec2Client services.EC2, featureGates config.FeatureGates, clusterName string, defaultTags map[string]string,
+	elbv2TaggingManager elbv2deploy.TaggingManager, lbcConfig config.ControllerConfig, ec2Client services.EC2, featureGates config.FeatureGates, clusterName string, defaultTags map[string]string,
 	externalManagedTags sets.Set[string], defaultSSLPolicy string, defaultTargetType string, defaultLoadBalancerScheme string,
 	backendSGProvider networking.BackendSGProvider, sgResolver networking.SecurityGroupResolver, enableBackendSG bool,
 	disableRestrictedSGRules bool, logger logr.Logger) Builder {
 
+	gwTagHelper := newTagHelper(sets.New(lbcConfig.ExternalManagedTags...), lbcConfig.DefaultTags)
 	subnetBuilder := newSubnetModelBuilder(loadBalancerType, trackingProvider, subnetsResolver, elbv2TaggingManager)
+	sgBuilder := newSecurityGroupBuilder(gwTagHelper, clusterName, enableBackendSG, sgResolver, backendSGProvider, logger)
+	lbBuilder := newLoadBalancerBuilder(loadBalancerType, gwTagHelper, clusterName)
 
 	return &baseModelBuilder{
-		lbBuilder: newLoadBalancerBuilder(subnetBuilder, defaultLoadBalancerScheme),
+		subnetBuilder:        subnetBuilder,
+		securityGroupBuilder: sgBuilder,
+		lbBuilder:            lbBuilder,
+		logger:               logger,
+
+		defaultLoadBalancerScheme: elbv2model.LoadBalancerScheme(defaultLoadBalancerScheme),
+		defaultIPType:             elbv2model.IPAddressTypeIPV4,
 	}
 }
 
@@ -45,25 +55,62 @@ var _ Builder = &baseModelBuilder{}
 type baseModelBuilder struct {
 	lbBuilder loadBalancerBuilder
 	logger    logr.Logger
+
+	subnetBuilder        subnetModelBuilder
+	securityGroupBuilder securityGroupBuilder
+
+	defaultLoadBalancerScheme elbv2model.LoadBalancerScheme
+	defaultIPType             elbv2model.IPAddressType
 }
 
 func (baseBuilder *baseModelBuilder) Build(ctx context.Context, gw *gwv1.Gateway, lbConf *elbv2gw.LoadBalancerConfiguration, routes map[int][]routeutils.RouteDescriptor) (core.Stack, *elbv2model.LoadBalancer, bool, error) {
+	stack := core.NewDefaultStack(core.StackID(k8s.NamespacedName(gw)))
 	if gw.DeletionTimestamp != nil && !gw.DeletionTimestamp.IsZero() {
 		if baseBuilder.isDeleteProtected(lbConf) {
 			return nil, nil, false, errors.Errorf("Unable to delete gateway %+v because deletion protection is enabled.", k8s.NamespacedName(gw))
 		}
+		return stack, nil, false, nil
 	}
 
-	stack := core.NewDefaultStack(core.StackID(k8s.NamespacedName(gw)))
+	/* Basic LB stuff (Scheme, IP Address Type) */
+	scheme, err := baseBuilder.buildLoadBalancerScheme(lbConf)
+
+	if err != nil {
+		return nil, nil, false, err
+	}
+
+	ipAddressType, err := baseBuilder.buildLoadBalancerIPAddressType(lbConf)
+
+	if err != nil {
+		return nil, nil, false, err
+	}
+
+	/* Subnets */
+
+	subnets, err := baseBuilder.subnetBuilder.buildLoadBalancerSubnets(ctx, lbConf.Spec.LoadBalancerSubnets, lbConf.Spec.LoadBalancerSubnetsSelector, scheme, ipAddressType, stack)
+
+	if err != nil {
+		return nil, nil, false, err
+	}
+
+	/* Security Groups */
+
+	securityGroups, err := baseBuilder.securityGroupBuilder.buildSecurityGroups(ctx, stack, lbConf, gw, routes, ipAddressType)
+
+	if err != nil {
+		return nil, nil, false, err
+	}
 
-	// TODO - Fix
-	_, err := baseBuilder.lbBuilder.buildLoadBalancerSpec(ctx, gw, stack, lbConf, routes)
+	/* Combine everything to form a LoadBalancer */
+	spec, err := baseBuilder.lbBuilder.buildLoadBalancerSpec(scheme, ipAddressType, gw, lbConf, subnets, securityGroups.securityGroupTokens)
 
 	if err != nil {
 		return nil, nil, false, err
 	}
 
-	return stack, nil, false, nil
+	lb := elbv2model.NewLoadBalancer(stack, resourceIDLoadBalancer, spec)
+
+	return stack, lb, securityGroups.backendSecurityGroupAllocated, nil
 }
 
 func (baseBuilder *baseModelBuilder) isDeleteProtected(lbConf *elbv2gw.LoadBalancerConfiguration) bool {
@@ -72,7 +119,7 @@ func (baseBuilder *baseModelBuilder) isDeleteProtected(lbConf *elbv2gw.LoadBalan
 	}
 
 	for _, attr := range lbConf.Spec.LoadBalancerAttributes {
-		if attr.Key == deletionProtectionAttributeKey {
+		if attr.Key == shared_constants.LBAttributeDeletionProtection {
 			deletionProtectionEnabled, err := strconv.ParseBool(attr.Value)
 
 			if err != nil {
@@ -86,3 +133,38 @@ func (baseBuilder *baseModelBuilder) isDeleteProtected(lbConf *elbv2gw.LoadBalan
 
 	return false
 }
+
+func (baseBuilder *baseModelBuilder) buildLoadBalancerScheme(lbConf *elbv2gw.LoadBalancerConfiguration) (elbv2model.LoadBalancerScheme, error) {
+	scheme := lbConf.Spec.Scheme
+
+	if scheme == nil {
+		return baseBuilder.defaultLoadBalancerScheme, nil
+	}
+	switch *scheme {
+	case elbv2gw.LoadBalancerScheme(elbv2model.LoadBalancerSchemeInternetFacing):
+		return elbv2model.LoadBalancerSchemeInternetFacing, nil
+	case elbv2gw.LoadBalancerScheme(elbv2model.LoadBalancerSchemeInternal):
+		return elbv2model.LoadBalancerSchemeInternal, nil
+	default:
+		return "", errors.Errorf("unknown scheme: %v", *scheme)
+	}
+}
+
+// buildLoadBalancerIPAddressType builds the LoadBalancer IPAddressType.
+func (baseBuilder *baseModelBuilder) buildLoadBalancerIPAddressType(lbConf *elbv2gw.LoadBalancerConfiguration) (elbv2model.IPAddressType, error) {
+
+	if lbConf.Spec.IpAddressType == nil {
+		return baseBuilder.defaultIPType, nil
+	}
+
+	switch *lbConf.Spec.IpAddressType {
+	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeIPV4):
+		return elbv2model.IPAddressTypeIPV4, nil
+	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeDualStack):
+		return elbv2model.IPAddressTypeDualStack, nil
+	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeDualStackWithoutPublicIPV4):
+		return elbv2model.IPAddressTypeDualStackWithoutPublicIPV4, nil
+	default:
+		return "", errors.Errorf("unknown IPAddressType: %v", *lbConf.Spec.IpAddressType)
+	}
+}
diff --git a/pkg/gateway/model/constants.go b/pkg/gateway/model/constants.go
deleted file mode 100644
index 327cd6f28a..0000000000
--- a/pkg/gateway/model/constants.go
+++ /dev/null
@@ -1,5 +0,0 @@
-package model
-
-const (
-	deletionProtectionAttributeKey = "deletion_protection.enabled"
-)
diff --git a/pkg/gateway/model/gateway_tag_helper.go b/pkg/gateway/model/gateway_tag_helper.go
new file mode 100644
index 0000000000..892abdd899
--- /dev/null
+++ b/pkg/gateway/model/gateway_tag_helper.go
@@ -0,0 +1,56 @@
+package model
+
+import (
+	"github.com/pkg/errors"
+	"k8s.io/apimachinery/pkg/util/sets"
+	elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/algorithm"
+)
+
+type tagHelper interface {
+	getGatewayTags(lbConf *elbv2gw.LoadBalancerConfiguration) (map[string]string, error)
+}
+
+type tagHelperImpl struct {
+	externalManagedTags sets.Set[string]
+	defaultTags         map[string]string
+}
+
+func newTagHelper(externalManagedTags sets.Set[string], defaultTags map[string]string) tagHelper {
+	return &tagHelperImpl{
+		externalManagedTags: externalManagedTags,
+		defaultTags:         defaultTags,
+	}
+}
+
+func (t *tagHelperImpl) getGatewayTags(lbConf *elbv2gw.LoadBalancerConfiguration) (map[string]string, error) {
+	var annotationTags map[string]string
+
+	if lbConf != nil {
+		annotationTags = t.convertTagsToMap(lbConf.Spec.Tags)
+	}
+
+	if err := t.validateTagCollisionWithExternalManagedTags(annotationTags); err != nil {
+		return nil, err
+	}
+
+	return algorithm.MergeStringMap(t.defaultTags, annotationTags), nil
+}
+
+func (t *tagHelperImpl) validateTagCollisionWithExternalManagedTags(tags map[string]string) error {
+	for tagKey := range tags {
+		if t.externalManagedTags.Has(tagKey) {
+			return errors.Errorf("external managed tag key %v cannot be specified", tagKey)
+		}
+	}
+	return nil
+}
+
+func (t *tagHelperImpl) convertTagsToMap(tags []elbv2gw.AWSTag) map[string]string {
+	m := make(map[string]string)
+
+	for _, tag := range tags {
+		m[tag.Key] = tag.Value
+	}
+	return m
+}
diff --git a/pkg/gateway/model/mock_gateway_tag_helper.go b/pkg/gateway/model/mock_gateway_tag_helper.go
new file mode 100644
index 0000000000..fe063ff75a
--- /dev/null
+++ b/pkg/gateway/model/mock_gateway_tag_helper.go
@@ -0,0 +1,14 @@
+package model
+
+import elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
+
+type mockTagHelper struct {
+	tags map[string]string
+	err  error
+}
+
+func (m *mockTagHelper) getGatewayTags(lbConf *elbv2gw.LoadBalancerConfiguration) (map[string]string, error) {
+	return m.tags, m.err
+}
+
+var _ tagHelper = &mockTagHelper{}
diff --git a/pkg/gateway/model/model_build_loadbalancer.go b/pkg/gateway/model/model_build_loadbalancer.go
index 98945e4d8d..3eddc0016b 100644
--- a/pkg/gateway/model/model_build_loadbalancer.go
+++ b/pkg/gateway/model/model_build_loadbalancer.go
@@ -1,97 +1,123 @@
 package model
 
 import (
-	"context"
-	"github.com/pkg/errors"
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	"regexp"
 	elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
-	"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
 	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
 	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 )
 
+var invalidLoadBalancerNamePattern = regexp.MustCompile("[[:^alnum:]]")
+
+const (
+	resourceIDLoadBalancer = "LoadBalancer"
+)
+
 type loadBalancerBuilder interface {
-	buildLoadBalancerSpec(ctx context.Context, gw *gwv1.Gateway, stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, routes map[int][]routeutils.RouteDescriptor) (elbv2model.LoadBalancerSpec, error)
+	buildLoadBalancerSpec(scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, gw *gwv1.Gateway, lbConf *elbv2gw.LoadBalancerConfiguration, subnets buildLoadBalancerSubnetsOutput, securityGroupTokens []core.StringToken) (elbv2model.LoadBalancerSpec, error)
 }
 
 type loadBalancerBuilderImpl struct {
-	subnetBuilder subnetModelBuilder
-
-	defaultLoadBalancerScheme elbv2model.LoadBalancerScheme
-	defaultIPType             elbv2model.IPAddressType
+	loadBalancerType elbv2model.LoadBalancerType
+	clusterName      string
+	tagHelper        tagHelper
 }
 
-func newLoadBalancerBuilder(subnetBuilder subnetModelBuilder, defaultLoadBalancerScheme string) loadBalancerBuilder {
-
+func newLoadBalancerBuilder(loadBalancerType elbv2model.LoadBalancerType, tagHelper tagHelper, clusterName string) loadBalancerBuilder {
 	return &loadBalancerBuilderImpl{
-		subnetBuilder:             subnetBuilder,
-		defaultLoadBalancerScheme: elbv2model.LoadBalancerScheme(defaultLoadBalancerScheme),
-		defaultIPType:             elbv2model.IPAddressTypeIPV4,
+		loadBalancerType: loadBalancerType,
+		clusterName:      clusterName,
+		tagHelper:        tagHelper,
 	}
 }
 
-func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerSpec(ctx context.Context, gw *gwv1.Gateway, stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, routes map[int][]routeutils.RouteDescriptor) (elbv2model.LoadBalancerSpec, error) {
-	scheme, err := lbModelBuilder.buildLoadBalancerScheme(lbConf)
+func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerSpec(scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, gw *gwv1.Gateway, lbConf *elbv2gw.LoadBalancerConfiguration, subnets buildLoadBalancerSubnetsOutput, securityGroupTokens []core.StringToken) (elbv2model.LoadBalancerSpec, error) {
+
+	name, err := lbModelBuilder.buildLoadBalancerName(lbConf, gw, scheme)
 	if err != nil {
 		return elbv2model.LoadBalancerSpec{}, err
 	}
-	ipAddressType, err := lbModelBuilder.buildLoadBalancerIPAddressType(lbConf)
+
+	tags, err := lbModelBuilder.tagHelper.getGatewayTags(lbConf)
 	if err != nil {
 		return elbv2model.LoadBalancerSpec{}, err
 	}
-	configuredSubnets, sourcePrefixEnabled, err := lbModelBuilder.subnetBuilder.buildLoadBalancerSubnets(ctx, lbConf.Spec.LoadBalancerSubnets, lbConf.Spec.LoadBalancerSubnetsSelector, scheme, ipAddressType, stack)
-	if err != nil {
-		return elbv2model.LoadBalancerSpec{}, err
+
+	spec := elbv2model.LoadBalancerSpec{
+		Name:                        name,
+		Type:                        lbModelBuilder.loadBalancerType,
+		Scheme:                      scheme,
+		IPAddressType:               ipAddressType,
+		SubnetMappings:              subnets.subnets,
+		SecurityGroups:              securityGroupTokens,
+		LoadBalancerAttributes:      lbModelBuilder.buildLoadBalancerAttributes(lbConf),
+		MinimumLoadBalancerCapacity: lbModelBuilder.buildLoadBalancerMinimumCapacity(lbConf),
+		Tags:                        tags,
 	}
 
-	return elbv2model.LoadBalancerSpec{
-		Type:                         elbv2model.LoadBalancerTypeApplication,
-		Scheme:                       scheme,
-		IPAddressType:                ipAddressType,
-		SubnetMappings:               configuredSubnets,
-		EnablePrefixForIpv6SourceNat: lbModelBuilder.translateSourcePrefixEnabled(sourcePrefixEnabled),
-	}, nil
-}
+	if lbModelBuilder.loadBalancerType == elbv2model.LoadBalancerTypeNetwork {
+		lbModelBuilder.addL4Fields(&spec, lbConf, subnets)
+	}
 
-func (lbModelBuilder *loadBalancerBuilderImpl) translateSourcePrefixEnabled(b bool) elbv2model.EnablePrefixForIpv6SourceNat {
-	if b {
-		return elbv2model.EnablePrefixForIpv6SourceNatOn
+	if lbModelBuilder.loadBalancerType == elbv2model.LoadBalancerTypeApplication {
+		lbModelBuilder.addL7Fields(&spec, lbConf)
 	}
-	return elbv2model.EnablePrefixForIpv6SourceNatOff
 
+	return spec, nil
 }
 
-func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerScheme(lbConf *elbv2gw.LoadBalancerConfiguration) (elbv2model.LoadBalancerScheme, error) {
-	scheme := lbConf.Spec.Scheme
+func (lbModelBuilder *loadBalancerBuilderImpl) addL4Fields(spec *elbv2model.LoadBalancerSpec, lbConf *elbv2gw.LoadBalancerConfiguration, subnets buildLoadBalancerSubnetsOutput) {
+	spec.EnablePrefixForIpv6SourceNat = lbModelBuilder.translateSourcePrefixEnabled(subnets.sourceIPv6NatEnabled)
 
-	if scheme == nil {
-		return lbModelBuilder.defaultLoadBalancerScheme, nil
-	}
-	switch *scheme {
-	case elbv2gw.LoadBalancerScheme(elbv2model.LoadBalancerSchemeInternetFacing):
-		return elbv2model.LoadBalancerSchemeInternetFacing, nil
-	case elbv2gw.LoadBalancerScheme(elbv2model.LoadBalancerSchemeInternal):
-		return elbv2model.LoadBalancerSchemeInternal, nil
-	default:
-		return "", errors.Errorf("unknown scheme: %v", *scheme)
+	if lbConf.Spec.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic != nil {
+		spec.SecurityGroupsInboundRulesOnPrivateLink = (*elbv2model.SecurityGroupsInboundRulesOnPrivateLinkStatus)(lbConf.Spec.EnforceSecurityGroupInboundRulesOnPrivateLinkTraffic)
 	}
 }
 
-// buildLoadBalancerIPAddressType builds the LoadBalancer IPAddressType.
-func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerIPAddressType(lbConf *elbv2gw.LoadBalancerConfiguration) (elbv2model.IPAddressType, error) {
+func (lbModelBuilder *loadBalancerBuilderImpl) addL7Fields(spec *elbv2model.LoadBalancerSpec, lbConf *elbv2gw.LoadBalancerConfiguration) {
+	spec.CustomerOwnedIPv4Pool = lbConf.Spec.CustomerOwnedIpv4Pool
+	spec.IPv4IPAMPool = lbConf.Spec.IPv4IPAMPoolId
+}
+
+func (lbModelBuilder *loadBalancerBuilderImpl) translateSourcePrefixEnabled(sourceNATEnabled bool) elbv2model.EnablePrefixForIpv6SourceNat {
+	if sourceNATEnabled {
+		return elbv2model.EnablePrefixForIpv6SourceNatOn
+	}
+	return elbv2model.EnablePrefixForIpv6SourceNatOff
+}
 
-	if lbConf.Spec.IpAddressType == nil {
-		return lbModelBuilder.defaultIPType, nil
+func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerName(lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, scheme elbv2model.LoadBalancerScheme) (string, error) {
+	if lbConf.Spec.LoadBalancerName != nil {
+		name := *lbConf.Spec.LoadBalancerName
+		return name, nil
 	}
+	uuidHash := sha256.New()
+	_, _ = uuidHash.Write([]byte(lbModelBuilder.clusterName))
+	_, _ = uuidHash.Write([]byte(gw.UID))
+	_, _ = uuidHash.Write([]byte(scheme))
+	uuid := hex.EncodeToString(uuidHash.Sum(nil))
+
+	sanitizedNamespace := invalidLoadBalancerNamePattern.ReplaceAllString(gw.Namespace, "")
+	sanitizedName := invalidLoadBalancerNamePattern.ReplaceAllString(gw.Name, "")
+	return fmt.Sprintf("k8s-%.8s-%.8s-%.10s", sanitizedNamespace, sanitizedName, uuid), nil
+}
 
-	switch *lbConf.Spec.IpAddressType {
-	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeIPV4):
-		return elbv2model.IPAddressTypeIPV4, nil
-	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeDualStack):
-		return elbv2model.IPAddressTypeDualStack, nil
-	case elbv2gw.LoadBalancerIpAddressType(elbv2model.IPAddressTypeDualStackWithoutPublicIPV4):
-		return elbv2model.IPAddressTypeDualStackWithoutPublicIPV4, nil
-	default:
-		return "", errors.Errorf("unknown IPAddressType: %v", *lbConf.Spec.IpAddressType)
+func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerAttributes(lbConf *elbv2gw.LoadBalancerConfiguration) []elbv2model.LoadBalancerAttribute {
+	var attributes []elbv2model.LoadBalancerAttribute
+	for _, attr := range lbConf.Spec.LoadBalancerAttributes {
+		attributes = append(attributes, elbv2model.LoadBalancerAttribute{
+			Key:   attr.Key,
+			Value: attr.Value,
+		})
 	}
+	return attributes
+}
+
+// TODO -- Fill this in at a later time.
+func (lbModelBuilder *loadBalancerBuilderImpl) buildLoadBalancerMinimumCapacity(lbConf *elbv2gw.LoadBalancerConfiguration) *elbv2model.MinimumLoadBalancerCapacity {
+	return nil
 }
diff --git a/pkg/gateway/model/model_build_security_group.go b/pkg/gateway/model/model_build_security_group.go
new file mode 100644
index 0000000000..d657398383
--- /dev/null
+++ b/pkg/gateway/model/model_build_security_group.go
@@ -0,0 +1,311 @@
+package model
+
+import (
+	"context"
+	"crypto/sha256"
+	"encoding/hex"
+	"fmt"
+	awssdk "github.com/aws/aws-sdk-go-v2/aws"
+	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
+	"github.com/go-logr/logr"
+	"github.com/pkg/errors"
+	"k8s.io/apimachinery/pkg/types"
+	"k8s.io/apimachinery/pkg/util/sets"
+	"regexp"
+	elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
+	ec2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/ec2"
+	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/networking"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"strings"
+)
+
+var (
+	invalidSecurityGroupNamePtn = regexp.MustCompile("[[:^alnum:]]")
+)
+
+const (
+	resourceIDManagedSecurityGroup = "ManagedLBSecurityGroup"
+
+	managedSGDescription = "[k8s] Managed SecurityGroup for LoadBalancer"
+)
+
+type securityGroupOutput struct {
+	securityGroupTokens           []core.StringToken
+	backendSecurityGroupToken     core.StringToken
+	backendSecurityGroupAllocated bool
+}
+
+type securityGroupBuilder interface {
+	buildSecurityGroups(ctx context.Context, stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, routes map[int][]routeutils.RouteDescriptor, ipAddressType elbv2model.IPAddressType) (securityGroupOutput, error)
+}
+
+type securityGroupBuilderImpl struct {
+	tagHelper         tagHelper
+	clusterName       string
+	sgResolver        networking.SecurityGroupResolver
+	backendSGProvider networking.BackendSGProvider
+
+	enableBackendSG bool
+	logger          logr.Logger
+}
+
+func newSecurityGroupBuilder(tagHelper tagHelper, clusterName string, enableBackendSG bool, sgResolver networking.SecurityGroupResolver, backendSGProvider networking.BackendSGProvider, logger logr.Logger) securityGroupBuilder {
+	return &securityGroupBuilderImpl{
+		tagHelper:         tagHelper,
+		clusterName:       clusterName,
+		logger:            logger,
+		enableBackendSG:   enableBackendSG,
+		sgResolver:        sgResolver,
+		backendSGProvider: backendSGProvider,
+	}
+}
+
+func (builder *securityGroupBuilderImpl) buildSecurityGroups(ctx context.Context, stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, routes map[int][]routeutils.RouteDescriptor, ipAddressType elbv2model.IPAddressType) (securityGroupOutput, error) {
+	var sgNameOrIds []string
+	if lbConf != nil && lbConf.Spec.SecurityGroups != nil {
+		sgNameOrIds = *lbConf.Spec.SecurityGroups
+	}
+
+	if len(sgNameOrIds) == 0 {
+		return builder.handleManagedSecurityGroup(ctx, stack, lbConf, gw, routes, ipAddressType)
+	}
+
+	return builder.handleExplicitSecurityGroups(ctx, lbConf, gw, sgNameOrIds)
+}
+
+func (builder *securityGroupBuilderImpl) handleManagedSecurityGroup(ctx context.Context, stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, routes map[int][]routeutils.RouteDescriptor, ipAddressType elbv2model.IPAddressType) (securityGroupOutput, error) {
+	var lbSGTokens []core.StringToken
+	managedSG, err := builder.buildManagedSecurityGroup(stack, lbConf, gw, routes, ipAddressType)
+	if err != nil {
+		return securityGroupOutput{}, err
+	}
+	lbSGTokens = append(lbSGTokens, managedSG.GroupID())
+	var backendSecurityGroupToken core.StringToken
+	var backendSGAllocated bool
+	if !builder.enableBackendSG {
+		backendSecurityGroupToken = managedSG.GroupID()
+	} else {
+		backendSecurityGroupToken, err = builder.getBackendSecurityGroup(ctx, gw)
+		if err != nil {
+			return securityGroupOutput{}, err
+		}
+		backendSGAllocated = true
+		lbSGTokens = append(lbSGTokens, backendSecurityGroupToken)
+	}
+	builder.logger.Info("Auto Create SG", "LB SGs", lbSGTokens, "backend SG", backendSecurityGroupToken)
+	return securityGroupOutput{
+		securityGroupTokens:           lbSGTokens,
+		backendSecurityGroupToken:     backendSecurityGroupToken,
+		backendSecurityGroupAllocated: backendSGAllocated,
+	}, nil
+}
+
+func (builder *securityGroupBuilderImpl) handleExplicitSecurityGroups(ctx context.Context, lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, sgNameOrIds []string) (securityGroupOutput, error) {
+	var lbSGTokens []core.StringToken
+	manageBackendSGRules := lbConf.Spec.ManageBackendSecurityGroupRules
+	frontendSGIDs, err := builder.sgResolver.ResolveViaNameOrID(ctx, sgNameOrIds)
+	if err != nil {
+		return securityGroupOutput{}, err
+	}
+	for _, sgID := range frontendSGIDs {
+		lbSGTokens = append(lbSGTokens, core.LiteralStringToken(sgID))
+	}
+
+	var backendSecurityGroupToken core.StringToken
+	var backendSGAllocated bool
+	if manageBackendSGRules {
+		if !builder.enableBackendSG {
+			return securityGroupOutput{}, errors.New("backendSG feature is required to manage worker node SG rules when frontendSG manually specified")
+		}
+		backendSecurityGroupToken, err = builder.getBackendSecurityGroup(ctx, gw)
+		if err != nil {
+			return securityGroupOutput{}, err
+		}
+		backendSGAllocated = true
+		lbSGTokens = append(lbSGTokens, backendSecurityGroupToken)
+	}
+	builder.logger.Info("SG configured via annotation", "LB SGs", lbSGTokens, "backend SG", backendSecurityGroupToken)
+	return securityGroupOutput{
+		securityGroupTokens:           lbSGTokens,
+		backendSecurityGroupToken:     backendSecurityGroupToken,
+		backendSecurityGroupAllocated: backendSGAllocated,
+	}, nil
+}
+
+func (builder *securityGroupBuilderImpl) getBackendSecurityGroup(ctx context.Context, gw *gwv1.Gateway) (core.StringToken, error) {
+	backendSGID, err := builder.backendSGProvider.Get(ctx, networking.ResourceTypeGateway, []types.NamespacedName{k8s.NamespacedName(gw)})
+	if err != nil {
+		return nil, err
+	}
+	return core.LiteralStringToken(backendSGID), nil
+}
+
+func (builder *securityGroupBuilderImpl) buildManagedSecurityGroup(stack core.Stack, lbConf *elbv2gw.LoadBalancerConfiguration, gw *gwv1.Gateway, routes map[int][]routeutils.RouteDescriptor, ipAddressType elbv2model.IPAddressType) (*ec2model.SecurityGroup, error) {
+	name := builder.buildManagedSecurityGroupName(gw)
+	tags, err := builder.tagHelper.getGatewayTags(lbConf)
+	if err != nil {
+		return nil, err
+	}
+
+	ingressPermissions := builder.buildManagedSecurityGroupIngressPermissions(lbConf, routes, ipAddressType)
+	return ec2model.NewSecurityGroup(stack, resourceIDManagedSecurityGroup, ec2model.SecurityGroupSpec{
+		GroupName:   name,
+		Description: managedSGDescription,
+		Tags:        tags,
+		Ingress:     ingressPermissions,
+	}), nil
+}
+
+func (builder *securityGroupBuilderImpl) buildManagedSecurityGroupName(gw *gwv1.Gateway) string {
+	uuidHash := sha256.New()
+	_, _ = uuidHash.Write([]byte(builder.clusterName))
+	_, _ = uuidHash.Write([]byte(gw.Name))
+	_, _ = uuidHash.Write([]byte(gw.Namespace))
+	_, _ = uuidHash.Write([]byte(gw.UID))
+	uuid := hex.EncodeToString(uuidHash.Sum(nil))
+
+	sanitizedNamespace := invalidSecurityGroupNamePtn.ReplaceAllString(gw.Namespace, "")
+	sanitizedName := invalidSecurityGroupNamePtn.ReplaceAllString(gw.Name, "")
+	return fmt.Sprintf("k8s-%.8s-%.8s-%.10s", sanitizedNamespace, sanitizedName, uuid)
+}
+
+func (builder *securityGroupBuilderImpl) buildManagedSecurityGroupIngressPermissions(lbConf *elbv2gw.LoadBalancerConfiguration, routes map[int][]routeutils.RouteDescriptor, ipAddressType elbv2model.IPAddressType) []ec2model.IPPermission {
+	var permissions []ec2model.IPPermission
+
+	// Default to 0.0.0.0/0 and ::/0
+	// If user specified actual ranges, then these values will be overridden.
+	// TODO - Document this
+	sourceRanges := []string{
+		"0.0.0.0/0",
+		"::/0",
+	}
+	var prefixes []string
+	var enableICMP bool
+
+	if lbConf != nil && lbConf.Spec.SourceRanges != nil {
+		sourceRanges = *lbConf.Spec.SourceRanges
+	}
+
+	if lbConf != nil && lbConf.Spec.SecurityGroupPrefixes != nil {
+		prefixes = *lbConf.Spec.SecurityGroupPrefixes
+	}
+
+	if lbConf != nil && lbConf.Spec.EnableICMP {
+		enableICMP = true
+	}
+
+	includeIPv6 := isIPv6Supported(ipAddressType)
+
+	// Port Loop
+	for port, cfg := range routes {
+		// Protocol Loop
+		for _, protocol := range generateProtocolListFromRoutes(cfg) {
+			// CIDR Loop
+			for _, cidr := range sourceRanges {
+				isIPv6 := isIPv6CIDR(cidr)
+
+				if !isIPv6 {
+					permissions = append(permissions, ec2model.IPPermission{
+						IPProtocol: protocol,
+						FromPort:   awssdk.Int32(int32(port)),
+						ToPort:     awssdk.Int32(int32(port)),
+						IPRanges: []ec2model.IPRange{
+							{
+								CIDRIP: cidr,
+							},
+						},
+					})
+
+					if enableICMP {
+						permissions = append(permissions, ec2model.IPPermission{
+							IPProtocol: shared_constants.ICMPV4Protocol,
+							FromPort:   awssdk.Int32(shared_constants.ICMPV4TypeForPathMtu),
+							ToPort:     awssdk.Int32(shared_constants.ICMPV4CodeForPathMtu),
+							IPRanges: []ec2model.IPRange{
+								{
+									CIDRIP: cidr,
+								},
+							},
+						})
+					}
+
+				} else if includeIPv6 {
+					permissions = append(permissions, ec2model.IPPermission{
+						IPProtocol: protocol,
+						FromPort:   awssdk.Int32(int32(port)),
+						ToPort:     awssdk.Int32(int32(port)),
+						IPv6Range: []ec2model.IPv6Range{
+							{
+								CIDRIPv6: cidr,
+							},
+						},
+					})
+
+					if enableICMP {
+						permissions = append(permissions, ec2model.IPPermission{
+							IPProtocol: shared_constants.ICMPV6Protocol,
+							FromPort:   awssdk.Int32(shared_constants.ICMPV6TypeForPathMtu),
+							ToPort:     awssdk.Int32(shared_constants.ICMPV6CodeForPathMtu),
+							IPv6Range: []ec2model.IPv6Range{
+								{
+									CIDRIPv6: cidr,
+								},
+							},
+						})
+					}
+				}
+			} // CIDR Loop
+			// PL loop
+			for _, prefixID := range prefixes {
+				permissions = append(permissions, ec2model.IPPermission{
+					IPProtocol: protocol,
+					FromPort:   awssdk.Int32(int32(port)),
+					ToPort:     awssdk.Int32(int32(port)),
+					PrefixLists: []ec2model.PrefixList{
+						{
+							ListID: prefixID,
+						},
+					},
+				})
+			} // PL Loop
+		} // Protocol Loop
+	} // Port Loop
+	return permissions
+}
+
+func generateProtocolListFromRoutes(routes []routeutils.RouteDescriptor) []string {
+	protocolSet := sets.New[string]()
+
+	for _, route := range routes {
+		switch route.GetRouteKind() {
+		case routeutils.HTTPRouteKind, routeutils.GRPCRouteKind, routeutils.TCPRouteKind, routeutils.TLSRouteKind:
+			protocolSet.Insert(string(ec2types.ProtocolTcp))
+			break
+		case routeutils.UDPRouteKind:
+			protocolSet = protocolSet.Insert(string(ec2types.ProtocolUdp))
+			break
+		default:
+			// Ignore? Throw error?
+		}
+	}
+	return protocolSet.UnsortedList()
+}
+
+func isIPv6Supported(ipAddressType elbv2model.IPAddressType) bool {
+	switch ipAddressType {
+	case elbv2model.IPAddressTypeDualStack, elbv2model.IPAddressTypeDualStackWithoutPublicIPV4:
+		return true
+	default:
+		return false
+	}
+}
+
+// TODO - Refactor?
+func isIPv6CIDR(cidr string) bool {
+	return strings.Contains(cidr, ":")
+}
diff --git a/pkg/gateway/model/model_build_security_group_test.go b/pkg/gateway/model/model_build_security_group_test.go
new file mode 100644
index 0000000000..a7bfacbed7
--- /dev/null
+++ b/pkg/gateway/model/model_build_security_group_test.go
@@ -0,0 +1,918 @@
+package model
+
+import (
+	"context"
+	"fmt"
+	awssdk "github.com/aws/aws-sdk-go-v2/aws"
+	"github.com/go-logr/logr"
+	"github.com/golang/mock/gomock"
+	"github.com/pkg/errors"
+	"github.com/stretchr/testify/assert"
+	"k8s.io/apimachinery/pkg/types"
+	elbv2gw "sigs.k8s.io/aws-load-balancer-controller/apis/gateway/v1beta1"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/gateway/routeutils"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
+	coremodel "sigs.k8s.io/aws-load-balancer-controller/pkg/model/core"
+	ec2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/ec2"
+	elbv2model "sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/networking"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
+	"testing"
+)
+
+func Test_BuildSecurityGroups_Specified(t *testing.T) {
+	const clusterName = "my-cluster"
+
+	type resolveSgCall struct {
+		securityGroups []string
+		err            error
+	}
+
+	type backendSgProviderCall struct {
+		sgId string
+		err  error
+	}
+
+	testCases := []struct {
+		name            string
+		lbConf          *elbv2gw.LoadBalancerConfiguration
+		ipAddressType   elbv2model.IPAddressType
+		expectedTags    map[string]string
+		tagErr          error
+		enableBackendSg bool
+
+		resolveSg    *resolveSgCall
+		providerCall *backendSgProviderCall
+
+		expectErr              bool
+		expectedBackendSgToken coremodel.StringToken
+		expectedSgTokens       []coremodel.StringToken
+		backendSgAllocated     bool
+	}{
+		{
+			name: "sg specified - no backend sg",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SecurityGroups: &[]string{
+						"sg1",
+						"sg2",
+					},
+				},
+			},
+			resolveSg: &resolveSgCall{
+				securityGroups: []string{
+					"sg1",
+					"sg2",
+				},
+			},
+			expectedSgTokens: []coremodel.StringToken{
+				coremodel.LiteralStringToken("sg1"),
+				coremodel.LiteralStringToken("sg2"),
+			},
+		},
+		{
+			name:            "sg specified - with backend sg",
+			enableBackendSg: true,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+					SecurityGroups: &[]string{
+						"sg1",
+						"sg2",
+					},
+				},
+			},
+			resolveSg: &resolveSgCall{
+				securityGroups: []string{
+					"sg1",
+					"sg2",
+				},
+			},
+			providerCall: &backendSgProviderCall{
+				sgId: "auto-allocated",
+			},
+			expectedSgTokens: []coremodel.StringToken{
+				coremodel.LiteralStringToken("sg1"),
+				coremodel.LiteralStringToken("sg2"),
+				coremodel.LiteralStringToken("auto-allocated"),
+			},
+			expectedBackendSgToken: coremodel.LiteralStringToken("auto-allocated"),
+			backendSgAllocated:     true,
+		},
+		{
+			name: "sg specified - with backend sg - error - backendsg not enabled",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+					SecurityGroups: &[]string{
+						"sg1",
+						"sg2",
+					},
+				},
+			},
+			resolveSg: &resolveSgCall{
+				securityGroups: []string{
+					"sg1",
+					"sg2",
+				},
+			},
+			expectErr: true,
+		},
+		{
+			name:            "sg specified - with backend sg - error - resolve sg error",
+			enableBackendSg: true,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+					SecurityGroups: &[]string{
+						"sg1",
+						"sg2",
+					},
+				},
+			},
+			resolveSg: &resolveSgCall{
+				err: errors.New("bad thing"),
+			},
+			expectErr: true,
+		},
+		{
+			name:            "sg specified - with backend sg - error - resolve sg error",
+			enableBackendSg: true,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+					SecurityGroups: &[]string{
+						"sg1",
+						"sg2",
+					},
+				},
+			},
+			resolveSg: &resolveSgCall{
+				securityGroups: []string{
+					"sg1",
+					"sg2",
+				},
+			},
+			providerCall: &backendSgProviderCall{
+				err: errors.New("bad thing"),
+			},
+			expectErr: true,
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctrl := gomock.NewController(t)
+			defer ctrl.Finish()
+
+			mockTagger := &mockTagHelper{
+				tags: tc.expectedTags,
+				err:  tc.tagErr,
+			}
+
+			gw := &gwv1.Gateway{}
+			gw.Name = "my-gw"
+			gw.Namespace = "my-namespace"
+
+			mockSgProvider := networking.NewMockBackendSGProvider(ctrl)
+			mockSgResolver := networking.NewMockSecurityGroupResolver(ctrl)
+
+			if tc.resolveSg != nil {
+				mockSgResolver.EXPECT().ResolveViaNameOrID(gomock.Any(), gomock.Eq(*tc.lbConf.Spec.SecurityGroups)).Return(tc.resolveSg.securityGroups, tc.resolveSg.err).Times(1)
+			}
+
+			if tc.providerCall != nil {
+				mockSgProvider.EXPECT().Get(gomock.Any(), gomock.Eq(networking.ResourceType(networking.ResourceTypeGateway)), gomock.Eq([]types.NamespacedName{k8s.NamespacedName(gw)})).Return(tc.providerCall.sgId, tc.providerCall.err).Times(1)
+			}
+
+			stack := coremodel.NewDefaultStack(coremodel.StackID{Namespace: "namespace", Name: "name"})
+			builder := newSecurityGroupBuilder(mockTagger, clusterName, tc.enableBackendSg, mockSgResolver, mockSgProvider, logr.Discard())
+
+			out, err := builder.buildSecurityGroups(context.Background(), stack, tc.lbConf, gw, make(map[int][]routeutils.RouteDescriptor), tc.ipAddressType)
+
+			if tc.expectErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tc.expectedBackendSgToken, out.backendSecurityGroupToken)
+			assert.Equal(t, tc.expectedSgTokens, out.securityGroupTokens)
+			assert.Equal(t, tc.backendSgAllocated, out.backendSecurityGroupAllocated)
+		})
+	}
+}
+
+func Test_BuildSecurityGroups_Allocate(t *testing.T) {
+	const clusterName = "my-cluster"
+
+	type backendSgProviderCall struct {
+		sgId string
+		err  error
+	}
+
+	testCases := []struct {
+		name            string
+		lbConf          *elbv2gw.LoadBalancerConfiguration
+		ipAddressType   elbv2model.IPAddressType
+		expectedTags    map[string]string
+		tagErr          error
+		enableBackendSg bool
+
+		providerCall *backendSgProviderCall
+
+		expectErr              bool
+		hasBackendSg           bool
+		backendSgAllocated     bool
+		expectedStackResources int
+	}{
+		{
+			name: "sg allocate - no backend sg",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{},
+			},
+			expectedStackResources: 1,
+		},
+		{
+			name:            "sg allocate - with backend sg",
+			enableBackendSg: true,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+				},
+			},
+			providerCall: &backendSgProviderCall{
+				sgId: "auto-allocated",
+			},
+			backendSgAllocated:     true,
+			expectedStackResources: 1,
+		},
+		{
+			name:            "sg allocate - provider error",
+			enableBackendSg: true,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					ManageBackendSecurityGroupRules: true,
+				},
+			},
+			providerCall: &backendSgProviderCall{
+				err: errors.New("bad thing"),
+			},
+			expectErr: true,
+		},
+		{
+			name: "sg allocate - tag error",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{},
+			},
+			expectErr: true,
+			tagErr:    errors.New("bad thing"),
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			ctrl := gomock.NewController(t)
+			defer ctrl.Finish()
+
+			mockTagger := &mockTagHelper{
+				tags: tc.expectedTags,
+				err:  tc.tagErr,
+			}
+
+			gw := &gwv1.Gateway{}
+			gw.Name = "my-gw"
+			gw.Namespace = "my-namespace"
+
+			mockSgProvider := networking.NewMockBackendSGProvider(ctrl)
+			mockSgResolver := networking.NewMockSecurityGroupResolver(ctrl)
+
+			if tc.providerCall != nil {
+				mockSgProvider.EXPECT().Get(gomock.Any(), gomock.Eq(networking.ResourceType(networking.ResourceTypeGateway)), gomock.Eq([]types.NamespacedName{k8s.NamespacedName(gw)})).Return(tc.providerCall.sgId, tc.providerCall.err).Times(1)
+			}
+
+			stack := coremodel.NewDefaultStack(coremodel.StackID{Namespace: "namespace", Name: "name"})
+			builder := newSecurityGroupBuilder(mockTagger, clusterName, tc.enableBackendSg, mockSgResolver, mockSgProvider, logr.Discard())
+
+			out, err := builder.buildSecurityGroups(context.Background(), stack, tc.lbConf, gw, make(map[int][]routeutils.RouteDescriptor), tc.ipAddressType)
+
+			if tc.expectErr {
+				assert.Error(t, err)
+				return
+			}
+			assert.NoError(t, err)
+			assert.Equal(t, tc.backendSgAllocated, out.backendSecurityGroupAllocated)
+			var resSGs []*ec2model.SecurityGroup
+			listErr := stack.ListResources(&resSGs)
+			assert.NoError(t, listErr)
+			assert.Equal(t, tc.expectedStackResources, len(resSGs))
+			if tc.hasBackendSg {
+				assert.NotNil(t, out.backendSecurityGroupToken)
+			}
+		})
+	}
+}
+
+func Test_BuildSecurityGroups_BuildManagedSecurityGroupIngressPermissions(t *testing.T) {
+	testCases := []struct {
+		name          string
+		lbConf        *elbv2gw.LoadBalancerConfiguration
+		ipAddressType elbv2model.IPAddressType
+		routes        map[int][]routeutils.RouteDescriptor
+		expected      []ec2model.IPPermission
+	}{
+		{
+			name:     "no routes",
+			lbConf:   &elbv2gw.LoadBalancerConfiguration{},
+			expected: make([]ec2model.IPPermission, 0),
+		},
+		{
+			name: "ipv4 - tcp - with default source ranges",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "0.0.0.0/0",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "ipv4 - tcp - with source range",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+						"127.100.0.1/24",
+						"127.200.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "ipv4 - udp - with source range",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+						"127.100.0.1/24",
+						"127.200.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.UDPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "udp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "udp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "udp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "ipv4 - udp - with source range - icmp enabled",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+					},
+					EnableICMP: true,
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.UDPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "udp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "icmp",
+					FromPort:   awssdk.Int32(2),
+					ToPort:     awssdk.Int32(3),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "ipv4 - with duplicated route type - with source range",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+						"127.100.0.1/24",
+						"127.200.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "ipv4 - with duplicated route type - with source range - multiple ports",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+						"127.100.0.1/24",
+						"127.200.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+				85: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+				90: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(85),
+					ToPort:     awssdk.Int32(85),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(85),
+					ToPort:     awssdk.Int32(85),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(85),
+					ToPort:     awssdk.Int32(85),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(90),
+					ToPort:     awssdk.Int32(90),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(90),
+					ToPort:     awssdk.Int32(90),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.100.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(90),
+					ToPort:     awssdk.Int32(90),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.200.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name:          "ipv6 - with default source ranges",
+			ipAddressType: elbv2model.IPAddressTypeDualStack,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "0.0.0.0/0",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPv6Range: []ec2model.IPv6Range{
+						{
+							CIDRIPv6: "::/0",
+						},
+					},
+				},
+			},
+		},
+		{
+			name:          "ipv6 - with source range",
+			ipAddressType: elbv2model.IPAddressTypeDualStack,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"2001:db8::/32",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+				85: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+				90: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+					&routeutils.MockRoute{
+						Kind: routeutils.HTTPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPv6Range: []ec2model.IPv6Range{
+						{
+							CIDRIPv6: "2001:db8::/32",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(85),
+					ToPort:     awssdk.Int32(85),
+					IPv6Range: []ec2model.IPv6Range{
+						{
+							CIDRIPv6: "2001:db8::/32",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(90),
+					ToPort:     awssdk.Int32(90),
+					IPv6Range: []ec2model.IPv6Range{
+						{
+							CIDRIPv6: "2001:db8::/32",
+						},
+					},
+				},
+			},
+		},
+		{
+			name:          "ipv6 + ipv4 - with source range",
+			ipAddressType: elbv2model.IPAddressTypeDualStack,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"2001:db8::/32",
+						"127.0.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPv6Range: []ec2model.IPv6Range{
+						{
+							CIDRIPv6: "2001:db8::/32",
+						},
+					},
+				},
+			},
+		},
+		{
+			name:          "ipv6 + ipv4 - with source range - but lb type doesnt support ipv6",
+			ipAddressType: elbv2model.IPAddressTypeIPV4,
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"2001:db8::/32",
+						"127.0.0.1/24",
+					},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+			},
+		},
+		{
+			name: "prefix list",
+			lbConf: &elbv2gw.LoadBalancerConfiguration{
+				Spec: elbv2gw.LoadBalancerConfigurationSpec{
+					SourceRanges: &[]string{
+						"127.0.0.1/24",
+					},
+					SecurityGroupPrefixes: &[]string{"pl1", "pl2"},
+				},
+			},
+			routes: map[int][]routeutils.RouteDescriptor{
+				80: {
+					&routeutils.MockRoute{
+						Kind: routeutils.TCPRouteKind,
+					},
+				},
+			},
+			expected: []ec2model.IPPermission{
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					IPRanges: []ec2model.IPRange{
+						{
+							CIDRIP: "127.0.0.1/24",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					PrefixLists: []ec2model.PrefixList{
+						{
+							ListID: "pl1",
+						},
+					},
+				},
+				{
+					IPProtocol: "tcp",
+					FromPort:   awssdk.Int32(80),
+					ToPort:     awssdk.Int32(80),
+					PrefixLists: []ec2model.PrefixList{
+						{
+							ListID: "pl2",
+						},
+					},
+				},
+			},
+		},
+	}
+
+	for _, tc := range testCases {
+		t.Run(tc.name, func(t *testing.T) {
+			builder := &securityGroupBuilderImpl{}
+			permissions := builder.buildManagedSecurityGroupIngressPermissions(tc.lbConf, tc.routes, tc.ipAddressType)
+			assert.ElementsMatch(t, tc.expected, permissions, fmt.Sprintf("%+v", permissions))
+		})
+	}
+}
diff --git a/pkg/gateway/model/model_build_subnet.go b/pkg/gateway/model/model_build_subnet.go
index 9b2c13301d..adfce1aa93 100644
--- a/pkg/gateway/model/model_build_subnet.go
+++ b/pkg/gateway/model/model_build_subnet.go
@@ -15,8 +15,13 @@ import (
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/networking"
 )
 
+type buildLoadBalancerSubnetsOutput struct {
+	subnets              []elbv2model.SubnetMapping
+	sourceIPv6NatEnabled bool
+}
+
 type subnetModelBuilder interface {
-	buildLoadBalancerSubnets(ctx context.Context, gwSubnetConfig *[]elbv2gw.SubnetConfiguration, gwSubnetTagSelectors *map[string][]string, scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, stack core.Stack) ([]elbv2model.SubnetMapping, bool, error)
+	buildLoadBalancerSubnets(ctx context.Context, gwSubnetConfig *[]elbv2gw.SubnetConfiguration, gwSubnetTagSelectors *map[string][]string, scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, stack core.Stack) (buildLoadBalancerSubnetsOutput, error)
 }
 
 type subnetModelBuilderImpl struct {
@@ -50,17 +55,17 @@ func newSubnetModelBuilder(loadBalancerType elbv2model.LoadBalancerType, trackin
 	}
 }
 
-func (subnetBuilder *subnetModelBuilderImpl) buildLoadBalancerSubnets(ctx context.Context, gwSubnetConfig *[]elbv2gw.SubnetConfiguration, gwSubnetTagSelectors *map[string][]string, scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, stack core.Stack) ([]elbv2model.SubnetMapping, bool, error) {
+func (subnetBuilder *subnetModelBuilderImpl) buildLoadBalancerSubnets(ctx context.Context, gwSubnetConfig *[]elbv2gw.SubnetConfiguration, gwSubnetTagSelectors *map[string][]string, scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType, stack core.Stack) (buildLoadBalancerSubnetsOutput, error) {
 	sourceNATEnabled, err := subnetBuilder.validateSubnetsInput(gwSubnetConfig, scheme, ipAddressType)
 
 	if err != nil {
-		return nil, false, err
+		return buildLoadBalancerSubnetsOutput{}, err
 	}
 
 	resolvedEC2Subnets, err := subnetBuilder.resolveEC2Subnets(ctx, stack, gwSubnetConfig, gwSubnetTagSelectors, scheme)
 
 	if err != nil {
-		return nil, false, err
+		return buildLoadBalancerSubnetsOutput{}, err
 	}
 
 	resultPtrs := make([]*elbv2model.SubnetMapping, 0)
@@ -80,7 +85,7 @@ func (subnetBuilder *subnetModelBuilderImpl) buildLoadBalancerSubnets(ctx contex
 	for _, mutator := range subnetBuilder.subnetMutatorChain {
 		err := mutator.Mutate(resultPtrs, resolvedEC2Subnets, subnetConfig)
 		if err != nil {
-			return nil, false, err
+			return buildLoadBalancerSubnetsOutput{}, err
 		}
 	}
 
@@ -90,7 +95,10 @@ func (subnetBuilder *subnetModelBuilderImpl) buildLoadBalancerSubnets(ctx contex
 		result = append(result, *v)
 	}
 
-	return result, sourceNATEnabled, nil
+	return buildLoadBalancerSubnetsOutput{
+		subnets:              result,
+		sourceIPv6NatEnabled: sourceNATEnabled,
+	}, nil
 }
 
 func (subnetBuilder *subnetModelBuilderImpl) validateSubnetsInput(subnetConfigsPtr *[]elbv2gw.SubnetConfiguration, scheme elbv2model.LoadBalancerScheme, ipAddressType elbv2model.IPAddressType) (bool, error) {
diff --git a/pkg/gateway/model/model_build_subnet_test.go b/pkg/gateway/model/model_build_subnet_test.go
index d59fce9513..b7fdeba931 100644
--- a/pkg/gateway/model/model_build_subnet_test.go
+++ b/pkg/gateway/model/model_build_subnet_test.go
@@ -97,11 +97,11 @@ func Test_BuildLoadBalancerSubnets(t *testing.T) {
 		},
 	}
 
-	subnetMappings, ipv6SourceNatEnabled, err := builder.buildLoadBalancerSubnets(context.Background(), &gwSubnetConfig, nil, elbv2model.LoadBalancerSchemeInternal, elbv2model.IPAddressTypeIPV4, nil)
+	output, err := builder.buildLoadBalancerSubnets(context.Background(), &gwSubnetConfig, nil, elbv2model.LoadBalancerSchemeInternal, elbv2model.IPAddressTypeIPV4, nil)
 
 	assert.NoError(t, err)
-	assert.Equal(t, expectedMappings, subnetMappings)
-	assert.False(t, ipv6SourceNatEnabled)
+	assert.Equal(t, expectedMappings, output.subnets)
+	assert.False(t, output.sourceIPv6NatEnabled)
 	assert.Equal(t, 1, mm.called)
 }
 
diff --git a/pkg/gateway/routeutils/mock_route.go b/pkg/gateway/routeutils/mock_route.go
new file mode 100644
index 0000000000..13b438c58e
--- /dev/null
+++ b/pkg/gateway/routeutils/mock_route.go
@@ -0,0 +1,46 @@
+package routeutils
+
+import (
+	"k8s.io/apimachinery/pkg/types"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
+)
+
+type MockRoute struct {
+	Kind string
+}
+
+func (m *MockRoute) GetBackendRefs() []gwv1.BackendRef {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockRoute) GetRouteNamespacedName() types.NamespacedName {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockRoute) GetRouteKind() string {
+	return m.Kind
+}
+
+func (m *MockRoute) GetHostnames() []gwv1.Hostname {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockRoute) GetParentRefs() []gwv1.ParentReference {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockRoute) GetRawRoute() interface{} {
+	//TODO implement me
+	panic("implement me")
+}
+
+func (m *MockRoute) GetAttachedRules() []RouteRule {
+	//TODO implement me
+	panic("implement me")
+}
+
+var _ RouteDescriptor = &MockRoute{}
diff --git a/pkg/ingress/finalizer.go b/pkg/ingress/finalizer.go
index c1c0cac67c..4b4d73e06b 100644
--- a/pkg/ingress/finalizer.go
+++ b/pkg/ingress/finalizer.go
@@ -5,11 +5,7 @@ import (
 	"fmt"
 	networking "k8s.io/api/networking/v1"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
-)
-
-const (
-	explicitGroupFinalizerPrefix = "group.ingress.k8s.aws/"
-	implicitGroupFinalizer       = "ingress.k8s.aws/resources"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 )
 
 // FinalizerManager manages finalizer for ingresses.
@@ -62,7 +58,7 @@ func (m *defaultFinalizerManager) RemoveGroupFinalizer(ctx context.Context, grou
 // for implicit group, the format is "ingress.k8s.aws/resources"
 func buildGroupFinalizer(groupID GroupID) string {
 	if groupID.IsExplicit() {
-		return fmt.Sprintf("%s%s", explicitGroupFinalizerPrefix, groupID.Name)
+		return fmt.Sprintf("%s%s", shared_constants.ExplicitGroupFinalizerPrefix, groupID.Name)
 	}
-	return implicitGroupFinalizer
+	return shared_constants.ImplicitGroupFinalizer
 }
diff --git a/pkg/ingress/group_loader.go b/pkg/ingress/group_loader.go
index 2bd98ab61a..0aad20eeea 100644
--- a/pkg/ingress/group_loader.go
+++ b/pkg/ingress/group_loader.go
@@ -4,6 +4,7 @@ import (
 	"context"
 	"fmt"
 	"regexp"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"sort"
 	"strings"
 
@@ -117,10 +118,10 @@ func (m *defaultGroupLoader) LoadGroupIDIfAny(ctx context.Context, ing *networki
 func (m *defaultGroupLoader) LoadGroupIDsPendingFinalization(_ context.Context, ing *networking.Ingress) []GroupID {
 	var groupIDs []GroupID
 	for _, finalizer := range ing.GetFinalizers() {
-		if finalizer == implicitGroupFinalizer {
+		if finalizer == shared_constants.ImplicitGroupFinalizer {
 			groupIDs = append(groupIDs, NewGroupIDForImplicitGroup(k8s.NamespacedName(ing)))
-		} else if strings.HasPrefix(finalizer, explicitGroupFinalizerPrefix) {
-			groupName := finalizer[len(explicitGroupFinalizerPrefix):]
+		} else if strings.HasPrefix(finalizer, shared_constants.ExplicitGroupFinalizerPrefix) {
+			groupName := finalizer[len(shared_constants.ExplicitGroupFinalizerPrefix):]
 			groupIDs = append(groupIDs, NewGroupIDForExplicitGroup(groupName))
 		}
 	}
diff --git a/pkg/ingress/model_builder.go b/pkg/ingress/model_builder.go
index 1e341f24c1..049c10b3f9 100644
--- a/pkg/ingress/model_builder.go
+++ b/pkg/ingress/model_builder.go
@@ -3,6 +3,7 @@ package ingress
 import (
 	"context"
 	"reflect"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"strconv"
 
 	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
@@ -30,8 +31,7 @@ import (
 )
 
 const (
-	lbAttrsDeletionProtectionEnabled = "deletion_protection.enabled"
-	controllerName                   = "ingress"
+	controllerName = "ingress"
 )
 
 // ModelBuilder is responsible for build mode stack for a IngressGroup.
@@ -443,8 +443,8 @@ func (t *defaultModelBuildTask) getDeletionProtectionViaAnnotation(ing *networki
 	if err != nil {
 		return false, err
 	}
-	if _, deletionProtectionSpecified := lbAttributes[lbAttrsDeletionProtectionEnabled]; deletionProtectionSpecified {
-		deletionProtectionEnabled, err := strconv.ParseBool(lbAttributes[lbAttrsDeletionProtectionEnabled])
+	if _, deletionProtectionSpecified := lbAttributes[shared_constants.LBAttributeDeletionProtection]; deletionProtectionSpecified {
+		deletionProtectionEnabled, err := strconv.ParseBool(lbAttributes[shared_constants.LBAttributeDeletionProtection])
 		if err != nil {
 			return false, err
 		}
diff --git a/pkg/ingress/model_builder_test.go b/pkg/ingress/model_builder_test.go
index 0c27e4743c..95a24c5b8d 100644
--- a/pkg/ingress/model_builder_test.go
+++ b/pkg/ingress/model_builder_test.go
@@ -3,6 +3,7 @@ package ingress
 import (
 	"context"
 	"encoding/json"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"testing"
 	"time"
 
@@ -2169,8 +2170,8 @@ func Test_defaultModelBuilder_Build(t *testing.T) {
 									Scheme: elbv2types.LoadBalancerSchemeEnumInternal,
 								},
 								Tags: map[string]string{
-									"elbv2.k8s.aws/cluster": "cluster-name",
-									"ingress.k8s.aws/stack": "ns-1/ing-1",
+									shared_constants.TagKeyK8sCluster: "cluster-name",
+									"ingress.k8s.aws/stack":           "ns-1/ing-1",
 								},
 							},
 							{
diff --git a/pkg/metrics/util/reconcile_counter.go b/pkg/metrics/util/reconcile_counter.go
index 25910aa654..9b6c62c6d1 100644
--- a/pkg/metrics/util/reconcile_counter.go
+++ b/pkg/metrics/util/reconcile_counter.go
@@ -26,8 +26,8 @@ func NewReconcileCounters() *ReconcileCounters {
 		serviceReconciles:    make(map[types.NamespacedName]int),
 		ingressReconciles:    make(map[types.NamespacedName]int),
 		tgbReconciles:        make(map[types.NamespacedName]int),
-		nlbGatewayReconciles: make(map[types.NamespacedName]int),
 		albGatewayReconciles: make(map[types.NamespacedName]int),
+		nlbGatewayReconciles: make(map[types.NamespacedName]int),
 		mutex:                sync.Mutex{},
 	}
 }
diff --git a/pkg/networking/backend_sg_provider.go b/pkg/networking/backend_sg_provider.go
index 8b3900e523..d48332c321 100644
--- a/pkg/networking/backend_sg_provider.go
+++ b/pkg/networking/backend_sg_provider.go
@@ -8,6 +8,7 @@ import (
 	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
 	"github.com/aws/smithy-go"
 	"regexp"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"sort"
 	"strings"
 	"sync"
@@ -24,6 +25,7 @@ import (
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/runtime"
 	"sigs.k8s.io/controller-runtime/pkg/client"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 )
 
 const (
@@ -31,14 +33,8 @@ const (
 	defaultSGDeletionTimeout      = 2 * time.Minute
 
 	resourceTypeSecurityGroup = "security-group"
-	tagKeyK8sCluster          = "elbv2.k8s.aws/cluster"
-	tagKeyResource            = "elbv2.k8s.aws/resource"
 	tagValueBackend           = "backend-sg"
 
-	explicitGroupFinalizerPrefix = "group.ingress.k8s.aws/"
-	implicitGroupFinalizer       = "ingress.k8s.aws/resources"
-	serviceFinalizer             = "service.k8s.aws/resources"
-
 	sgDescription = "[k8s] Shared Backend SecurityGroup for LoadBalancer"
 )
 
@@ -47,6 +43,7 @@ type ResourceType string
 const (
 	ResourceTypeIngress = "ingress"
 	ResourceTypeService = "service"
+	ResourceTypeGateway = "gateway"
 )
 
 // BackendSGProvider is responsible for providing backend security groups
@@ -59,7 +56,7 @@ type BackendSGProvider interface {
 
 // NewBackendSGProvider constructs a new  defaultBackendSGProvider
 func NewBackendSGProvider(clusterName string, backendSG string, vpcID string,
-	ec2Client services.EC2, k8sClient client.Client, defaultTags map[string]string, logger logr.Logger) *defaultBackendSGProvider {
+	ec2Client services.EC2, k8sClient client.Client, defaultTags map[string]string, enableGatewayCheck bool, logger logr.Logger) *defaultBackendSGProvider {
 	return &defaultBackendSGProvider{
 		vpcID:       vpcID,
 		clusterName: clusterName,
@@ -70,9 +67,11 @@ func NewBackendSGProvider(clusterName string, backendSG string, vpcID string,
 		logger:      logger,
 		mutex:       sync.Mutex{},
 
+		enableGatewayCheck: enableGatewayCheck,
+
 		checkIngressFinalizersFunc: func(finalizers []string) bool {
 			for _, fin := range finalizers {
-				if fin == implicitGroupFinalizer || strings.HasPrefix(fin, explicitGroupFinalizerPrefix) {
+				if fin == shared_constants.ImplicitGroupFinalizer || strings.HasPrefix(fin, shared_constants.ExplicitGroupFinalizerPrefix) {
 					return true
 				}
 			}
@@ -81,7 +80,16 @@ func NewBackendSGProvider(clusterName string, backendSG string, vpcID string,
 
 		checkServiceFinalizersFunc: func(finalizers []string) bool {
 			for _, fin := range finalizers {
-				if fin == serviceFinalizer {
+				if fin == shared_constants.ServiceFinalizer {
+					return true
+				}
+			}
+			return false
+		},
+
+		checkGatewayFinalizersFunc: func(finalizers []string) bool {
+			for _, fin := range finalizers {
+				if fin == shared_constants.ALBGatewayFinalizer || fin == shared_constants.NLBGatewayFinalizer {
 					return true
 				}
 			}
@@ -113,8 +121,11 @@ type defaultBackendSGProvider struct {
 	// controller deletes the backend SG.
 	objectsMap sync.Map
 
+	enableGatewayCheck bool
+
 	checkServiceFinalizersFunc func([]string) bool
 	checkIngressFinalizersFunc func([]string) bool
+	checkGatewayFinalizersFunc func([]string) bool
 
 	defaultDeletionPollInterval time.Duration
 	defaultDeletionTimeout      time.Duration
@@ -175,6 +186,9 @@ func (p *defaultBackendSGProvider) isBackendSGRequired(ctx context.Context) (boo
 	if required, err := p.checkServiceListForUnmapped(ctx); required || err != nil {
 		return required, err
 	}
+	if required, err := p.checkGatewayListForUnmapped(ctx); required || err != nil {
+		return required, err
+	}
 	return false, nil
 }
 
@@ -210,6 +224,26 @@ func (p *defaultBackendSGProvider) checkServiceListForUnmapped(ctx context.Conte
 	return false, nil
 }
 
+func (p *defaultBackendSGProvider) checkGatewayListForUnmapped(ctx context.Context) (bool, error) {
+	if !p.enableGatewayCheck {
+		return false, nil
+	}
+
+	gwList := &gwv1.GatewayList{}
+	if err := p.k8sClient.List(ctx, gwList); err != nil {
+		return true, errors.Wrapf(err, "unable to list gateways")
+	}
+	for _, gw := range gwList.Items {
+		if !p.checkGatewayFinalizersFunc(gw.GetFinalizers()) {
+			continue
+		}
+		if !p.existsInObjectMap(ResourceTypeGateway, k8s.NamespacedName(&gw)) {
+			return true, nil
+		}
+	}
+	return false, nil
+}
+
 func (p *defaultBackendSGProvider) existsInObjectMap(resourceType ResourceType, resource types.NamespacedName) bool {
 	if _, exists := p.objectsMap.Load(getObjectKey(resourceType, resource)); exists {
 		return true
@@ -269,11 +303,11 @@ func (p *defaultBackendSGProvider) buildBackendSGTags(_ context.Context) []ec2ty
 			ResourceType: resourceTypeSecurityGroup,
 			Tags: append(defaultTags, []ec2types.Tag{
 				{
-					Key:   awssdk.String(tagKeyK8sCluster),
+					Key:   awssdk.String(shared_constants.TagKeyK8sCluster),
 					Value: awssdk.String(p.clusterName),
 				},
 				{
-					Key:   awssdk.String(tagKeyResource),
+					Key:   awssdk.String(shared_constants.TagKeyResource),
 					Value: awssdk.String(tagValueBackend),
 				},
 			}...),
@@ -289,16 +323,16 @@ func (p *defaultBackendSGProvider) getBackendSGFromEC2(ctx context.Context, sgNa
 				Values: []string{vpcID},
 			},
 			{
-				Name:   awssdk.String(fmt.Sprintf("tag:%v", tagKeyK8sCluster)),
+				Name:   awssdk.String(fmt.Sprintf("tag:%v", shared_constants.TagKeyK8sCluster)),
 				Values: []string{p.clusterName},
 			},
 			{
-				Name:   awssdk.String(fmt.Sprintf("tag:%v", tagKeyResource)),
+				Name:   awssdk.String(fmt.Sprintf("tag:%v", shared_constants.TagKeyResource)),
 				Values: []string{tagValueBackend},
 			},
 		},
 	}
-	p.logger.V(1).Info("Queriying existing SG", "vpc-id", vpcID, "name", sgName)
+	p.logger.V(1).Info("Querying existing SG", "vpc-id", vpcID, "name", sgName)
 	sgs, err := p.ec2Client.DescribeSecurityGroupsAsList(ctx, req)
 	if err != nil && !isEC2SecurityGroupNotFoundError(err) {
 		return "", err
diff --git a/pkg/networking/backend_sg_provider_test.go b/pkg/networking/backend_sg_provider_test.go
index 4850d7d30d..839b0d2ee7 100644
--- a/pkg/networking/backend_sg_provider_test.go
+++ b/pkg/networking/backend_sg_provider_test.go
@@ -7,6 +7,7 @@ import (
 	"k8s.io/apimachinery/pkg/types"
 	"reflect"
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/k8s"
+	gwv1 "sigs.k8s.io/gateway-api/apis/v1"
 	"testing"
 
 	"github.com/go-logr/logr"
@@ -42,12 +43,13 @@ func Test_defaultBackendSGProvider_Get(t *testing.T) {
 		err  error
 	}
 	type fields struct {
-		backendSG       string
-		ingResources    []*networking.Ingress
-		svcResource     *corev1.Service
-		defaultTags     map[string]string
-		describeSGCalls []describeSecurityGroupsAsListCall
-		createSGCalls   []createSecurityGroupWithContexCall
+		backendSG          string
+		ingResources       []*networking.Ingress
+		svcResource        *corev1.Service
+		enableGatewayCheck bool
+		defaultTags        map[string]string
+		describeSGCalls    []describeSecurityGroupsAsListCall
+		createSGCalls      []createSecurityGroupWithContexCall
 	}
 	defaultEC2Filters := []ec2types.Filter{
 		{
@@ -285,7 +287,7 @@ func Test_defaultBackendSGProvider_Get(t *testing.T) {
 			}
 			k8sClient := mock_client.NewMockClient(ctrl)
 			sgProvider := NewBackendSGProvider(defaultClusterName, tt.fields.backendSG,
-				defaultVPCID, ec2Client, k8sClient, tt.fields.defaultTags, logr.New(&log.NullLogSink{}))
+				defaultVPCID, ec2Client, k8sClient, tt.fields.defaultTags, tt.fields.enableGatewayCheck, logr.New(&log.NullLogSink{}))
 
 			resourceType := ResourceTypeIngress
 			var activeResources []types.NamespacedName
@@ -317,6 +319,11 @@ func Test_defaultBackendSGProvider_Release(t *testing.T) {
 		services []*corev1.Service
 		err      error
 	}
+	type listGatewaysCall struct {
+		gateways []*gwv1.Gateway
+		err      error
+	}
+
 	type deleteSecurityGroupWithContextCall struct {
 		req  *ec2sdk.DeleteSecurityGroupInput
 		resp *ec2sdk.DeleteSecurityGroupOutput
@@ -333,11 +340,13 @@ func Test_defaultBackendSGProvider_Release(t *testing.T) {
 		listIngressCalls           []listIngressCall
 		deleteSGCalls              []deleteSecurityGroupWithContextCall
 		listServicesCalls          []listServicesCall
+		listGatewaysCall           []listGatewaysCall
 		activeIngresses            []*networking.Ingress
 		inactiveIngresses          []*networking.Ingress
 		svcResource                *corev1.Service
 		resourceMapItems           []mapItem
 		backendSGRequiredForActive bool
+		enableGatewayCheck         bool
 	}
 	ing := &networking.Ingress{
 		ObjectMeta: metav1.ObjectMeta{
@@ -545,6 +554,94 @@ func Test_defaultBackendSGProvider_Release(t *testing.T) {
 				inactiveIngresses: []*networking.Ingress{ing},
 			},
 		},
+		{
+			name: "backend sg required for gw - nlb",
+			fields: fields{
+				autogenSG: "sg-autogen",
+				listIngressCalls: []listIngressCall{
+					{},
+				},
+				listServicesCalls: []listServicesCall{
+					{},
+				},
+				listGatewaysCall: []listGatewaysCall{
+					{
+						gateways: []*gwv1.Gateway{
+							{
+								ObjectMeta: metav1.ObjectMeta{
+									Namespace:  "awesome-ns",
+									Name:       "gw-1",
+									Finalizers: []string{"gateway.k8s.aws/nlb"},
+								},
+							},
+						},
+					},
+				},
+				enableGatewayCheck: true,
+				inactiveIngresses:  []*networking.Ingress{ing},
+			},
+		},
+		{
+			name: "backend sg required for gw - alb",
+			fields: fields{
+				autogenSG: "sg-autogen",
+				listIngressCalls: []listIngressCall{
+					{},
+				},
+				listServicesCalls: []listServicesCall{
+					{},
+				},
+				listGatewaysCall: []listGatewaysCall{
+					{
+						gateways: []*gwv1.Gateway{
+							{
+								ObjectMeta: metav1.ObjectMeta{
+									Namespace:  "awesome-ns",
+									Name:       "gw-1",
+									Finalizers: []string{"gateway.k8s.aws/alb"},
+								},
+							},
+						},
+					},
+				},
+				enableGatewayCheck: true,
+				inactiveIngresses:  []*networking.Ingress{ing},
+			},
+		},
+		{
+			name: "backend sg required for gw - alb but gw not enabled.",
+			fields: fields{
+				autogenSG: "sg-autogen",
+				listIngressCalls: []listIngressCall{
+					{},
+				},
+				listServicesCalls: []listServicesCall{
+					{},
+				},
+				listGatewaysCall: []listGatewaysCall{
+					{
+						gateways: []*gwv1.Gateway{
+							{
+								ObjectMeta: metav1.ObjectMeta{
+									Namespace:  "awesome-ns",
+									Name:       "gw-1",
+									Finalizers: []string{"gateway.k8s.aws/alb"},
+								},
+							},
+						},
+					},
+				},
+				inactiveIngresses: []*networking.Ingress{ing},
+				deleteSGCalls: []deleteSecurityGroupWithContextCall{
+					{
+						req: &ec2sdk.DeleteSecurityGroupInput{
+							GroupId: awssdk.String("sg-autogen"),
+						},
+						resp: &ec2sdk.DeleteSecurityGroupOutput{},
+					},
+				},
+			},
+		},
 		{
 			name: "backend sg requirement for service already known",
 			fields: fields{
@@ -732,7 +829,7 @@ func Test_defaultBackendSGProvider_Release(t *testing.T) {
 			ec2Client := services.NewMockEC2(ctrl)
 			k8sClient := mock_client.NewMockClient(ctrl)
 			sgProvider := NewBackendSGProvider(defaultClusterName, tt.fields.backendSG,
-				defaultVPCID, ec2Client, k8sClient, tt.fields.defaultTags, logr.New(&log.NullLogSink{}))
+				defaultVPCID, ec2Client, k8sClient, tt.fields.defaultTags, tt.fields.enableGatewayCheck, logr.New(&log.NullLogSink{}))
 			if len(tt.fields.autogenSG) > 0 {
 				sgProvider.backendSG = ""
 				sgProvider.autoGeneratedSG = tt.fields.autogenSG
@@ -771,6 +868,21 @@ func Test_defaultBackendSGProvider_Release(t *testing.T) {
 					},
 				).AnyTimes()
 			}
+
+			for _, call := range tt.fields.listGatewaysCall {
+				if !tt.fields.enableGatewayCheck {
+					break
+				}
+				k8sClient.EXPECT().List(gomock.Any(), &gwv1.GatewayList{}, gomock.Any()).DoAndReturn(
+					func(ctx context.Context, gatewayList *gwv1.GatewayList, opts ...client.ListOption) error {
+						for _, gw := range call.gateways {
+							gatewayList.Items = append(gatewayList.Items, *(gw.DeepCopy()))
+						}
+						return call.err
+					},
+				).AnyTimes()
+			}
+
 			for _, ing := range tt.env.ingresses {
 				assert.NoError(t, k8sClient.Create(context.Background(), ing.DeepCopy()))
 			}
diff --git a/pkg/service/model_build_load_balancer_test.go b/pkg/service/model_build_load_balancer_test.go
index 02a6cdfbb0..edc838f6c3 100644
--- a/pkg/service/model_build_load_balancer_test.go
+++ b/pkg/service/model_build_load_balancer_test.go
@@ -6,6 +6,7 @@ import (
 	ec2types "github.com/aws/aws-sdk-go-v2/service/ec2/types"
 	elbv2types "github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2/types"
 	"github.com/aws/aws-sdk-go/service/ec2"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"testing"
 
 	"k8s.io/apimachinery/pkg/util/sets"
@@ -24,8 +25,6 @@ import (
 	"sigs.k8s.io/aws-load-balancer-controller/pkg/model/elbv2"
 )
 
-const lbAttrsDeletionProtectionEnabled = "deletion_protection.enabled"
-
 func Test_defaultModelBuilderTask_buildLBAttributes(t *testing.T) {
 	tests := []struct {
 		testName  string
@@ -78,7 +77,7 @@ func Test_defaultModelBuilderTask_buildLBAttributes(t *testing.T) {
 					Value: "true",
 				},
 				{
-					Key:   lbAttrsDeletionProtectionEnabled,
+					Key:   shared_constants.LBAttributeDeletionProtection,
 					Value: "true",
 				},
 			},
@@ -112,7 +111,7 @@ func Test_defaultModelBuilderTask_buildLBAttributes(t *testing.T) {
 					Value: "true",
 				},
 				{
-					Key:   lbAttrsDeletionProtectionEnabled,
+					Key:   shared_constants.LBAttributeDeletionProtection,
 					Value: "true",
 				},
 				{
@@ -1265,8 +1264,8 @@ func Test_defaultModelBuilderTask_buildLoadBalancerSubnets(t *testing.T) {
 								Scheme: elbv2types.LoadBalancerSchemeEnumInternal,
 							},
 							Tags: map[string]string{
-								"elbv2.k8s.aws/cluster": "cluster-name",
-								"service.k8s.aws/stack": "namespace/serviceName",
+								shared_constants.TagKeyK8sCluster: "cluster-name",
+								"service.k8s.aws/stack":           "namespace/serviceName",
 							},
 						},
 					},
diff --git a/pkg/service/model_build_managed_sg.go b/pkg/service/model_build_managed_sg.go
index fd66a21304..0416468cfe 100644
--- a/pkg/service/model_build_managed_sg.go
+++ b/pkg/service/model_build_managed_sg.go
@@ -6,6 +6,7 @@ import (
 	"encoding/hex"
 	"fmt"
 	"regexp"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"strings"
 
 	awssdk "github.com/aws/aws-sdk-go-v2/aws"
@@ -17,15 +18,6 @@ import (
 )
 
 const (
-	icmpv4Protocol = "icmp"
-	icmpv6Protocol = "icmpv6"
-
-	icmpv4TypeForPathMtu = 3 // https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml#icmp-parameters-codes-3
-	icmpv4CodeForPathMtu = 4
-
-	icmpv6TypeForPathMtu = 2 // https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-codes-2
-	icmpv6CodeForPathMtu = 0
-
 	resourceIDManagedSecurityGroup = "ManagedLBSecurityGroup"
 )
 
@@ -99,9 +91,9 @@ func (t *defaultModelBuildTask) buildManagedSecurityGroupIngressPermissions(ctx
 				})
 				if icmpForPathMtuConfigured && icmpForPathMtuConfiguredFlag == "on" {
 					permissions = append(permissions, ec2model.IPPermission{
-						IPProtocol: string(icmpv4Protocol),
-						FromPort:   awssdk.Int32(icmpv4TypeForPathMtu),
-						ToPort:     awssdk.Int32(icmpv4CodeForPathMtu),
+						IPProtocol: shared_constants.ICMPV4Protocol,
+						FromPort:   awssdk.Int32(shared_constants.ICMPV4TypeForPathMtu),
+						ToPort:     awssdk.Int32(shared_constants.ICMPV4CodeForPathMtu),
 						IPRanges: []ec2model.IPRange{
 							{
 								CIDRIP: cidr,
@@ -122,9 +114,9 @@ func (t *defaultModelBuildTask) buildManagedSecurityGroupIngressPermissions(ctx
 				})
 				if icmpForPathMtuConfigured && icmpForPathMtuConfiguredFlag == "on" {
 					permissions = append(permissions, ec2model.IPPermission{
-						IPProtocol: string(icmpv6Protocol),
-						FromPort:   awssdk.Int32(icmpv6TypeForPathMtu),
-						ToPort:     awssdk.Int32(icmpv6CodeForPathMtu),
+						IPProtocol: shared_constants.ICMPV6Protocol,
+						FromPort:   awssdk.Int32(shared_constants.ICMPV6TypeForPathMtu),
+						ToPort:     awssdk.Int32(shared_constants.ICMPV6CodeForPathMtu),
 						IPv6Range: []ec2model.IPv6Range{
 							{
 								CIDRIPv6: cidr,
diff --git a/pkg/service/model_builder.go b/pkg/service/model_builder.go
index 759a957554..4b12004aeb 100644
--- a/pkg/service/model_builder.go
+++ b/pkg/service/model_builder.go
@@ -2,6 +2,7 @@ package service
 
 import (
 	"context"
+	"sigs.k8s.io/aws-load-balancer-controller/pkg/shared_constants"
 	"strconv"
 	"sync"
 
@@ -29,7 +30,6 @@ const (
 	LoadBalancerTypeExternal       = "external"
 	LoadBalancerTargetTypeIP       = "ip"
 	LoadBalancerTargetTypeInstance = "instance"
-	lbAttrsDeletionProtection      = "deletion_protection.enabled"
 	controllerName                 = "service"
 )
 
@@ -274,8 +274,8 @@ func (t *defaultModelBuildTask) getDeletionProtectionViaAnnotation(svc corev1.Se
 	if err != nil {
 		return false, err
 	}
-	if _, deletionProtectionSpecified := lbAttributes[lbAttrsDeletionProtection]; deletionProtectionSpecified {
-		deletionProtectionEnabled, err := strconv.ParseBool(lbAttributes[lbAttrsDeletionProtection])
+	if _, deletionProtectionSpecified := lbAttributes[shared_constants.LBAttributeDeletionProtection]; deletionProtectionSpecified {
+		deletionProtectionEnabled, err := strconv.ParseBool(lbAttributes[shared_constants.LBAttributeDeletionProtection])
 		if err != nil {
 			return false, err
 		}
diff --git a/pkg/shared_constants/attributes.go b/pkg/shared_constants/attributes.go
new file mode 100644
index 0000000000..73092d7746
--- /dev/null
+++ b/pkg/shared_constants/attributes.go
@@ -0,0 +1,6 @@
+package shared_constants
+
+const (
+	// LBAttributeDeletionProtection deletion protection attribute name
+	LBAttributeDeletionProtection = "deletion_protection.enabled"
+)
diff --git a/pkg/shared_constants/finalizers.go b/pkg/shared_constants/finalizers.go
new file mode 100644
index 0000000000..7f90abf231
--- /dev/null
+++ b/pkg/shared_constants/finalizers.go
@@ -0,0 +1,18 @@
+package shared_constants
+
+const (
+	// ExplicitGroupFinalizerPrefix the prefix for finalizers applied to an ingress group
+	ExplicitGroupFinalizerPrefix = "group.ingress.k8s.aws/"
+
+	// ImplicitGroupFinalizer the finalizer used on an ingress resource
+	ImplicitGroupFinalizer = "ingress.k8s.aws/resources"
+
+	// ServiceFinalizer the finalizer used on service resources
+	ServiceFinalizer = "service.k8s.aws/resources"
+
+	// NLBGatewayFinalizer the finalizer we attach to an NLB Gateway resource
+	NLBGatewayFinalizer = "gateway.k8s.aws/nlb"
+
+	// ALBGatewayFinalizer the finalizer we attach to an ALB Gateway resource
+	ALBGatewayFinalizer = "gateway.k8s.aws/alb"
+)
diff --git a/pkg/shared_constants/icmp.go b/pkg/shared_constants/icmp.go
new file mode 100644
index 0000000000..f156a552b1
--- /dev/null
+++ b/pkg/shared_constants/icmp.go
@@ -0,0 +1,12 @@
+package shared_constants
+
+const (
+	ICMPV4Protocol = "icmp"
+	ICMPV6Protocol = "icmpv6"
+
+	ICMPV4CodeForPathMtu = 3 // https://www.iana.org/assignments/icmp-parameters/icmp-parameters.xhtml#icmp-parameters-codes-3
+	ICMPV6CodeForPathMtu = 4
+
+	ICMPV4TypeForPathMtu = 2 // https://www.iana.org/assignments/icmpv6-parameters/icmpv6-parameters.xhtml#icmpv6-parameters-codes-2
+	ICMPV6TypeForPathMtu = 0
+)
diff --git a/pkg/shared_constants/tag_keys.go b/pkg/shared_constants/tag_keys.go
new file mode 100644
index 0000000000..cc6a370112
--- /dev/null
+++ b/pkg/shared_constants/tag_keys.go
@@ -0,0 +1,9 @@
+package shared_constants
+
+const (
+	// TagKeyK8sCluster AWS TagKey for cluster resources.
+	TagKeyK8sCluster = "elbv2.k8s.aws/cluster"
+
+	// TagKeyResource AWS TagKey to denote what resource is being represented.
+	TagKeyResource = "elbv2.k8s.aws/resource"
+)