Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

kubernetes_cluster: Add support for private_dns_zone_id #10201

Merged
merged 16 commits into from
Feb 11, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -325,6 +325,48 @@ func testAccKubernetesCluster_privateClusterOn(t *testing.T) {
})
}

func TestAccKubernetesCluster_privateClusterOnWithPrivateDNSZone(t *testing.T) {
checkIfShouldRunTestsIndividually(t)
testAccKubernetesCluster_privateClusterOnWithPrivateDNSZone(t)
}

func testAccKubernetesCluster_privateClusterOnWithPrivateDNSZone(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
r := KubernetesClusterResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.privateClusterWithPrivateDNSZoneConfig(data, true),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("private_cluster_enabled").HasValue("true"),
),
},
data.ImportStep(),
})
}

func TestAccKubernetesCluster_privateClusterOnWithPrivateDNSZoneSystem(t *testing.T) {
checkIfShouldRunTestsIndividually(t)
testAccKubernetesCluster_privateClusterOnWithPrivateDNSZoneSystem(t)
}

func testAccKubernetesCluster_privateClusterOnWithPrivateDNSZoneSystem(t *testing.T) {
data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test")
r := KubernetesClusterResource{}

data.ResourceTest(t, r, []resource.TestStep{
{
Config: r.privateClusterWithPrivateDNSZoneSystemConfig(data, true),
Check: resource.ComposeTestCheckFunc(
check.That(data.ResourceName).ExistsInAzure(r),
check.That(data.ResourceName).Key("private_cluster_enabled").HasValue("true"),
),
},
data.ImportStep(),
})
}

func TestAccKubernetesCluster_privateClusterOff(t *testing.T) {
checkIfShouldRunTestsIndividually(t)
testAccKubernetesCluster_privateClusterOff(t)
Expand Down Expand Up @@ -1059,6 +1101,118 @@ resource "azurerm_kubernetes_cluster" "test" {
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, enablePrivateCluster, data.RandomInteger)
}

func (KubernetesClusterResource) privateClusterWithPrivateDNSZoneConfig(data acceptance.TestData, enablePrivateCluster bool) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-aks-%d"
location = "%s"
}

resource "azurerm_private_dns_zone" "test" {
name = "privatelink.%s.azmk8s.io"
resource_group_name = azurerm_resource_group.test.name
}

resource "azurerm_user_assigned_identity" "test" {
name = "acctestRG-aks-%d"
resource_group_name = azurerm_resource_group.test.name
location = azurerm_resource_group.test.location
}

resource "azurerm_role_assignment" "test" {
scope = azurerm_private_dns_zone.test.id
role_definition_name = "Private DNS Zone Contributor"
principal_id = azurerm_user_assigned_identity.test.principal_id
}

resource "azurerm_kubernetes_cluster" "test" {
name = "acctestaks%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
dns_prefix = "acctestaks%d"
private_cluster_enabled = %t
private_dns_zone_id = azurerm_private_dns_zone.test.id

linux_profile {
admin_username = "acctestuser%d"

ssh_key {
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt [email protected]"
}
}

default_node_pool {
name = "default"
node_count = 1
vm_size = "Standard_DS2_v2"
}

identity {
type = "UserAssigned"
user_assigned_identity_id = azurerm_user_assigned_identity.test.id
}

network_profile {
network_plugin = "kubenet"
load_balancer_sku = "standard"
}

depends_on = [
azurerm_role_assignment.test,
]
}
`, data.RandomInteger, data.Locations.Primary, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger, enablePrivateCluster, data.RandomInteger)
}

func (KubernetesClusterResource) privateClusterWithPrivateDNSZoneSystemConfig(data acceptance.TestData, enablePrivateCluster bool) string {
return fmt.Sprintf(`
provider "azurerm" {
features {}
}

resource "azurerm_resource_group" "test" {
name = "acctestRG-aks-%d"
location = "%s"
}

