diff --git a/azurerm/internal/services/containers/kubernetes_cluster_auth_resource_test.go b/azurerm/internal/services/containers/kubernetes_cluster_auth_resource_test.go index 607505d4ac8f..c6772c4f96b7 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_auth_resource_test.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_auth_resource_test.go @@ -9,19 +9,21 @@ import ( ) var kubernetesAuthTests = map[string]func(t *testing.T){ - "apiServerAuthorizedIPRanges": testAccKubernetesCluster_apiServerAuthorizedIPRanges, - "managedClusterIdentity": testAccKubernetesCluster_managedClusterIdentity, - "userAssignedIdentity": testAccKubernetesCluster_userAssignedIdentity, - "updateWithUserAssignedIdentity": testAccKubernetesCluster_updateWithUserAssignedIdentity, - "roleBasedAccessControl": testAccKubernetesCluster_roleBasedAccessControl, - "AAD": testAccKubernetesCluster_roleBasedAccessControlAAD, - "AADUpdateToManaged": testAccKubernetesCluster_roleBasedAccessControlAADUpdateToManaged, - "AADManaged": testAccKubernetesCluster_roleBasedAccessControlAADManaged, - "AADManagedChange": testAccKubernetesCluster_roleBasedAccessControlAADManagedChange, - "roleBasedAccessControlAzure": testAccKubernetesCluster_roleBasedAccessControlAzure, - "servicePrincipal": testAccKubernetesCluster_servicePrincipal, - "servicePrincipalToSystemAssigned": testAccKubernetesCluster_servicePrincipalToSystemAssignedIdentity, - "servicePrincipalToUserAssigned": testAccKubernetesCluster_servicePrincipalToUserAssignedIdentity, + "apiServerAuthorizedIPRanges": testAccKubernetesCluster_apiServerAuthorizedIPRanges, + "managedClusterIdentity": testAccKubernetesCluster_managedClusterIdentity, + "userAssignedIdentity": testAccKubernetesCluster_userAssignedIdentity, + "updateWithUserAssignedIdentity": testAccKubernetesCluster_updateWithUserAssignedIdentity, + "roleBasedAccessControl": testAccKubernetesCluster_roleBasedAccessControl, + "AAD": testAccKubernetesCluster_roleBasedAccessControlAAD, + "AADUpdateToManaged": testAccKubernetesCluster_roleBasedAccessControlAADUpdateToManaged, + "AADManaged": testAccKubernetesCluster_roleBasedAccessControlAADManaged, + "AADManagedLocalAccountDisabled": testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabled, + "AADManagedLocalAccountDisabledUpdate": testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabledUpdated, + "AADManagedChange": testAccKubernetesCluster_roleBasedAccessControlAADManagedChange, + "roleBasedAccessControlAzure": testAccKubernetesCluster_roleBasedAccessControlAzure, + "servicePrincipal": testAccKubernetesCluster_servicePrincipal, + "servicePrincipalToSystemAssigned": testAccKubernetesCluster_servicePrincipalToSystemAssignedIdentity, + "servicePrincipalToUserAssigned": testAccKubernetesCluster_servicePrincipalToUserAssignedIdentity, } func TestAccKubernetesCluster_apiServerAuthorizedIPRanges(t *testing.T) { @@ -310,6 +312,62 @@ func testAccKubernetesCluster_roleBasedAccessControlAADManaged(t *testing.T) { }) } +func TestAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabled(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabled(t) +} + +func testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabled(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + clientData := data.Client() + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.roleBasedAccessControlAADManagedConfigWithLocalAccountDisabled(data, clientData.TenantID), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("role_based_access_control.0.azure_active_directory.0.server_app_secret"), + }) +} + +func TestAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabledUpdated(t *testing.T) { + checkIfShouldRunTestsIndividually(t) + testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabledUpdated(t) +} + +func testAccKubernetesCluster_roleBasedAccessControlAADManagedWithLocalAccountDisabledUpdated(t *testing.T) { + data := acceptance.BuildTestData(t, "azurerm_kubernetes_cluster", "test") + r := KubernetesClusterResource{} + clientData := data.Client() + + data.ResourceTest(t, r, []acceptance.TestStep{ + { + Config: r.roleBasedAccessControlAADManagedConfig(data, clientData.TenantID), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("role_based_access_control.0.azure_active_directory.0.server_app_secret"), + { + Config: r.roleBasedAccessControlAADManagedConfigWithLocalAccountDisabled(data, clientData.TenantID), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("role_based_access_control.0.azure_active_directory.0.server_app_secret"), + { + Config: r.roleBasedAccessControlAADManagedConfig(data, clientData.TenantID), + Check: acceptance.ComposeTestCheckFunc( + check.That(data.ResourceName).ExistsInAzure(r), + ), + }, + data.ImportStep("role_based_access_control.0.azure_active_directory.0.server_app_secret"), + }) +} + func TestAccKubernetesCluster_roleBasedAccessControlAADManagedChange(t *testing.T) { checkIfShouldRunTestsIndividually(t) testAccKubernetesCluster_roleBasedAccessControlAADManagedChange(t) @@ -921,6 +979,55 @@ resource "azurerm_kubernetes_cluster" "test" { `, tenantId, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) } +func (KubernetesClusterResource) roleBasedAccessControlAADManagedConfigWithLocalAccountDisabled(data acceptance.TestData, tenantId string) string { + return fmt.Sprintf(` +variable "tenant_id" { + default = "%s" +} + +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" + local_account_disabled = true + + linux_profile { + admin_username = "acctestuser%d" + + ssh_key { + key_data = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQCqaZoyiz1qbdOQ8xEf6uEu1cCwYowo5FHtsBhqLoDnnp7KUTEBN+L2NxRIfQ781rxV6Iq5jSav6b2Q8z5KiseOlvKA/RF2wqU0UPYqQviQhLmW6THTpmrv/YkUCuzxDpsH7DUDhZcwySLKVVe0Qm3+5N2Ta6UYH3lsDf9R9wTP2K/+vAnflKebuypNlmocIvakFWoZda18FOmsOoIVXQ8HWFNCuw9ZCunMSN62QGamCe3dL5cXlkgHYv7ekJE15IA9aOJcM7e90oeTqo+7HTcWfdu0qQqPWY5ujyMw/llas8tsXY85LFqRnr3gJ02bAscjc477+X+j/gkpFoN1QEmt terraform@demo.tld" + } + } + + default_node_pool { + name = "default" + node_count = 1 + vm_size = "Standard_DS2_v2" + } + + identity { + type = "SystemAssigned" + } + + role_based_access_control { + enabled = true + + azure_active_directory { + tenant_id = var.tenant_id + managed = true + azure_rbac_enabled = false + } + } +} +`, tenantId, data.RandomInteger, data.Locations.Primary, data.RandomInteger, data.RandomInteger, data.RandomInteger) +} + func (KubernetesClusterResource) roleBasedAccessControlAADManagedConfigScale(data acceptance.TestData, tenantId string) string { return fmt.Sprintf(` variable "tenant_id" { diff --git a/azurerm/internal/services/containers/kubernetes_cluster_resource.go b/azurerm/internal/services/containers/kubernetes_cluster_resource.go index 14a7db46e67f..ab439c7661ac 100644 --- a/azurerm/internal/services/containers/kubernetes_cluster_resource.go +++ b/azurerm/internal/services/containers/kubernetes_cluster_resource.go @@ -330,6 +330,11 @@ func resourceKubernetesCluster() *pluginsdk.Resource { }, }, + "local_account_disabled": { + Type: pluginsdk.TypeBool, + Optional: true, + }, + "network_profile": { Type: pluginsdk.TypeList, Optional: true, @@ -918,6 +923,7 @@ func resourceKubernetesClusterCreate(d *pluginsdk.ResourceData, meta interface{} WindowsProfile: windowsProfile, NetworkProfile: networkProfile, NodeResourceGroup: utils.String(nodeResourceGroup), + DisableLocalAccounts: utils.Bool(d.Get("local_account_disabled").(bool)), }, Tags: tags.Expand(t), } @@ -1162,6 +1168,11 @@ func resourceKubernetesClusterUpdate(d *pluginsdk.ResourceData, meta interface{} existing.ManagedClusterProperties.LinuxProfile = linuxProfile } + if d.HasChange("local_account_disabled") { + updateCluster = true + existing.ManagedClusterProperties.DisableLocalAccounts = utils.Bool(d.Get("local_account_disabled").(bool)) + } + if d.HasChange("network_profile") { updateCluster = true @@ -1383,6 +1394,7 @@ func resourceKubernetesClusterRead(d *pluginsdk.ResourceData, meta interface{}) d.Set("kubernetes_version", props.KubernetesVersion) d.Set("node_resource_group", props.NodeResourceGroup) d.Set("enable_pod_security_policy", props.EnablePodSecurityPolicy) + d.Set("local_account_disabled", props.DisableLocalAccounts) upgradeChannel := "" if profile := props.AutoUpgradeProfile; profile != nil && profile.UpgradeChannel != containerservice.UpgradeChannelNone { @@ -1456,8 +1468,8 @@ func resourceKubernetesClusterRead(d *pluginsdk.ResourceData, meta interface{}) return fmt.Errorf("setting `windows_profile`: %+v", err) } - // adminProfile is only available for RBAC enabled clusters with AAD - if props.AadProfile != nil { + // adminProfile is only available for RBAC enabled clusters with AAD and local account is not disabled + if props.AadProfile != nil && (props.DisableLocalAccounts == nil || !*props.DisableLocalAccounts) { adminProfile, err := client.GetAccessProfile(ctx, id.ResourceGroup, id.ManagedClusterName, "clusterAdmin") if err != nil { return fmt.Errorf("retrieving Admin Access Profile for Managed Kubernetes Cluster %q (Resource Group %q): %+v", id.ManagedClusterName, id.ResourceGroup, err) diff --git a/website/docs/r/kubernetes_cluster.html.markdown b/website/docs/r/kubernetes_cluster.html.markdown index aa77a872b646..4b855b49cfd1 100644 --- a/website/docs/r/kubernetes_cluster.html.markdown +++ b/website/docs/r/kubernetes_cluster.html.markdown @@ -319,6 +319,8 @@ A `default_node_pool` block supports the following: * `kubelet_disk_type` - (Optional) The type of disk used by kubelet. At this time the only possible value is `OS`. +* `local_account_disabled` - (Optional) Is local account disabled for AAD integrated kubernetes cluster? + * `max_pods` - (Optional) The maximum number of pods that can run on each agent. Changing this forces a new resource to be created. * `node_public_ip_prefix_id` - (Optional) Resource ID for the Public IP Addresses Prefix for the nodes in this Node Pool. `enable_node_public_ip` should be `true`. Changing this forces a new resource to be created.