Skip to content

Commit 4dde249

Browse files
committed
Rfrain from adding Egress IP to public LB backend pool
This PR is to stop adding Egress IP to public load balancer backend pool regardless of presence of an OutBoundRule in any Azure cluster. This change comes with a consequence of no outbound connectivity except to the infrastructure subnet even if there is no OutBoundRule. However this is required to tackle following situation: - If an infra node is being used as an egressNode then health check for egress IP also succeeds when it is added to public load balancer and LB considers it as a legitimate ingress router backend. - Limits the number of egress IP which can be created on a cluster due to some Azure specific limitation. Signed-off-by: Arnab Ghosh <[email protected]>
1 parent 467e50f commit 4dde249

File tree

1 file changed

+10
-104
lines changed

1 file changed

+10
-104
lines changed

pkg/cloudprovider/azure.go

Lines changed: 10 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,15 @@ package cloudprovider
33
import (
44
"context"
55
"fmt"
6-
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
7-
"k8s.io/utils/ptr"
86
"net"
97
"os"
108
"strings"
119
"sync"
1210
"time"
1311

12+
"github.com/Azure/azure-sdk-for-go/sdk/azcore/runtime"
13+
"k8s.io/utils/ptr"
14+
1415
"github.com/Azure/azure-sdk-for-go/sdk/azcore"
1516
"github.com/Azure/azure-sdk-for-go/sdk/azcore/arm"
1617
"github.com/Azure/azure-sdk-for-go/sdk/azcore/cloud"
@@ -48,7 +49,6 @@ type Azure struct {
4849
vmClient *armcompute.VirtualMachinesClient
4950
virtualNetworkClient *armnetwork.VirtualNetworksClient
5051
networkClient *armnetwork.InterfacesClient
51-
backendAddressPoolClient *armnetwork.LoadBalancerBackendAddressPoolsClient
5252
nodeMapLock sync.Mutex
5353
nodeLockMap map[string]*sync.Mutex
5454
azureWorkloadIdentityEnabled bool
@@ -162,11 +162,6 @@ func (a *Azure) initCredentials() error {
162162
return fmt.Errorf("failed to initialize new VirtualNetworksClient: %w", err)
163163
}
164164

165-
a.backendAddressPoolClient, err = armnetwork.NewLoadBalancerBackendAddressPoolsClient(cfg.subscriptionID, cred, options)
166-
if err != nil {
167-
return fmt.Errorf("failed to initialize new LoadBalancerBackendAddressPoolsClient: %w", err)
168-
}
169-
170165
return nil
171166
}
172167

@@ -198,65 +193,14 @@ func (a *Azure) AssignPrivateIP(ip net.IP, node *corev1.Node) error {
198193
name := fmt.Sprintf("%s_%s", node.Name, ipc)
199194
untrue := false
200195

201-
// In some Azure setups (Azure private, public ARO, private ARO) outbound connectivity is achieved through
202-
// outbound rules tied to the backend address pool of the primary IP of the VM NIC. An Azure constraint
203-
// forbids the creation of a secondary IP tied to such address pool and would result in
204-
// OutboundRuleCannotBeUsedWithBackendAddressPoolThatIsReferencedBySecondaryIpConfigs.
205-
// Work around it by not specifying the backend address pool when an outbound rule is set, even though
206-
// that means preventing outbound connectivity to the egress IP, which will be able to reach the
207-
// infrastructure subnet nonetheless. In public Azure clusters, outbound connectivity is achieved through
208-
// UserDefinedRouting, which doesn't impose such constraints on secondary IPs.
209-
loadBalancerBackendAddressPoolsArgument := networkInterface.Properties.IPConfigurations[0].Properties.LoadBalancerBackendAddressPools
210-
var attachedOutboundRule *armnetwork.SubResource
211-
OuterLoop:
212-
for _, ipconfig := range networkInterface.Properties.IPConfigurations {
213-
if ipconfig.Properties.LoadBalancerBackendAddressPools != nil {
214-
for _, pool := range ipconfig.Properties.LoadBalancerBackendAddressPools {
215-
if pool.ID == nil {
216-
continue
217-
}
218-
// for some reason, the struct for the pool above is not entirely filled out:
219-
// BackendAddressPoolPropertiesFormat:(*network.BackendAddressPoolPropertiesFormat)(nil)
220-
// Do a separate get for this pool in order to check whether there are any outbound rules
221-
// attached to it
222-
realPool, err := a.getBackendAddressPool(ptr.Deref(pool.ID, ""))
223-
if err != nil {
224-
return fmt.Errorf("error looking up backend address pool %s with ID %s: %v", ptr.Deref(pool.Name, ""), ptr.Deref(pool.ID, ""), err)
225-
}
226-
if realPool.Properties.LoadBalancerBackendAddresses != nil && len(realPool.Properties.LoadBalancerBackendAddresses) > 0 {
227-
if realPool.Properties.OutboundRule != nil {
228-
loadBalancerBackendAddressPoolsArgument = nil
229-
attachedOutboundRule = realPool.Properties.OutboundRule
230-
break OuterLoop
231-
}
232-
if realPool.Properties.OutboundRules != nil && len(realPool.Properties.OutboundRules) > 0 {
233-
loadBalancerBackendAddressPoolsArgument = nil
234-
attachedOutboundRule = (realPool.Properties.OutboundRules)[0]
235-
break OuterLoop
236-
}
237-
}
238-
}
239-
}
240-
}
241-
if loadBalancerBackendAddressPoolsArgument == nil {
242-
outboundRuleStr := ""
243-
if attachedOutboundRule != nil && attachedOutboundRule.ID != nil {
244-
// https://issues.redhat.com/browse/OCPBUGS-33617 showed that there can be a rule without an ID...
245-
outboundRuleStr = fmt.Sprintf(": %s", ptr.Deref(attachedOutboundRule.ID, ""))
246-
}
247-
klog.Warningf("Egress IP %s will have no outbound connectivity except for the infrastructure subnet: "+
248-
"omitting backend address pool when adding secondary IP: it has an outbound rule already%s",
249-
ipc, outboundRuleStr)
250-
}
251196
newIPConfiguration := &armnetwork.InterfaceIPConfiguration{
252197
Name: &name,
253198
Properties: &armnetwork.InterfaceIPConfigurationPropertiesFormat{
254-
PrivateIPAddress: &ipc,
255-
PrivateIPAllocationMethod: ptr.To(armnetwork.IPAllocationMethodStatic),
256-
Subnet: networkInterface.Properties.IPConfigurations[0].Properties.Subnet,
257-
Primary: &untrue,
258-
LoadBalancerBackendAddressPools: loadBalancerBackendAddressPoolsArgument,
259-
ApplicationSecurityGroups: applicationSecurityGroups,
199+
PrivateIPAddress: &ipc,
200+
PrivateIPAllocationMethod: ptr.To(armnetwork.IPAllocationMethodStatic),
201+
Subnet: networkInterface.Properties.IPConfigurations[0].Properties.Subnet,
202+
Primary: &untrue,
203+
ApplicationSecurityGroups: applicationSecurityGroups,
260204
},
261205
}
262206
for _, ipCfg := range ipConfigurations {
@@ -272,6 +216,8 @@ OuterLoop:
272216
ipConfigurations = append(ipConfigurations, newIPConfiguration)
273217
networkInterface.Properties.IPConfigurations = ipConfigurations
274218
// Send the request
219+
klog.Warningf("Egress IP %s will have no outbound connectivity except for the infrastructure subnet: "+
220+
"omitting backend address pool when adding secondary IP", ipc)
275221
poller, err := a.createOrUpdate(networkInterface)
276222
if err != nil {
277223
return err
@@ -490,46 +436,6 @@ func (a *Azure) getNetworkInterfaces(instance *armcompute.VirtualMachine) ([]arm
490436
return networkInterfaces, nil
491437
}
492438

493-
func splitObjectID(azureResourceID string) (resourceGroupName, loadBalancerName, backendAddressPoolName string) {
494-
// example of an azureResourceID:
495-
// "/subscriptions/53b8f551-f0fc-4bea-8cba-6d1fefd54c8a/resourceGroups/huirwang-debug1-2qh9t-rg/providers/Microsoft.Network/loadBalancers/huirwang-debug1-2qh9t/backendAddressPools/huirwang-debug1-2qh9t"
496-
497-
// Split the Azure resource ID into parts using "/"
498-
parts := strings.Split(azureResourceID, "/")
499-
500-
// Iterate through the parts to find the relevant subIDs
501-
for i, part := range parts {
502-
switch part {
503-
case "resourceGroups":
504-
if i+1 < len(parts) {
505-
resourceGroupName = parts[i+1]
506-
}
507-
case "loadBalancers":
508-
if i+1 < len(parts) {
509-
loadBalancerName = parts[i+1]
510-
}
511-
case "backendAddressPools":
512-
if i+1 < len(parts) {
513-
backendAddressPoolName = parts[i+1]
514-
}
515-
}
516-
}
517-
return
518-
}
519-
520-
func (a *Azure) getBackendAddressPool(poolID string) (*armnetwork.BackendAddressPool, error) {
521-
ctx, cancel := context.WithTimeout(a.ctx, defaultAzureOperationTimeout)
522-
defer cancel()
523-
resourceGroupName, loadBalancerName, backendAddressPoolName := splitObjectID(poolID)
524-
response, err := a.backendAddressPoolClient.Get(ctx, resourceGroupName, loadBalancerName, backendAddressPoolName, nil)
525-
if err != nil {
526-
return nil, fmt.Errorf("failed to retrieve backend address pool for backendAddressPoolClient=%s, loadBalancerName=%s, backendAddressPoolName=%s: %w",
527-
resourceGroupName, loadBalancerName, backendAddressPoolName, err)
528-
}
529-
return &response.BackendAddressPool, nil
530-
531-
}
532-
533439
func (a *Azure) getNetworkInterface(id string) (armnetwork.Interface, error) {
534440
ctx, cancel := context.WithTimeout(a.ctx, defaultAzureOperationTimeout)
535441
defer cancel()

0 commit comments

Comments
 (0)