From 1ffc668111bbde63b096a0907b6f05588e420046 Mon Sep 17 00:00:00 2001 From: Sai Ganesh Date: Sat, 30 Aug 2025 10:35:02 +0400 Subject: [PATCH 1/2] Add support private ipv4 addresses annotation for NLB --- pkg/providers/v1/aws.go | 5 ++ pkg/providers/v1/aws_loadbalancer.go | 15 +++++- pkg/providers/v1/aws_loadbalancer_test.go | 64 +++++++++++++++++++++++ 3 files changed, 82 insertions(+), 2 deletions(-) diff --git a/pkg/providers/v1/aws.go b/pkg/providers/v1/aws.go index 024dab2ada..da36515e6a 100644 --- a/pkg/providers/v1/aws.go +++ b/pkg/providers/v1/aws.go @@ -227,6 +227,11 @@ const ServiceAnnotationLoadBalancerTargetGroupAttributes = "service.beta.kuberne // static IP addresses for the NLB. Only supported on elbv2 (NLB) const ServiceAnnotationLoadBalancerEIPAllocations = "service.beta.kubernetes.io/aws-load-balancer-eip-allocations" +// ServiceAnnotationLoadBalancerPrivateIPv4Addresses is the annotation used on the +// service to specify a comma separated list of Private IPv4 addresses to use as +// static IP addresses for the NLB. Only supported on elbv2 (NLB) +const ServiceAnnotationLoadBalancerPrivateIPv4Addresses = "service.beta.kubernetes.io/aws-load-balancer-private-ipv4-addresses" + // ServiceAnnotationLoadBalancerTargetNodeLabels is the annotation used on the service // to specify a comma-separated list of key-value pairs which will be used to select // the target nodes for the load balancer diff --git a/pkg/providers/v1/aws_loadbalancer.go b/pkg/providers/v1/aws_loadbalancer.go index d45c21bd2d..914c289fe8 100644 --- a/pkg/providers/v1/aws_loadbalancer.go +++ b/pkg/providers/v1/aws_loadbalancer.go @@ -177,9 +177,17 @@ func (c *Cloud) ensureLoadBalancerv2(ctx context.Context, namespacedName types.N } } + var privateIPv4Addresses []string + if privateIpList, present := annotations[ServiceAnnotationLoadBalancerPrivateIPv4Addresses]; present { + privateIPv4Addresses = strings.Split(privateIpList, ",") + if len(privateIPv4Addresses) != len(discoveredSubnetIDs) { + return nil, fmt.Errorf("error creating load balancer: Must have same number of Private IPv4Addresses (%d) and SubnetIDs (%d)", len(privateIPv4Addresses), len(discoveredSubnetIDs)) + } + } + // We are supposed to specify one subnet per AZ. // TODO: What happens if we have more than one subnet per AZ? - createRequest.SubnetMappings = createSubnetMappings(discoveredSubnetIDs, allocationIDs) + createRequest.SubnetMappings = createSubnetMappings(discoveredSubnetIDs, allocationIDs, privateIPv4Addresses) for k, v := range tags { createRequest.Tags = append(createRequest.Tags, elbv2types.Tag{ @@ -1466,7 +1474,7 @@ func elbListenersAreEqual(actual, expected elbtypes.Listener) bool { return true } -func createSubnetMappings(subnetIDs []string, allocationIDs []string) []elbv2types.SubnetMapping { +func createSubnetMappings(subnetIDs []string, allocationIDs []string, privateIPv4Addresses []string) []elbv2types.SubnetMapping { response := []elbv2types.SubnetMapping{} for index, id := range subnetIDs { @@ -1474,6 +1482,9 @@ func createSubnetMappings(subnetIDs []string, allocationIDs []string) []elbv2typ if len(allocationIDs) > 0 { sm.AllocationId = aws.String(allocationIDs[index]) } + if len(privateIPv4Addresses) > 0 { + sm.PrivateIPv4Address = aws.String(privateIPv4Addresses[index]) + } response = append(response, sm) } diff --git a/pkg/providers/v1/aws_loadbalancer_test.go b/pkg/providers/v1/aws_loadbalancer_test.go index 569c4434db..1518bdf7aa 100644 --- a/pkg/providers/v1/aws_loadbalancer_test.go +++ b/pkg/providers/v1/aws_loadbalancer_test.go @@ -1312,6 +1312,70 @@ func TestCloud_buildTargetGroupAttributes(t *testing.T) { } } +func TestCreateSubnetMappings(t *testing.T) { + tests := []struct { + name string + subnetIDs []string + allocationIDs []string + privateIPv4Addresses []string + expectedSubnetMappings []elbv2types.SubnetMapping + }{ + { + name: "Add allocation ids", + subnetIDs: []string{"subnet-1234", "subnet-3456"}, + allocationIDs: []string{"eipalloc-2345", "eipalloc-4567"}, + privateIPv4Addresses: []string{}, + expectedSubnetMappings: []elbv2types.SubnetMapping{ + { + SubnetId: aws.String("subnet-1234"), + AllocationId: aws.String("eipalloc-2345"), + }, + { + SubnetId: aws.String("subnet-3456"), + AllocationId: aws.String("eipalloc-4567"), + }, + }, + }, + { + name: "Add Private ip address", + subnetIDs: []string{"subnet-1234", "subnet-3456"}, + allocationIDs: []string{}, + privateIPv4Addresses: []string{"10.1.2.3", "10.2.3.4"}, + expectedSubnetMappings: []elbv2types.SubnetMapping{ + { + SubnetId: aws.String("subnet-1234"), + PrivateIPv4Address: aws.String("10.1.2.3"), + }, + { + SubnetId: aws.String("subnet-3456"), + PrivateIPv4Address: aws.String("10.2.3.4"), + }, + }, + }, + { + name: "No private ips and allocation ids", + subnetIDs: []string{"subnet-1234", "subnet-3456"}, + allocationIDs: []string{}, + privateIPv4Addresses: []string{}, + expectedSubnetMappings: []elbv2types.SubnetMapping{ + { + SubnetId: aws.String("subnet-1234"), + }, + { + SubnetId: aws.String("subnet-3456"), + }, + }, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + actualSubnetMappings := createSubnetMappings(tt.subnetIDs, tt.allocationIDs, tt.privateIPv4Addresses) + assert.Equal(t, tt.expectedSubnetMappings, actualSubnetMappings) + }) + } +} + // Unit test generated by Cursor AI func TestGetKeyValuePropertiesFromAnnotation_TargetGroupAttributes(t *testing.T) { tests := []struct { From e5ba2d24b35019ccdadd8f0714e606abf599f827 Mon Sep 17 00:00:00 2001 From: Sai Ganesh Date: Fri, 26 Sep 2025 12:47:58 +0400 Subject: [PATCH 2/2] Fix the linting issue --- pkg/providers/v1/aws_loadbalancer.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pkg/providers/v1/aws_loadbalancer.go b/pkg/providers/v1/aws_loadbalancer.go index 914c289fe8..57cc17a999 100644 --- a/pkg/providers/v1/aws_loadbalancer.go +++ b/pkg/providers/v1/aws_loadbalancer.go @@ -178,8 +178,8 @@ func (c *Cloud) ensureLoadBalancerv2(ctx context.Context, namespacedName types.N } var privateIPv4Addresses []string - if privateIpList, present := annotations[ServiceAnnotationLoadBalancerPrivateIPv4Addresses]; present { - privateIPv4Addresses = strings.Split(privateIpList, ",") + if privateIPList, present := annotations[ServiceAnnotationLoadBalancerPrivateIPv4Addresses]; present { + privateIPv4Addresses = strings.Split(privateIPList, ",") if len(privateIPv4Addresses) != len(discoveredSubnetIDs) { return nil, fmt.Errorf("error creating load balancer: Must have same number of Private IPv4Addresses (%d) and SubnetIDs (%d)", len(privateIPv4Addresses), len(discoveredSubnetIDs)) }