resource "azurerm_kubernetes_cluster" "test" {
name = "acctestaks%d"
location = azurerm_resource_group.test.location
resource_group_name = azurerm_resource_group.test.name
dns_prefix = "acctestaks%d"
private_cluster_enabled = %t
private_dns_zone_id = "System"

linux_profile {
admin_username = "acctestuser%d"

ssh_key {
key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt [email protected]"
}
}

default_node_pool {
name = "default"
node_count = 1
vm_size = "Standard_DS2_v2"
}

identity {
type = "SystemAssigned"
}

network_profile {
network_plugin = "kubenet"
load_balancer_sku = "standard"
}
}
`, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, enablePrivateCluster, data.RandomInteger)
}

func (KubernetesClusterResource) standardLoadBalancerConfig(data acceptance.TestData) string {
return fmt.Sprintf(`
provider "azurerm" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,22 @@ import (
)

var kubernetesOtherTests = map[string]func(t *testing.T){
"basicAvailabilitySet": testAccKubernetesCluster_basicAvailabilitySet,
"basicVMSS": testAccKubernetesCluster_basicVMSS,
"requiresImport": testAccKubernetesCluster_requiresImport,
"criticalAddonsTaint": testAccKubernetesCluster_criticalAddonsTaint,
"linuxProfile": testAccKubernetesCluster_linuxProfile,
"nodeLabels": testAccKubernetesCluster_nodeLabels,
"nodeResourceGroup": testAccKubernetesCluster_nodeResourceGroup,
"paidSku": testAccKubernetesCluster_paidSku,
"upgradeConfig": testAccKubernetesCluster_upgrade,
"tags": testAccKubernetesCluster_tags,
"windowsProfile": testAccKubernetesCluster_windowsProfile,
"outboundTypeLoadBalancer": testAccKubernetesCluster_outboundTypeLoadBalancer,
"privateClusterOn": testAccKubernetesCluster_privateClusterOn,
"privateClusterOff": testAccKubernetesCluster_privateClusterOff,
"basicAvailabilitySet": testAccKubernetesCluster_basicAvailabilitySet,
"basicVMSS": testAccKubernetesCluster_basicVMSS,
"requiresImport": testAccKubernetesCluster_requiresImport,
"criticalAddonsTaint": testAccKubernetesCluster_criticalAddonsTaint,
"linuxProfile": testAccKubernetesCluster_linuxProfile,
"nodeLabels": testAccKubernetesCluster_nodeLabels,
"nodeResourceGroup": testAccKubernetesCluster_nodeResourceGroup,
"paidSku": testAccKubernetesCluster_paidSku,
"upgradeConfig": testAccKubernetesCluster_upgrade,
"tags": testAccKubernetesCluster_tags,
"windowsProfile": testAccKubernetesCluster_windowsProfile,
"outboundTypeLoadBalancer": testAccKubernetesCluster_outboundTypeLoadBalancer,
"privateClusterOn": testAccKubernetesCluster_privateClusterOn,
"privateClusterOff": testAccKubernetesCluster_privateClusterOff,
"privateClusterPrivateDNS": testAccKubernetesCluster_privateClusterOnWithPrivateDNSZone,
"privateClusterPrivateDNSSystem": testAccKubernetesCluster_privateClusterOnWithPrivateDNSZoneSystem,
}

func TestAccKubernetesCluster_basicAvailabilitySet(t *testing.T) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import (
"strings"
"time"

privateDnsValidate "github.com/terraform-providers/terraform-provider-azurerm/azurerm/internal/services/privatedns/validate"

"github.com/Azure/azure-sdk-for-go/services/containerservice/mgmt/2020-12-01/containerservice"
"github.com/hashicorp/terraform-plugin-sdk/helper/customdiff"
"github.com/hashicorp/terraform-plugin-sdk/helper/schema"
Expand Down Expand Up @@ -453,6 +455,19 @@ func resourceKubernetesCluster() *schema.Resource {
ConflictsWith: []string{"private_link_enabled"},
},

"private_dns_zone_id": {
favoretti marked this conversation as resolved.
Show resolved Hide resolved
Type: schema.TypeString,
Optional: true,
Computed: true, // a Private Cluster is `System` by default even if unspecified
ForceNew: true,
favoretti marked this conversation as resolved.
Show resolved Hide resolved
ValidateFunc: validation.Any(
privateDnsValidate.PrivateDnsZoneID,
validation.StringInSlice([]string{
"System",
}, false),
),
},

"role_based_access_control": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -810,6 +825,13 @@ func resourceKubernetesClusterCreate(d *schema.ResourceData, meta interface{}) e
}
}

