Skip to content

Commit 4d24cb6

Browse files
committed
Remove any Egress IP from Azure public LB backend
The consensus is to not add egress IP to public load balancer backend pool regardless of the presence of an OutBoundRule. During upgrade this PR let cobtroller removes any egress IP added to public load balancer backend pool previously. Signed-off-by: Arnab Ghosh <[email protected]>
1 parent 73a52ca commit 4d24cb6

File tree

7 files changed

+88
-6
lines changed

7 files changed

+88
-6
lines changed

pkg/cloudprovider/aws.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,11 @@ func (a *AWS) GetNodeEgressIPConfiguration(node *corev1.Node, cloudPrivateIPConf
226226
return []*NodeEgressIPConfiguration{config}, nil
227227
}
228228

229+
func (a *AWS) SyncLBBackend(_ net.IP, _ *corev1.Node) error {
230+
// We dont add Egress IP to AWS public LB backend; nothing to do
231+
return nil
232+
}
233+
229234
// Unfortunately the AWS API (WaitUntilInstanceRunning) only handles equality
230235
// assertion: so on delete we can't specify and assert that the IP which is
231236
// being removed is completely removed, we are forced to do the inverse, i.e:

pkg/cloudprovider/azure.go

Lines changed: 57 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,11 @@ import (
99
"sync"
1010
"time"
1111

12-
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
13-
"k8s.io/utils/ptr"
14-
1512
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1613
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
1714
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
1815
"github.com/Azure/azure-sdk-for-go/sdk/azcore/policy"
16+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
1917
"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
2018
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/compute/armcompute"
2119
"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v6"
@@ -26,6 +24,7 @@ import (
2624
corev1 "k8s.io/api/core/v1"
2725
"k8s.io/klog/v2"
2826
utilnet "k8s.io/utils/net"
27+
"k8s.io/utils/ptr"
2928
)
3029

3130
const (
@@ -51,6 +50,7 @@ type Azure struct {
5150
nodeMapLock sync.Mutex
5251
nodeLockMap map[string]*sync.Mutex
5352
azureWorkloadIdentityEnabled bool
53+
lbBackendPoolSynced bool
5454
}
5555

5656
type azureCredentialsConfig struct {
@@ -302,6 +302,60 @@ func (a *Azure) GetNodeEgressIPConfiguration(node *corev1.Node, cloudPrivateIPCo
302302
return []*NodeEgressIPConfiguration{config}, nil
303303
}
304304

305+
// The consensus is to not add egress IP to public load balancer
306+
// backend pool regardless of the presence of an OutBoundRule.
307+
// During upgrade this function removes any egress IP added to
308+
// public load balancer backend pool previously.
309+
func (a *Azure) SyncLBBackend(ip net.IP, node *corev1.Node) error {
310+
if a.lbBackendPoolSynced {
311+
// nothing to do. Return immediately if LB backend has already synced
312+
return nil
313+
}
314+
ipc := ip.String()
315+
klog.Infof("Acquiring node lock for modifying load balancer backend pool, node: %s, ip: %s", node.Name, ipc)
316+
nodeLock := a.getNodeLock(node.Name)
317+
nodeLock.Lock()
318+
defer nodeLock.Unlock()
319+
instance, err := a.getInstance(node)
320+
if err != nil {
321+
return err
322+
}
323+
networkInterfaces, err := a.getNetworkInterfaces(instance)
324+
if err != nil {
325+
return err
326+
}
327+
if networkInterfaces[0].Properties == nil {
328+
return fmt.Errorf("nil network interface properties")
329+
}
330+
// Perform the operation against the first interface listed, which will be
331+
// the primary interface (if it's defined as such) or the first one returned
332+
// following the order Azure specifies.
333+
networkInterface := networkInterfaces[0]
334+
var loadBalanceerBackendPoolModified bool
335+
// omit Egress IP from LB backend pool
336+
ipConfigurations := networkInterface.Properties.IPConfigurations
337+
for _, ipCfg := range ipConfigurations {
338+
if ptr.Deref(ipCfg.Properties.PrivateIPAddress, "") == ipc &&
339+
ipCfg.Properties.LoadBalancerBackendAddressPools != nil {
340+
ipCfg.Properties.LoadBalancerBackendAddressPools = nil
341+
loadBalanceerBackendPoolModified = true
342+
}
343+
}
344+
if loadBalanceerBackendPoolModified {
345+
networkInterface.Properties.IPConfigurations = ipConfigurations
346+
poller, err := a.createOrUpdate(networkInterface)
347+
if err != nil {
348+
return err
349+
}
350+
if err = a.waitForCompletion(poller); err != nil {
351+
return err
352+
}
353+
a.lbBackendPoolSynced = true
354+
return nil
355+
}
356+
return nil
357+
}
358+
305359
func (a *Azure) createOrUpdate(networkInterface armnetwork.Interface) (*runtime.Poller[armnetwork.InterfacesClientCreateOrUpdateResponse], error) {
306360
ctx, cancel := context.WithTimeout(a.ctx, defaultAzureOperationTimeout)
307361
defer cancel()

pkg/cloudprovider/cloudprovider.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,10 @@ import (
99
"path/filepath"
1010
"sync"
1111

12+
v1 "github.com/openshift/api/cloudnetwork/v1"
1213
configv1 "github.com/openshift/api/config/v1"
1314
apifeatures "github.com/openshift/api/features"
1415
"github.com/openshift/library-go/pkg/operator/configobserver/featuregates"
15-
16-
v1 "github.com/openshift/api/cloudnetwork/v1"
1716
corev1 "k8s.io/api/core/v1"
1817
)
1918

@@ -61,6 +60,10 @@ type CloudProviderIntf interface {
6160
// instance and IP family (AWS), also: the interface is either keyed by name
6261
// (GCP) or ID (Azure, AWS).
6362
GetNodeEgressIPConfiguration(node *corev1.Node, cloudPrivateIPConfigs []*v1.CloudPrivateIPConfig) ([]*NodeEgressIPConfiguration, error)
63+
64+
// SyncLBBackend removes any egress IP which is already added to backend pool of
65+
// a public load balancer. This is mostly Azure specific and may be removed later.
66+
SyncLBBackend(ip net.IP, node *corev1.Node) error
6467
}
6568

6669
// CloudProviderWithMoveIntf is additional interface that can be added to cloud

pkg/cloudprovider/cloudprovider_fake.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,3 +69,7 @@ func (f *FakeCloudProvider) GetNodeEgressIPConfiguration(node *corev1.Node, clou
6969
}
7070
return nil, nil
7171
}
72+
73+
func (a *FakeCloudProvider) SyncLBBackend(_ net.IP, _ *corev1.Node) error {
74+
return nil
75+
}

pkg/cloudprovider/gcp.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ func (g *GCP) GetNodeEgressIPConfiguration(node *corev1.Node, cloudPrivateIPConf
191191
return nil, nil
192192
}
193193

194+
func (a *GCP) SyncLBBackend(_ net.IP, _ *corev1.Node) error {
195+
// We dont add Egress IP to GCP public LB backend; nothing to do
196+
return nil
197+
}
198+
194199
// The GCP zone operations API call. All GCP infrastructure modifications are
195200
// assigned a unique operation ID and are queued in a global/zone operations
196201
// queue. In the case of assignments of private IP addresses to instances, the

pkg/cloudprovider/openstack.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,11 @@ func (o *OpenStack) GetNodeEgressIPConfiguration(node *corev1.Node, cloudPrivate
546546
return nil, fmt.Errorf("no suitable interface configurations found")
547547
}
548548

549+
func (a *OpenStack) SyncLBBackend(_ net.IP, _ *corev1.Node) error {
550+
// We dont add Egress IP to OpenStack public LB backend; nothing to do
551+
return nil
552+
}
553+
549554
// getNeutronPortNodeEgressIPConfiguration renders the NeutronPortNodeEgressIPConfiguration for a given port.
550555
// The interface is keyed by a neutron UUID.
551556
// If multiple IPv4 repectively multiple IPv6 subnets are attached to the same port, throw an error.

pkg/controller/cloudprivateipconfig/cloudprivateipconfig_controller.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -180,8 +180,14 @@ func (c *CloudPrivateIPConfigController) SyncHandler(key string) error {
180180

181181
nodeNameToAdd, nodeNameToDel := c.computeOp(cloudPrivateIPConfig)
182182
switch {
183-
// Dequeue on NOOP, there's nothing to do
184183
case nodeNameToAdd == "" && nodeNameToDel == "":
184+
node, err := c.nodesLister.Get(cloudPrivateIPConfig.Spec.Node)
185+
if err != nil {
186+
return err
187+
}
188+
if err := c.cloudProviderClient.SyncLBBackend(ip, node); err != nil {
189+
return fmt.Errorf("error while syncing egress IP %q added to LB backend pool", key)
190+
}
185191
return nil
186192
case nodeNameToAdd != "" && nodeNameToDel != "":
187193
klog.Infof("CloudPrivateIPConfig: %q will be moved from node %q to node %q", key, nodeNameToDel, nodeNameToAdd)

0 commit comments

Comments
 (0)