diff --git a/README.md b/README.md index 3eb0c07..fc11a2f 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ The following resources are used by this module: - [azurerm_management_lock.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/management_lock) (resource) - [azurerm_monitor_diagnostic_setting.aks](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/monitor_diagnostic_setting) (resource) - [azurerm_role_assignment.acr](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) +- [azurerm_role_assignment.dns_zone_contributor](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) - [azurerm_role_assignment.network_contributor_on_resource_group](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/role_assignment) (resource) - [azurerm_user_assigned_identity.aks](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/user_assigned_identity) (resource) - [modtm_telemetry.telemetry](https://registry.terraform.io/providers/Azure/modtm/latest/docs/resources/telemetry) (resource) @@ -299,6 +300,22 @@ Type: `string` Default: `"AzureLinux"` +### [private\_dns\_zone\_id](#input\_private\_dns\_zone\_id) + +Description: (Optional) Either the ID of Private DNS Zone which should be delegated to this Cluster. + +Type: `string` + +Default: `null` + +### [private\_dns\_zone\_id\_enabled](#input\_private\_dns\_zone\_id\_enabled) + +Description: (Optional) Enable private DNS zone integration for the AKS cluster. + +Type: `bool` + +Default: `false` + ### [rbac\_aad\_admin\_group\_object\_ids](#input\_rbac\_aad\_admin\_group\_object\_ids) Description: Object ID of groups with admin access. diff --git a/examples/default/README.md b/examples/default/README.md index 5ea8a3b..f0deaf7 100644 --- a/examples/default/README.md +++ b/examples/default/README.md @@ -58,12 +58,14 @@ resource "azurerm_resource_group" "this" { # Leaving location as `null` will cause the module to use the resource group location # with a data source. module "test" { - source = "../../" - kubernetes_version = "1.30" - enable_telemetry = var.enable_telemetry # see variables.tf - name = module.naming.kubernetes_cluster.name_unique - resource_group_name = azurerm_resource_group.this.name - location = azurerm_resource_group.this.location + source = "../../" + kubernetes_version = "1.30" + enable_telemetry = var.enable_telemetry # see variables.tf + name = module.naming.kubernetes_cluster.name_unique + resource_group_name = azurerm_resource_group.this.name + location = azurerm_resource_group.this.location + private_dns_zone_id = azurerm_private_dns_zone.mydomain.id + private_dns_zone_id_enabled = true network = { name = module.avm_res_network_virtualnetwork.name resource_group_name = azurerm_resource_group.this.name @@ -82,6 +84,11 @@ resource "azurerm_private_dns_zone" "this" { resource_group_name = azurerm_resource_group.this.name } +resource "azurerm_private_dns_zone" "mydomain" { + name = "privatelink.eastus2.azmk8s.io" + resource_group_name = azurerm_resource_group.this.name +} + module "avm_res_network_virtualnetwork" { source = "Azure/avm-res-network-virtualnetwork/azurerm" version = "0.2.3" @@ -118,6 +125,7 @@ The following requirements are needed by this module: The following resources are used by this module: +- [azurerm_private_dns_zone.mydomain](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) (resource) - [azurerm_private_dns_zone.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/private_dns_zone) (resource) - [azurerm_resource_group.this](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) (resource) - [random_integer.region_index](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/integer) (resource) diff --git a/examples/default/main.tf b/examples/default/main.tf index a3a873f..32af2b1 100644 --- a/examples/default/main.tf +++ b/examples/default/main.tf @@ -52,12 +52,14 @@ resource "azurerm_resource_group" "this" { # Leaving location as `null` will cause the module to use the resource group location # with a data source. module "test" { - source = "../../" - kubernetes_version = "1.30" - enable_telemetry = var.enable_telemetry # see variables.tf - name = module.naming.kubernetes_cluster.name_unique - resource_group_name = azurerm_resource_group.this.name - location = azurerm_resource_group.this.location + source = "../../" + kubernetes_version = "1.30" + enable_telemetry = var.enable_telemetry # see variables.tf + name = module.naming.kubernetes_cluster.name_unique + resource_group_name = azurerm_resource_group.this.name + location = azurerm_resource_group.this.location + private_dns_zone_id = azurerm_private_dns_zone.mydomain.id + private_dns_zone_id_enabled = true network = { name = module.avm_res_network_virtualnetwork.name resource_group_name = azurerm_resource_group.this.name @@ -76,6 +78,11 @@ resource "azurerm_private_dns_zone" "this" { resource_group_name = azurerm_resource_group.this.name } +resource "azurerm_private_dns_zone" "mydomain" { + name = "privatelink.eastus2.azmk8s.io" + resource_group_name = azurerm_resource_group.this.name +} + module "avm_res_network_virtualnetwork" { source = "Azure/avm-res-network-virtualnetwork/azurerm" version = "0.2.3" diff --git a/locals.tf b/locals.tf index 2b1c99c..da596c8 100644 --- a/locals.tf +++ b/locals.tf @@ -1,4 +1,12 @@ - +locals { + private_dns_zone_name = try(reverse(split("/", var.private_dns_zone_id))[0], null) + valid_private_dns_zone_regexs = [ + "private\\.[a-z0-9]+\\.azmk8s\\.io", + "privatelink\\.[a-z0-9]+\\.azmk8s\\.io", + "[a-zA-Z0-9\\-]{1,32}\\.private\\.[a-z]+\\.azmk8s\\.io", + "[a-zA-Z0-9\\-]{1,32}\\.privatelink\\.[a-z]+\\.azmk8s\\.io", + ] +} locals { locations_cached_or_live = data.local_file.locations.content diff --git a/main.tf b/main.tf index 9314318..a9785d3 100644 --- a/main.tf +++ b/main.tf @@ -38,7 +38,7 @@ data "azurerm_resource_group" "this" { } data "azurerm_user_assigned_identity" "cluster_identity" { - name = split("/", one(azurerm_kubernetes_cluster.this.identity[0].identity_ids))[8] + name = split("/", one(local.managed_identities.user_assigned.this.user_assigned_resource_ids))[8] resource_group_name = data.azurerm_resource_group.this.name } @@ -48,6 +48,14 @@ resource "azurerm_role_assignment" "network_contributor_on_resource_group" { role_definition_name = "Network Contributor" } +resource "azurerm_role_assignment" "dns_zone_contributor" { + count = var.private_dns_zone_id_enabled ? 1 : 0 + + principal_id = data.azurerm_user_assigned_identity.cluster_identity.principal_id + scope = var.private_dns_zone_id + role_definition_name = "Private DNS Zone Contributor" +} + resource "azurerm_kubernetes_cluster" "this" { location = var.location name = "aks-${var.name}" @@ -60,6 +68,7 @@ resource "azurerm_kubernetes_cluster" "this" { node_os_channel_upgrade = "NodeImage" oidc_issuer_enabled = true private_cluster_enabled = true + private_dns_zone_id = var.private_dns_zone_id role_based_access_control_enabled = true sku_tier = "Standard" tags = var.tags @@ -135,6 +144,14 @@ resource "azurerm_kubernetes_cluster" "this" { condition = var.orchestrator_version == null || try(can(regex("^[0-9]+\\.[0-9]+$", var.orchestrator_version)), false) error_message = "Ensure that orchestrator_version does not specify a patch version" } + precondition { + condition = var.private_dns_zone_id == null ? true : (anytrue([for r in local.valid_private_dns_zone_regexs : try(regex(r, local.private_dns_zone_name) == local.private_dns_zone_name, false)])) + error_message = "According to the [document](https://learn.microsoft.com/en-us/azure/aks/private-clusters?tabs=azure-portal#configure-a-private-dns-zone), the private DNS zone must be in one of the following format: `privatelink..azmk8s.io`, `.privatelink..azmk8s.io`, `private..azmk8s.io`, `.private..azmk8s.io`" + } + precondition { + condition = var.private_dns_zone_id != null ? var.private_dns_zone_id_enabled == true : var.private_dns_zone_id_enabled == false + error_message = "private_dns_zone_id must be set if private_dns_zone_id_enabled is true" + } } } @@ -285,4 +302,4 @@ data "local_file" "compute_provider" { data "local_file" "locations" { filename = "${path.module}/data/locations.json" -} \ No newline at end of file +} diff --git a/variables.tf b/variables.tf index b83ab55..5cb5091 100644 --- a/variables.tf +++ b/variables.tf @@ -207,6 +207,24 @@ variable "os_sku" { } } +variable "private_dns_zone_id" { + type = string + default = null + description = "(Optional) Either the ID of Private DNS Zone which should be delegated to this Cluster." + + validation { + condition = var.private_dns_zone_id == null || can(regex("^(/subscriptions/[^/]+/resourceGroups/[^/]+/providers/Microsoft.Network/privateDnsZones/[^/]+)$", var.private_dns_zone_id)) + error_message = "private_dns_zone_id must be a valid Private DNS Zone ID" + } +} + +variable "private_dns_zone_id_enabled" { + type = bool + default = false + description = "(Optional) Enable private DNS zone integration for the AKS cluster." + nullable = false +} + variable "rbac_aad_admin_group_object_ids" { type = list(string) default = null