diff --git a/api/v1beta1/azuremanagedcontrolplane_types.go b/api/v1beta1/azuremanagedcontrolplane_types.go index ac0d4336981..31e366a1b51 100644 --- a/api/v1beta1/azuremanagedcontrolplane_types.go +++ b/api/v1beta1/azuremanagedcontrolplane_types.go @@ -21,16 +21,20 @@ import ( clusterv1 "sigs.k8s.io/cluster-api/api/v1beta1" ) +// PrivateDNSZoneMode determines if the Private DNS Zone gets created. +// It is created by default on a private cluster and can be skipped based on a configured value. +type PrivateDNSZoneMode string + const ( // ManagedClusterFinalizer allows Reconcile to clean up Azure resources associated with the AzureManagedControlPlane before // removing it from the apiserver. ManagedClusterFinalizer = "azuremanagedcontrolplane.infrastructure.cluster.x-k8s.io" // PrivateDNSZoneModeSystem represents mode System for azuremanagedcontrolplane. - PrivateDNSZoneModeSystem string = "System" + PrivateDNSZoneModeSystem PrivateDNSZoneMode = "System" // PrivateDNSZoneModeNone represents mode None for azuremanagedcontrolplane. - PrivateDNSZoneModeNone string = "None" + PrivateDNSZoneModeNone PrivateDNSZoneMode = "None" ) // UpgradeChannel determines the type of upgrade channel for automatically upgrading the cluster. diff --git a/api/v1beta1/types_class.go b/api/v1beta1/types_class.go index 452eab517f8..f5ec3c7bb34 100644 --- a/api/v1beta1/types_class.go +++ b/api/v1beta1/types_class.go @@ -459,6 +459,12 @@ type NetworkClassSpec struct { // +optional PrivateDNSZoneName string `json:"privateDNSZoneName,omitempty"` + // PrivateDNSZone enables private dns zone creation modes for a private cluster. + // When unspecified, it defaults to PrivateDNSZoneModeSystem which creates a private DNS zone. + // +kubebuilder:validation:Enum=System;None + // +optional + PrivateDNSZone *PrivateDNSZoneMode `json:"privateDNSZone,omitempty"` + // PrivateDNSZoneResourceGroup defines the resource group to be used for Azure Private DNS Zone. // If not specified, the resource group of the cluster will be used to create the Azure Private DNS Zone. // +optional diff --git a/api/v1beta1/zz_generated.deepcopy.go b/api/v1beta1/zz_generated.deepcopy.go index eaa79ca7ebc..c8fd00f0222 100644 --- a/api/v1beta1/zz_generated.deepcopy.go +++ b/api/v1beta1/zz_generated.deepcopy.go @@ -3721,6 +3721,11 @@ func (in *NatGatewayClassSpec) DeepCopy() *NatGatewayClassSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkClassSpec) DeepCopyInto(out *NetworkClassSpec) { *out = *in + if in.PrivateDNSZone != nil { + in, out := &in.PrivateDNSZone, &out.PrivateDNSZone + *out = new(PrivateDNSZoneMode) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkClassSpec. @@ -3784,7 +3789,7 @@ func (in *NetworkSpec) DeepCopyInto(out *NetworkSpec) { *out = make([]LoadBalancerPort, len(*in)) copy(*out, *in) } - out.NetworkClassSpec = in.NetworkClassSpec + in.NetworkClassSpec.DeepCopyInto(&out.NetworkClassSpec) } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkSpec. @@ -3800,7 +3805,7 @@ func (in *NetworkSpec) DeepCopy() *NetworkSpec { // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *NetworkTemplateSpec) DeepCopyInto(out *NetworkTemplateSpec) { *out = *in - out.NetworkClassSpec = in.NetworkClassSpec + in.NetworkClassSpec.DeepCopyInto(&out.NetworkClassSpec) in.Vnet.DeepCopyInto(&out.Vnet) if in.Subnets != nil { in, out := &in.Subnets, &out.Subnets diff --git a/azure/scope/cluster.go b/azure/scope/cluster.go index f7f035f2e7b..b30f1b501a7 100644 --- a/azure/scope/cluster.go +++ b/azure/scope/cluster.go @@ -559,7 +559,7 @@ func (s *ClusterScope) VNetSpec() azure.ASOResourceSpecGetter[*asonetworkv1api20 // PrivateDNSSpec returns the private dns zone spec. func (s *ClusterScope) PrivateDNSSpec() (zoneSpec azure.ResourceSpecGetter, linkSpec, recordSpec []azure.ResourceSpecGetter) { - if s.IsAPIServerPrivate() { + if s.IsAPIServerPrivate() && s.PrivateDNSZoneMode() != infrav1.PrivateDNSZoneModeNone { resourceGroup := s.ResourceGroup() if s.AzureCluster.Spec.NetworkSpec.PrivateDNSZoneResourceGroup != "" { resourceGroup = s.AzureCluster.Spec.NetworkSpec.PrivateDNSZoneResourceGroup @@ -1251,3 +1251,13 @@ func (s *ClusterScope) getLastAppliedSecurityRules(nsgName string) map[string]in } return lastAppliedSecurityRules } + +// PrivateDNSZoneMode returns the current Private DNS Zone mode. +// When unconfigured, the method returns the default. +// Returned value is used to determine if the Private DNS Zone should be created. +func (s *ClusterScope) PrivateDNSZoneMode() infrav1.PrivateDNSZoneMode { + if s.AzureCluster.Spec.NetworkSpec.PrivateDNSZone == nil { + return infrav1.PrivateDNSZoneModeSystem + } + return *s.AzureCluster.Spec.NetworkSpec.PrivateDNSZone +} diff --git a/azure/scope/cluster_test.go b/azure/scope/cluster_test.go index 6bb5c6ba9e7..9463ca4e763 100644 --- a/azure/scope/cluster_test.go +++ b/azure/scope/cluster_test.go @@ -216,6 +216,58 @@ func TestAPIServerHost(t *testing.T) { }, want: "apiserver.example.private", }, + { + name: "private apiserver without private dns zone", + azureCluster: infrav1.AzureCluster{ + Spec: infrav1.AzureClusterSpec{ + AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ + SubscriptionID: fakeSubscriptionID, + IdentityRef: &corev1.ObjectReference{ + Kind: infrav1.AzureClusterIdentityKind, + }, + }, + ControlPlaneEnabled: true, + NetworkSpec: infrav1.NetworkSpec{ + NetworkClassSpec: infrav1.NetworkClassSpec{ + PrivateDNSZoneName: "", + PrivateDNSZone: ptr.To(infrav1.PrivateDNSZoneModeNone), + }, + APIServerLB: &infrav1.LoadBalancerSpec{ + LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ + Type: infrav1.Internal, + }, + }, + }, + }, + }, + want: "apiserver.my-cluster.capz.io", + }, + { + name: "private apiserver with private dns zone", + azureCluster: infrav1.AzureCluster{ + Spec: infrav1.AzureClusterSpec{ + AzureClusterClassSpec: infrav1.AzureClusterClassSpec{ + SubscriptionID: fakeSubscriptionID, + IdentityRef: &corev1.ObjectReference{ + Kind: infrav1.AzureClusterIdentityKind, + }, + }, + ControlPlaneEnabled: true, + NetworkSpec: infrav1.NetworkSpec{ + NetworkClassSpec: infrav1.NetworkClassSpec{ + PrivateDNSZoneName: "", + PrivateDNSZone: ptr.To(infrav1.PrivateDNSZoneModeSystem), + }, + APIServerLB: &infrav1.LoadBalancerSpec{ + LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ + Type: infrav1.Internal, + }, + }, + }, + }, + }, + want: "apiserver.my-cluster.capz.io", + }, } for _, tc := range tests { @@ -4137,3 +4189,95 @@ func TestAPIServerLBName(t *testing.T) { }) } } + +func TestPrivateDNSSpec(t *testing.T) { + tests := []struct { + name string + clusterName string + azureClusterNetworkSpec infrav1.NetworkSpec + expectPrivateDNSSpec bool + }{ + { + name: "Default PrivateDNSZone (PrivateDNSZoneModeSystem)", + clusterName: "private-default", + azureClusterNetworkSpec: infrav1.NetworkSpec{ + NetworkClassSpec: infrav1.NetworkClassSpec{ + PrivateDNSZoneName: "fake-privateDNSZoneName", + }, + APIServerLB: &infrav1.LoadBalancerSpec{ + FrontendIPs: []infrav1.FrontendIP{ + { + Name: "api-server-lb-internal-ip", + FrontendIPClass: infrav1.FrontendIPClass{ + PrivateIPAddress: infrav1.DefaultInternalLBIPAddress, + }, + }, + }, + LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ + Type: infrav1.Internal, + }, + }, + }, + expectPrivateDNSSpec: true, + }, + { + name: "PrivateDNSZone set to PrivateDNSZoneModeNone", + clusterName: "private-none", + azureClusterNetworkSpec: infrav1.NetworkSpec{ + NetworkClassSpec: infrav1.NetworkClassSpec{ + PrivateDNSZoneName: "fake-privateDNSZoneName", + PrivateDNSZone: ptr.To(infrav1.PrivateDNSZoneModeNone), + }, + APIServerLB: &infrav1.LoadBalancerSpec{ + LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ + Type: infrav1.Internal, + }, + }, + }, + expectPrivateDNSSpec: false, + }, + { + name: "Public LB", + clusterName: "public-none", + azureClusterNetworkSpec: infrav1.NetworkSpec{ + NetworkClassSpec: infrav1.NetworkClassSpec{ + PrivateDNSZoneName: "fake-privateDNSZoneName", + PrivateDNSZone: ptr.To(infrav1.PrivateDNSZoneModeNone), + }, + APIServerLB: &infrav1.LoadBalancerSpec{ + LoadBalancerClassSpec: infrav1.LoadBalancerClassSpec{ + Type: infrav1.Public, + }, + }, + }, + expectPrivateDNSSpec: false, + }, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + g := NewWithT(t) + + cluster := &clusterv1.Cluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.clusterName, + Namespace: "default", + }, + } + azureCluster := &infrav1.AzureCluster{ + ObjectMeta: metav1.ObjectMeta{ + Name: tc.clusterName, + }, + Spec: infrav1.AzureClusterSpec{ + NetworkSpec: tc.azureClusterNetworkSpec, + }, + } + + clusterScope := &ClusterScope{ + Cluster: cluster, + AzureCluster: azureCluster, + } + zoneSpec, _, _ := clusterScope.PrivateDNSSpec() + g.Expect(zoneSpec != nil).Should(Equal(tc.expectPrivateDNSSpec)) + }) + } +} diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml index 9a82c35e10e..927feee4b73 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclusters.yaml @@ -926,6 +926,14 @@ spec: description: LBType defines an Azure load balancer Type. type: string type: object + privateDNSZone: + description: |- + PrivateDNSZone enables private dns zone creation modes for a private cluster. + When unspecified, it defaults to PrivateDNSZoneModeSystem which creates a private DNS zone. + enum: + - System + - None + type: string privateDNSZoneName: description: PrivateDNSZoneName defines the zone name for the Azure Private DNS. diff --git a/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclustertemplates.yaml b/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclustertemplates.yaml index 2b5acaaec48..6946bd36976 100644 --- a/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclustertemplates.yaml +++ b/config/crd/bases/infrastructure.cluster.x-k8s.io_azureclustertemplates.yaml @@ -593,6 +593,14 @@ spec: Type. type: string type: object + privateDNSZone: + description: |- + PrivateDNSZone enables private dns zone creation modes for a private cluster. + When unspecified, it defaults to PrivateDNSZoneModeSystem which creates a private DNS zone. + enum: + - System + - None + type: string privateDNSZoneName: description: PrivateDNSZoneName defines the zone name for the Azure Private DNS.