if v, ok := d.GetOk("private_dns_zone_id"); ok {
if parameters.Identity == nil || (v.(string) != "System" && parameters.Identity.Type != containerservice.ResourceIdentityTypeUserAssigned) {
return fmt.Errorf("a user assigned identity must be used when using a custom private dns zone")
}
apiAccessProfile.PrivateDNSZone = utils.String(v.(string))
}

if v, ok := d.GetOk("disk_encryption_set_id"); ok && v.(string) != "" {
parameters.ManagedClusterProperties.DiskEncryptionSetID = utils.String(v.(string))
}
Expand Down Expand Up @@ -970,6 +992,9 @@ func resourceKubernetesClusterUpdate(d *schema.ResourceData, meta interface{}) e
AuthorizedIPRanges: utils.ExpandStringSlice(apiServerAuthorizedIPRangesRaw),
EnablePrivateCluster: &enablePrivateCluster,
}
if v, ok := d.GetOk("private_dns_zone_id"); ok {
existing.ManagedClusterProperties.APIServerAccessProfile.PrivateDNSZone = utils.String(v.(string))
}
}

if d.HasChange("auto_scaler_profile") {
Expand Down Expand Up @@ -1207,6 +1232,7 @@ func resourceKubernetesClusterRead(d *schema.ResourceData, meta interface{}) err

d.Set("private_link_enabled", accessProfile.EnablePrivateCluster)
d.Set("private_cluster_enabled", accessProfile.EnablePrivateCluster)
d.Set("private_dns_zone_id", accessProfile.PrivateDNSZone)
}

addonProfiles := flattenKubernetesAddOnProfiles(props.AddonProfiles)
Expand Down
46 changes: 45 additions & 1 deletion website/docs/r/kubernetes_cluster.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,51 @@ In addition, one of either `identity` or `service_principal` blocks must be spec

-> **NOTE:** Azure requires that a new, non-existent Resource Group is used, as otherwise the provisioning of the Kubernetes Service will fail.

* `private_cluster_enabled` Should this Kubernetes Cluster have its API server only exposed on internal IP addresses? This provides a Private IP Address for the Kubernetes API on the Virtual Network where the Kubernetes Cluster is located. Defaults to `false`. Changing this forces a new resource to be created.
* `private_cluster_enabled` - Should this Kubernetes Cluster have its API server only exposed on internal IP addresses? This provides a Private IP Address for the Kubernetes API on the Virtual Network where the Kubernetes Cluster is located. Defaults to `false`. Changing this forces a new resource to be created.

* `private_dns_zone_id` - (Optional) Either the ID of Private DNS Zone which should be delegated to this Cluster, or `System` to have AKS manage this.

-> **NOTE:** If you use BYO DNS Zone, AKS cluster should use identity type `UserAssigned` with `Private DNS Zone Contributor` role assigned to this identity for the zone. Next to it to prevent improper resource order destruction - cluster should depend on the role assignment, like in this example:

```
resource "azurerm_resource_group" "example" {
name = "example"
location = "eastus2"
}

resource "azurerm_private_dns_zone" "example" {
name = "privatelink.eastus2.azmk8s.io"
resource_group_name = azurerm_resource_group.example.name
}

resource "azurerm_user_assigned_identity" "example" {
name = "aks-example-identity"
resource_group_name = azurerm_resource_group.example.name
location = azurerm_resource_group.example.location
}

resource "azurerm_role_assignment" "example" {
scope = azurerm_private_dns_zone.example.id
role_definition_name = "Private DNS Zone Contributor"
principal_id = azurerm_user_assigned_identity.example.principal_id
}

resource "azurerm_kubernetes_cluster" "example" {
name = "aksexamplewithprivatednszone1"
location = azurerm_resource_group.example.location
resource_group_name = azurerm_resource_group.example.name
dns_prefix = "aksexamplednsprefix1"
private_cluster_enabled = true
private_dns_zone_id = azurerm_private_dns_zone.example.id

... rest of configuration omitted for brevity

depends_on = [
azurerm_role_assignment.example,
]
}

```

* `role_based_access_control` - (Optional) A `role_based_access_control` block. Changing this forces a new resource to be created.

Expand Down