From 1b606480f7a0b257e17d4b324687cf327460263d Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Fri, 12 Dec 2025 01:17:33 -0500 Subject: [PATCH 1/2] feat(aks): Allow converting kubeconfig using kubelogin Adds a new input variable, `kubelogin_mode`, to automatically convert the kubeconfig for AKS to the desired login mode (`azurecli`, `workloadidentity`, etc.) Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/main.tf | 45 +++++++++++++++++++-- terraform/cluster/azure-aks/test.tftest.hcl | 19 ++++++++- terraform/cluster/azure-aks/variables.tf | 20 +++++++++ 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/terraform/cluster/azure-aks/main.tf b/terraform/cluster/azure-aks/main.tf index 761a645dd..50c08b8e8 100644 --- a/terraform/cluster/azure-aks/main.tf +++ b/terraform/cluster/azure-aks/main.tf @@ -9,6 +9,10 @@ terraform { source = "hashicorp/azurerm" version = "~> 4.55.0" } + null = { + source = "hashicorp/null" + version = "~> 3.2" + } } } @@ -540,9 +544,44 @@ resource "azurerm_role_assignment" "node_pool_disk_encryption_set_reader" { principal_id = local.kubelet_object_id } -resource "local_file" "kube_config" { - content = azurerm_kubernetes_cluster.main.kube_config_raw - filename = local.kubeconfig_path +#----------------------------------------------------------------------------------------------------------------------- +# Kubeconfig +#----------------------------------------------------------------------------------------------------------------------- + +# Write kubeconfig as generated by Azure (uses kubelogin with devicecode by default) +# The kubeconfig already includes kubelogin in the exec block. +resource "local_sensitive_file" "kubeconfig" { + count = local.kubeconfig_path != "" ? 1 : 0 + + content = azurerm_kubernetes_cluster.main.kube_config_raw + filename = local.kubeconfig_path + file_permission = "0600" + + lifecycle { + ignore_changes = [content] + } +} + +# Convert kubeconfig to specified login mode if kubelogin_mode is set +# This runs after the kubeconfig file is created +resource "null_resource" "convert_kubeconfig" { + count = local.kubeconfig_path != "" && var.kubelogin_mode != "" ? 1 : 0 + + provisioner "local-exec" { + command = "kubelogin convert-kubeconfig -l ${var.kubelogin_mode} --kubeconfig ${local.kubeconfig_path}" + environment = { + KUBECONFIG = local.kubeconfig_path + } + } + + depends_on = [ + local_sensitive_file.kubeconfig + ] + + triggers = { + kubeconfig_content = azurerm_kubernetes_cluster.main.kube_config_raw + login_mode = var.kubelogin_mode + } } # Automatically assign "Azure Kubernetes Service RBAC Cluster Admin" to the diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index f1cb57470..798291858 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -170,6 +170,11 @@ run "minimal_configuration" { condition = azurerm_kubernetes_cluster.main.image_cleaner_interval_hours == 48 error_message = "Image Cleaner interval should default to 48 hours" } + + assert { + condition = length(null_resource.convert_kubeconfig) == 0 + error_message = "convert_kubeconfig resource should not be created when kubelogin_mode is empty (default)" + } } # Tests a full configuration with all optional variables explicitly set, @@ -221,6 +226,8 @@ run "full_configuration" { enable_volume_snapshots = true image_cleaner_enabled = true image_cleaner_interval_hours = 24 + context_path = "/tmp" + kubelogin_mode = "azurecli" } assert { @@ -397,6 +404,16 @@ run "full_configuration" { condition = azurerm_kubernetes_cluster.main.image_cleaner_interval_hours == 24 error_message = "Image Cleaner interval should match input value" } + + assert { + condition = length(null_resource.convert_kubeconfig) == 1 + error_message = "convert_kubeconfig resource should be created when kubelogin_mode is set" + } + + assert { + condition = null_resource.convert_kubeconfig[0].triggers.login_mode == "azurecli" + error_message = "convert_kubeconfig trigger should include login_mode set to azurecli" + } } # Tests the private cluster configuration, ensuring that enabling the private_cluster_enabled @@ -431,7 +448,7 @@ run "config_file_created" { } assert { - condition = length(local_file.kube_config) >= 1 + condition = length(local_sensitive_file.kubeconfig) >= 1 error_message = "Kubeconfig file should be generated when context path is provided" } } diff --git a/terraform/cluster/azure-aks/variables.tf b/terraform/cluster/azure-aks/variables.tf index 6f7a11403..667cc0fe9 100644 --- a/terraform/cluster/azure-aks/variables.tf +++ b/terraform/cluster/azure-aks/variables.tf @@ -340,3 +340,23 @@ variable "image_cleaner_interval_hours" { default = 48 } +variable "kubelogin_mode" { + description = "Login mode for kubelogin convert-kubeconfig. If set, converts the kubeconfig to use this login mode. Valid values: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity, azurepipelines. Leave empty to skip conversion and use the default devicecode mode from Azure." + type = string + default = "" + validation { + condition = var.kubelogin_mode == "" || contains([ + "devicecode", + "interactive", + "spn", + "ropc", + "msi", + "azurecli", + "azd", + "workloadidentity", + "azurepipelines" + ], var.kubelogin_mode) + error_message = "kubelogin_mode must be empty or one of: devicecode, interactive, spn, ropc, msi, azurecli, azd, workloadidentity, azurepipelines." + } +} + From e4344cc1e5534c289cf555c2c6331c226838e506 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Fri, 12 Dec 2025 01:17:54 -0500 Subject: [PATCH 2/2] terraform lock Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- .../cluster/azure-aks/.terraform.lock.hcl | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/terraform/cluster/azure-aks/.terraform.lock.hcl b/terraform/cluster/azure-aks/.terraform.lock.hcl index 84e7aa022..a00eb757a 100644 --- a/terraform/cluster/azure-aks/.terraform.lock.hcl +++ b/terraform/cluster/azure-aks/.terraform.lock.hcl @@ -50,6 +50,26 @@ provider "registry.terraform.io/hashicorp/local" { ] } +provider "registry.terraform.io/hashicorp/null" { + version = "3.2.4" + constraints = "~> 3.2" + hashes = [ + "h1:L5V05xwp/Gto1leRryuesxjMfgZwjb7oool4WS1UEFQ=", + "zh:59f6b52ab4ff35739647f9509ee6d93d7c032985d9f8c6237d1f8a59471bbbe2", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:795c897119ff082133150121d39ff26cb5f89a730a2c8c26f3a9c1abf81a9c43", + "zh:7b9c7b16f118fbc2b05a983817b8ce2f86df125857966ad356353baf4bff5c0a", + "zh:85e33ab43e0e1726e5f97a874b8e24820b6565ff8076523cc2922ba671492991", + "zh:9d32ac3619cfc93eb3c4f423492a8e0f79db05fec58e449dee9b2d5873d5f69f", + "zh:9e15c3c9dd8e0d1e3731841d44c34571b6c97f5b95e8296a45318b94e5287a6e", + "zh:b4c2ab35d1b7696c30b64bf2c0f3a62329107bd1a9121ce70683dec58af19615", + "zh:c43723e8cc65bcdf5e0c92581dcbbdcbdcf18b8d2037406a5f2033b1e22de442", + "zh:ceb5495d9c31bfb299d246ab333f08c7fb0d67a4f82681fbf47f2a21c3e11ab5", + "zh:e171026b3659305c558d9804062762d168f50ba02b88b231d20ec99578a6233f", + "zh:ed0fe2acdb61330b01841fa790be00ec6beaac91d41f311fb8254f74eb6a711f", + ] +} + provider "registry.terraform.io/hashicorp/random" { version = "3.7.2" hashes = [