sigs.k8s.io/cluster-api-provider-azure@v1.14.3/test/e2e/azure_securitygroups.go (about)

     1  //go:build e2e
     2  // +build e2e
     3  
     4  /*
     5  Copyright 2023 The Kubernetes Authors.
     6  
     7  Licensed under the Apache License, Version 2.0 (the "License");
     8  you may not use this file except in compliance with the License.
     9  You may obtain a copy of the License at
    10  
    11      http://www.apache.org/licenses/LICENSE-2.0
    12  
    13  Unless required by applicable law or agreed to in writing, software
    14  distributed under the License is distributed on an "AS IS" BASIS,
    15  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    16  See the License for the specific language governing permissions and
    17  limitations under the License.
    18  */
    19  
    20  package e2e
    21  
    22  import (
    23  	"context"
    24  
    25  	"github.com/Azure/azure-sdk-for-go/sdk/azidentity"
    26  	"github.com/Azure/azure-sdk-for-go/sdk/resourcemanager/network/armnetwork/v4"
    27  	. "github.com/onsi/ginkgo/v2"
    28  	. "github.com/onsi/gomega"
    29  	corev1 "k8s.io/api/core/v1"
    30  	"k8s.io/utils/ptr"
    31  	infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1"
    32  	clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1"
    33  	"sigs.k8s.io/cluster-api/test/framework"
    34  	"sigs.k8s.io/controller-runtime/pkg/client"
    35  )
    36  
    37  // AzureSecurityGroupsSpecInput is the input for AzureSecurityGroupsSpec.
    38  type AzureSecurityGroupsSpecInput struct {
    39  	BootstrapClusterProxy framework.ClusterProxy
    40  	Namespace             *corev1.Namespace
    41  	ClusterName           string
    42  	Cluster               *clusterv1.Cluster
    43  	WaitForUpdate         []interface{}
    44  }
    45  
    46  func AzureSecurityGroupsSpec(ctx context.Context, inputGetter func() AzureSecurityGroupsSpecInput) {
    47  	var (
    48  		specName         = "azure-vmextensions"
    49  		testSecurityRule = infrav1.SecurityRule{
    50  			Name:             "test-security-rule",
    51  			Description:      "test-security-rule",
    52  			Protocol:         "Tcp",
    53  			Direction:        "Outbound",
    54  			Priority:         100,
    55  			SourcePorts:      ptr.To("*"),
    56  			DestinationPorts: ptr.To("80"),
    57  			Source:           ptr.To("*"),
    58  			Destination:      ptr.To("*"),
    59  			Action:           "Allow",
    60  		}
    61  		testSecurityRule2 = infrav1.SecurityRule{
    62  			Name:             "test-security-rule-2",
    63  			Description:      "test-security-rule-2",
    64  			Protocol:         "Tcp",
    65  			Direction:        "Inbound",
    66  			Priority:         110,
    67  			SourcePorts:      ptr.To("*"),
    68  			DestinationPorts: ptr.To("80"),
    69  			Source:           ptr.To("*"),
    70  			Destination:      ptr.To("*"),
    71  			Action:           "Allow",
    72  		}
    73  		input AzureSecurityGroupsSpecInput
    74  	)
    75  
    76  	Expect(ctx).NotTo(BeNil(), "ctx is required for %s spec", specName)
    77  
    78  	input = inputGetter()
    79  	Expect(input.BootstrapClusterProxy).NotTo(BeNil(), "Invalid argument. input.BootstrapClusterProxy can't be nil when calling %s spec", specName)
    80  	Expect(input.Namespace).NotTo(BeNil(), "Invalid argument. input.Namespace can't be nil when calling %s spec", specName)
    81  	Expect(input.ClusterName).NotTo(BeEmpty(), "Invalid argument. input.ClusterName can't be empty when calling %s spec", specName)
    82  
    83  	By("creating a Kubernetes client to the workload cluster")
    84  	workloadClusterProxy := input.BootstrapClusterProxy.GetWorkloadCluster(ctx, input.Namespace.Name, input.ClusterName)
    85  	Expect(workloadClusterProxy).NotTo(BeNil())
    86  	mgmtClient := bootstrapClusterProxy.GetClient()
    87  	Expect(mgmtClient).NotTo(BeNil())
    88  
    89  	By("creating securitygroups and securityrules clients")
    90  	cred, err := azidentity.NewDefaultAzureCredential(nil)
    91  	Expect(err).NotTo(HaveOccurred())
    92  
    93  	securityGroupsClient, err := armnetwork.NewSecurityGroupsClient(getSubscriptionID(Default), cred, nil)
    94  	Expect(err).NotTo(HaveOccurred())
    95  
    96  	securityRulesClient, err := armnetwork.NewSecurityRulesClient(getSubscriptionID(Default), cred, nil)
    97  	Expect(err).NotTo(HaveOccurred())
    98  
    99  	azureCluster := &infrav1.AzureCluster{}
   100  	err = mgmtClient.Get(ctx, client.ObjectKey{
   101  		Namespace: input.Cluster.Spec.InfrastructureRef.Namespace,
   102  		Name:      input.Cluster.Spec.InfrastructureRef.Name,
   103  	}, azureCluster)
   104  	Expect(err).NotTo(HaveOccurred())
   105  
   106  	var expectedSubnets infrav1.Subnets
   107  	checkSubnets := func(g Gomega) {
   108  		for _, expectedSubnet := range expectedSubnets {
   109  			securityGroup, err := securityGroupsClient.Get(ctx, azureCluster.Spec.ResourceGroup, expectedSubnet.SecurityGroup.Name, nil)
   110  			g.Expect(err).NotTo(HaveOccurred())
   111  
   112  			var securityRules []string
   113  			pager := securityRulesClient.NewListPager(azureCluster.Spec.ResourceGroup, *securityGroup.Name, nil)
   114  			for pager.More() {
   115  				nextResult, err := pager.NextPage(ctx)
   116  				g.Expect(err).NotTo(HaveOccurred())
   117  				for _, securityRule := range nextResult.Value {
   118  					securityRules = append(securityRules, *securityRule.Name)
   119  				}
   120  			}
   121  
   122  			var expectedSecurityRuleNames []string
   123  			for _, expectedSecurityRule := range expectedSubnet.SecurityGroup.SecurityRules {
   124  				expectedSecurityRuleNames = append(expectedSecurityRuleNames, expectedSecurityRule.Name)
   125  			}
   126  
   127  			g.Expect(securityRules).To(ConsistOf(expectedSecurityRuleNames))
   128  		}
   129  	}
   130  
   131  	Byf("Creating subnets for the %s cluster", input.ClusterName)
   132  	testSubnet := infrav1.SubnetSpec{
   133  		SubnetClassSpec: infrav1.SubnetClassSpec{
   134  			Name: "test-subnet",
   135  			Role: infrav1.SubnetNode,
   136  		},
   137  		SecurityGroup: infrav1.SecurityGroup{
   138  			Name: "test-security-group",
   139  			SecurityGroupClass: infrav1.SecurityGroupClass{
   140  				SecurityRules: []infrav1.SecurityRule{
   141  					testSecurityRule,
   142  				},
   143  			},
   144  		},
   145  	}
   146  	originalSubnets := azureCluster.Spec.NetworkSpec.Subnets
   147  	expectedSubnets = originalSubnets
   148  	expectedSubnets = append(expectedSubnets, testSubnet)
   149  	Eventually(func(g Gomega) {
   150  		g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(azureCluster), azureCluster)).To(Succeed())
   151  		azureCluster.Spec.NetworkSpec.Subnets = expectedSubnets
   152  		g.Expect(mgmtClient.Update(ctx, azureCluster)).To(Succeed())
   153  	}, inputGetter().WaitForUpdate...).Should(Succeed())
   154  	Eventually(checkSubnets, input.WaitForUpdate...).Should(Succeed())
   155  
   156  	By("Creating new security rule for the subnet")
   157  	Expect(expectedSubnets).NotTo(BeEmpty())
   158  	testSubnet.SecurityGroup.SecurityRules = infrav1.SecurityRules{testSecurityRule, testSecurityRule2}
   159  	expectedSubnets = originalSubnets
   160  	expectedSubnets = append(expectedSubnets, testSubnet)
   161  	Eventually(func(g Gomega) {
   162  		g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(azureCluster), azureCluster)).To(Succeed())
   163  		azureCluster.Spec.NetworkSpec.Subnets = expectedSubnets
   164  		g.Expect(mgmtClient.Update(ctx, azureCluster)).To(Succeed())
   165  	}, inputGetter().WaitForUpdate...).Should(Succeed())
   166  	Eventually(checkSubnets, input.WaitForUpdate...).Should(Succeed())
   167  
   168  	By("Deleting security rule from the subnet")
   169  	Expect(expectedSubnets).NotTo(BeEmpty())
   170  	testSubnet.SecurityGroup.SecurityRules = infrav1.SecurityRules{testSecurityRule2}
   171  	expectedSubnets = originalSubnets
   172  	expectedSubnets = append(expectedSubnets, testSubnet)
   173  	Eventually(func(g Gomega) {
   174  		g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(azureCluster), azureCluster)).To(Succeed())
   175  		azureCluster.Spec.NetworkSpec.Subnets = expectedSubnets
   176  		g.Expect(mgmtClient.Update(ctx, azureCluster)).To(Succeed())
   177  	}, inputGetter().WaitForUpdate...).Should(Succeed())
   178  	Eventually(checkSubnets, input.WaitForUpdate...).Should(Succeed())
   179  
   180  	Byf("Deleting test subnet for the %s cluster", input.ClusterName)
   181  	Eventually(func(g Gomega) {
   182  		g.Expect(mgmtClient.Get(ctx, client.ObjectKeyFromObject(azureCluster), azureCluster)).To(Succeed())
   183  		azureCluster.Spec.NetworkSpec.Subnets = originalSubnets
   184  		g.Expect(mgmtClient.Update(ctx, azureCluster)).To(Succeed())
   185  	}, inputGetter().WaitForUpdate...).Should(Succeed())
   186  	Eventually(checkSubnets, input.WaitForUpdate...).Should(Succeed())
   187  }