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 }