sigs.k8s.io/cluster-api-provider-azure@v1.17.0/azure/services/privateendpoints/spec.go (about) 1 /* 2 Copyright 2023 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package privateendpoints 18 19 import ( 20 "context" 21 "sort" 22 23 asonetworkv1 "github.com/Azure/azure-service-operator/v2/api/network/v1api20220701" 24 "github.com/Azure/azure-service-operator/v2/pkg/genruntime" 25 metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" 26 "k8s.io/utils/ptr" 27 infrav1 "sigs.k8s.io/cluster-api-provider-azure/api/v1beta1" 28 "sigs.k8s.io/cluster-api-provider-azure/azure" 29 ) 30 31 // PrivateLinkServiceConnection defines the specification for a private link service connection associated with a private endpoint. 32 type PrivateLinkServiceConnection struct { 33 Name string 34 PrivateLinkServiceID string 35 GroupIDs []string 36 RequestMessage string 37 } 38 39 // PrivateEndpointSpec defines the specification for a private endpoint. 40 type PrivateEndpointSpec struct { 41 Name string 42 ResourceGroup string 43 Location string 44 CustomNetworkInterfaceName string 45 PrivateIPAddresses []string 46 SubnetID string 47 ApplicationSecurityGroups []string 48 ManualApproval bool 49 PrivateLinkServiceConnections []PrivateLinkServiceConnection 50 AdditionalTags infrav1.Tags 51 ClusterName string 52 } 53 54 // ResourceRef implements azure.ASOResourceSpecGetter. 55 func (s *PrivateEndpointSpec) ResourceRef() *asonetworkv1.PrivateEndpoint { 56 return &asonetworkv1.PrivateEndpoint{ 57 ObjectMeta: metav1.ObjectMeta{ 58 Name: azure.GetNormalizedKubernetesName(s.Name), 59 }, 60 } 61 } 62 63 // Parameters implements azure.ASOResourceSpecGetter. 64 func (s *PrivateEndpointSpec) Parameters(ctx context.Context, existingPrivateEndpoint *asonetworkv1.PrivateEndpoint) (*asonetworkv1.PrivateEndpoint, error) { 65 privateEndpoint := &asonetworkv1.PrivateEndpoint{} 66 if existingPrivateEndpoint != nil { 67 privateEndpoint = existingPrivateEndpoint 68 } 69 70 if len(s.ApplicationSecurityGroups) > 0 { 71 applicationSecurityGroups := make([]asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded, 0, len(s.ApplicationSecurityGroups)) 72 for _, applicationSecurityGroup := range s.ApplicationSecurityGroups { 73 applicationSecurityGroups = append(applicationSecurityGroups, asonetworkv1.ApplicationSecurityGroupSpec_PrivateEndpoint_SubResourceEmbedded{ 74 Reference: &genruntime.ResourceReference{ 75 ARMID: applicationSecurityGroup, 76 }, 77 }) 78 } 79 // Sort the slices in order to get the same order of elements for both new and existing application Security Groups. 80 sort.SliceStable(applicationSecurityGroups, func(i, j int) bool { 81 return applicationSecurityGroups[i].Reference.ARMID < applicationSecurityGroups[j].Reference.ARMID 82 }) 83 privateEndpoint.Spec.ApplicationSecurityGroups = applicationSecurityGroups 84 } 85 86 privateEndpoint.Spec.AzureName = s.Name 87 privateEndpoint.Spec.CustomNetworkInterfaceName = ptr.To(s.CustomNetworkInterfaceName) 88 privateEndpoint.Spec.Location = ptr.To(s.Location) 89 90 if len(s.PrivateIPAddresses) > 0 { 91 privateIPAddresses := make([]asonetworkv1.PrivateEndpointIPConfiguration, 0, len(s.PrivateIPAddresses)) 92 for _, address := range s.PrivateIPAddresses { 93 ipConfig := asonetworkv1.PrivateEndpointIPConfiguration{PrivateIPAddress: ptr.To(address)} 94 privateIPAddresses = append(privateIPAddresses, ipConfig) 95 } 96 sort.SliceStable(privateIPAddresses, func(i, j int) bool { 97 return *privateIPAddresses[i].PrivateIPAddress < *privateIPAddresses[j].PrivateIPAddress 98 }) 99 privateEndpoint.Spec.IpConfigurations = privateIPAddresses 100 } 101 102 if len(s.PrivateLinkServiceConnections) > 0 { 103 privateLinkServiceConnections := make([]asonetworkv1.PrivateLinkServiceConnection, 0, len(s.PrivateLinkServiceConnections)) 104 for _, privateLinkServiceConnection := range s.PrivateLinkServiceConnections { 105 linkServiceConnection := asonetworkv1.PrivateLinkServiceConnection{ 106 Name: ptr.To(privateLinkServiceConnection.Name), 107 PrivateLinkServiceReference: &genruntime.ResourceReference{ 108 ARMID: privateLinkServiceConnection.PrivateLinkServiceID, 109 }, 110 } 111 112 if len(privateLinkServiceConnection.GroupIDs) > 0 { 113 linkServiceConnection.GroupIds = privateLinkServiceConnection.GroupIDs 114 } 115 116 if privateLinkServiceConnection.RequestMessage != "" { 117 linkServiceConnection.RequestMessage = ptr.To(privateLinkServiceConnection.RequestMessage) 118 } 119 privateLinkServiceConnections = append(privateLinkServiceConnections, linkServiceConnection) 120 } 121 sort.SliceStable(privateLinkServiceConnections, func(i, j int) bool { 122 return *privateLinkServiceConnections[i].Name < *privateLinkServiceConnections[j].Name 123 }) 124 125 if s.ManualApproval { 126 privateEndpoint.Spec.ManualPrivateLinkServiceConnections = privateLinkServiceConnections 127 } else { 128 privateEndpoint.Spec.PrivateLinkServiceConnections = privateLinkServiceConnections 129 } 130 } 131 132 privateEndpoint.Spec.Owner = &genruntime.KnownResourceReference{ 133 Name: azure.GetNormalizedKubernetesName(s.ResourceGroup), 134 } 135 136 privateEndpoint.Spec.Subnet = &asonetworkv1.Subnet_PrivateEndpoint_SubResourceEmbedded{ 137 Reference: &genruntime.ResourceReference{ 138 ARMID: s.SubnetID, 139 }, 140 } 141 142 privateEndpoint.Spec.Tags = infrav1.Build(infrav1.BuildParams{ 143 ClusterName: s.ClusterName, 144 Lifecycle: infrav1.ResourceLifecycleOwned, 145 Name: ptr.To(s.Name), 146 Additional: s.AdditionalTags, 147 }) 148 149 return privateEndpoint, nil 150 } 151 152 // WasManaged implements azure.ASOResourceSpecGetter. 153 // It always returns true since CAPZ doesn't support BYO private endpoints. 154 func (s *PrivateEndpointSpec) WasManaged(privateEndpoint *asonetworkv1.PrivateEndpoint) bool { 155 return true 156 }