From 5228e483b45e15d5adfc7464c43c9ad9e2a40883 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 10:10:35 -0500 Subject: [PATCH 1/7] feat(aks): Multi-AZ and user NAT routing * Enables multi-AZ for the AKS cluster node pools. * Routes outbound traffic via the custom NAT gateway resource * Adds network profile settings for full cilium support Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/main.tf | 13 +- terraform/cluster/azure-aks/test.tftest.hcl | 119 +++++++++++++++--- terraform/cluster/azure-aks/variables.tf | 12 +- terraform/network/aws-vpc/.terraform.lock.hcl | 1 + terraform/network/aws-vpc/README.md | 52 ++++---- terraform/network/azure-vnet/README.md | 6 +- terraform/network/azure-vnet/main.tf | 17 ++- terraform/network/azure-vnet/test.tftest.hcl | 60 +++++++++ 8 files changed, 226 insertions(+), 54 deletions(-) diff --git a/terraform/cluster/azure-aks/main.tf b/terraform/cluster/azure-aks/main.tf index cc729630a..ea9a33b65 100644 --- a/terraform/cluster/azure-aks/main.tf +++ b/terraform/cluster/azure-aks/main.tf @@ -247,6 +247,7 @@ resource "azurerm_kubernetes_cluster" "main" { vnet_subnet_id = coalesce(var.vnet_subnet_id, try(data.azurerm_subnet.private[0].id, null)) orchestrator_version = var.kubernetes_version only_critical_addons_enabled = var.default_node_pool.only_critical_addons_enabled + zones = var.default_node_pool.availability_zones # checkov:skip=CKV_AZURE_226: we are using the managed disk type to reduce costs os_disk_type = var.default_node_pool.os_disk_type @@ -275,10 +276,13 @@ resource "azurerm_kubernetes_cluster" "main" { } network_profile { - network_plugin = "azure" - network_policy = "cilium" - service_cidr = var.service_cidr - dns_service_ip = var.dns_service_ip + network_plugin = "azure" + network_plugin_mode = "overlay" + network_policy = "cilium" + network_data_plane = "cilium" + outbound_type = var.outbound_type + service_cidr = var.service_cidr + dns_service_ip = var.dns_service_ip } oms_agent { @@ -313,6 +317,7 @@ resource "azurerm_kubernetes_cluster_node_pool" "autoscaled" { auto_scaling_enabled = true min_count = var.autoscaled_node_pool.min_count max_count = var.autoscaled_node_pool.max_count + zones = var.autoscaled_node_pool.availability_zones vnet_subnet_id = coalesce( var.vnet_subnet_id, try(data.azurerm_subnet.private[length(local.private_subnets) - 1].id, null) diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index 3a3a6885e..f7b7cdb22 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -22,8 +22,18 @@ mock_provider "azurerm" { id = "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Network/virtualNetworks/vnet-test/subnets/subnet-test" } } + mock_resource "azurerm_kubernetes_cluster" { + defaults = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } + } } + # Verifies that the module creates an AKS cluster with minimal configuration, # ensuring that all default values are correctly applied and only required variables are set. run "minimal_configuration" { @@ -35,6 +45,17 @@ run "minimal_configuration" { kubernetes_version = "1.32" } + override_resource { + target = azurerm_kubernetes_cluster.main + values = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } + } + assert { condition = azurerm_kubernetes_cluster.main.name == "windsor-aks-test" error_message = "Cluster name should default to 'windsor-aks-test' when cluster_name is omitted" @@ -84,6 +105,21 @@ run "minimal_configuration" { condition = azurerm_kubernetes_cluster.main.identity[0].type == "SystemAssigned" error_message = "Cluster should use system-assigned identity by default" } + + assert { + condition = azurerm_kubernetes_cluster.main.network_profile[0].outbound_type == "userAssignedNATGateway" + error_message = "Default outbound type should be 'userAssignedNATGateway'" + } + + assert { + condition = azurerm_kubernetes_cluster.main.network_profile[0].network_plugin_mode == "overlay" + error_message = "Network plugin mode should be 'overlay'" + } + + assert { + condition = azurerm_kubernetes_cluster.main.network_profile[0].network_data_plane == "cilium" + error_message = "Network data plane should be 'cilium'" + } } # Tests a full configuration with all optional variables explicitly set, @@ -97,13 +133,6 @@ run "full_configuration" { cluster_name = "test-cluster" resource_group_name = "test-rg" kubernetes_version = "1.32" - user_assigned_identity_ids = [ - "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1", - "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-2" - ] - kubelet_client_id = "test-client-id" - kubelet_object_id = "test-object-id" - kubelet_user_assigned_identity_id = "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1" default_node_pool = { name = "system" vm_size = "Standard_D2s_v3" @@ -114,6 +143,7 @@ run "full_configuration" { max_count = 3 node_count = 1 only_critical_addons_enabled = false + availability_zones = ["1", "2", "3"] } autoscaled_node_pool = { enabled = true @@ -125,11 +155,24 @@ run "full_configuration" { host_encryption_enabled = true min_count = 1 max_count = 3 + availability_zones = ["1", "2"] } role_based_access_control_enabled = true private_cluster_enabled = false azure_policy_enabled = true local_account_disabled = false + outbound_type = "loadBalancer" + } + + override_resource { + target = azurerm_kubernetes_cluster.main + values = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } } assert { @@ -204,32 +247,37 @@ run "full_configuration" { assert { condition = azurerm_kubernetes_cluster.main.local_account_disabled == false - error_message = "Local accounts should be enabled" + error_message = "Local accounts should be disabled when explicitly set to false" + } + + assert { + condition = azurerm_kubernetes_cluster.main.identity[0].type == "SystemAssigned" + error_message = "Cluster should use system-assigned identity by default" } assert { - condition = azurerm_kubernetes_cluster.main.identity[0].type == "UserAssigned" - error_message = "Cluster should use user-assigned identity when IDs are provided" + condition = length(azurerm_kubernetes_cluster.main.default_node_pool[0].zones) == 3 && contains(azurerm_kubernetes_cluster.main.default_node_pool[0].zones, "1") && contains(azurerm_kubernetes_cluster.main.default_node_pool[0].zones, "2") && contains(azurerm_kubernetes_cluster.main.default_node_pool[0].zones, "3") + error_message = "Default node pool zones should match input value" } assert { - condition = length(azurerm_kubernetes_cluster.main.identity[0].identity_ids) == 2 - error_message = "Cluster should have 2 user-assigned identity IDs" + condition = length(azurerm_kubernetes_cluster_node_pool.autoscaled[0].zones) == 2 && contains(azurerm_kubernetes_cluster_node_pool.autoscaled[0].zones, "1") && contains(azurerm_kubernetes_cluster_node_pool.autoscaled[0].zones, "2") + error_message = "Autoscaled node pool zones should match input value" } assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].client_id == "test-client-id" - error_message = "Kubelet client ID should match input" + condition = azurerm_kubernetes_cluster.main.network_profile[0].outbound_type == "loadBalancer" + error_message = "Outbound type should match input value" } assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].object_id == "test-object-id" - error_message = "Kubelet object ID should match input" + condition = azurerm_kubernetes_cluster.main.network_profile[0].network_plugin_mode == "overlay" + error_message = "Network plugin mode should be 'overlay'" } assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].user_assigned_identity_id == "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1" - error_message = "Kubelet user-assigned identity ID should match input" + condition = azurerm_kubernetes_cluster.main.network_profile[0].network_data_plane == "cilium" + error_message = "Network data plane should be 'cilium'" } } @@ -246,6 +294,17 @@ run "private_cluster" { kubernetes_version = "1.32" } + override_resource { + target = azurerm_kubernetes_cluster.main + values = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } + } + assert { condition = azurerm_kubernetes_cluster.main.private_cluster_enabled == true error_message = "Private cluster should be enabled" @@ -264,6 +323,17 @@ run "config_file_created" { context_path = "/tmp" } + override_resource { + target = azurerm_kubernetes_cluster.main + values = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } + } + assert { condition = length(local_file.kube_config) >= 1 error_message = "Kubeconfig file should be generated when context path is provided" @@ -279,6 +349,17 @@ run "network_configuration" { dns_service_ip = "10.0.0.10" } + override_resource { + target = azurerm_kubernetes_cluster.main + values = { + kubelet_identity = [{ + client_id = "44444444-4444-4444-4444-444444444444" + object_id = "55555555-5555-5555-5555-555555555555" + user_assigned_identity_id = "" + }] + } + } + assert { condition = azurerm_kubernetes_cluster.main.network_profile[0].service_cidr == "10.0.0.0/16" error_message = "Service CIDR should match input value" @@ -294,9 +375,11 @@ run "multiple_invalid_inputs" { command = plan expect_failures = [ var.kubernetes_version, + var.outbound_type, ] variables { context_id = "test" kubernetes_version = "v1.32" + outbound_type = "invalid" } } diff --git a/terraform/cluster/azure-aks/variables.tf b/terraform/cluster/azure-aks/variables.tf index 44e0a5947..b9ddb69a6 100644 --- a/terraform/cluster/azure-aks/variables.tf +++ b/terraform/cluster/azure-aks/variables.tf @@ -73,6 +73,7 @@ variable "default_node_pool" { max_count = number node_count = number only_critical_addons_enabled = bool + availability_zones = optional(list(string)) }) default = { name = "system" @@ -99,6 +100,7 @@ variable "autoscaled_node_pool" { host_encryption_enabled = bool min_count = number max_count = number + availability_zones = optional(list(string)) }) default = { enabled = true @@ -241,10 +243,14 @@ variable "endpoint_private_access" { default = false } -variable "kubelet_client_id" { - description = "Client ID of the user-assigned identity to use for the kubelet. If not provided, the cluster will use the system-assigned identity." +variable "outbound_type" { + description = "The outbound (egress) routing method which should be used for this Kubernetes Cluster." type = string - default = null + default = "userAssignedNATGateway" + validation { + condition = contains(["loadBalancer", "userDefinedRouting", "managedNATGateway", "userAssignedNATGateway"], var.outbound_type) + error_message = "The outbound_type must be one of: loadBalancer, userDefinedRouting, managedNATGateway, userAssignedNATGateway." + } } variable "kubelet_object_id" { diff --git a/terraform/network/aws-vpc/.terraform.lock.hcl b/terraform/network/aws-vpc/.terraform.lock.hcl index aa48e2247..5c0fff4e8 100644 --- a/terraform/network/aws-vpc/.terraform.lock.hcl +++ b/terraform/network/aws-vpc/.terraform.lock.hcl @@ -13,6 +13,7 @@ provider "registry.terraform.io/hashicorp/aws" { "h1:PQ3jzG6VNrfS35adtrBeLnVTnJef3f2t5SUV7XNikgo=", "h1:QAcpv9yoqEtVaBVyQ3hHsTc558AchV5/8lfAGoqmUkA=", "h1:QJEljz77aB459tng0v+5xIdV6mkmCM4RZO6ztk3pOEA=", + "h1:QJr1C4scuvEslohwPKrBPEjhQRyMT26HzhxZlLjl3cw=", "h1:RB3r7K1PgJ6S3J0l4u5/nB7G/inM2goPWY+QHesxuGo=", "h1:UT4pxGbPuANnxyCeDn5/Ybr476EkyxcsYsU+q0iYt/Q=", "h1:Uv/PPkYgnjKcsesOVWiTHaY/1R5/OgH1UYnXvtu0K58=", diff --git a/terraform/network/aws-vpc/README.md b/terraform/network/aws-vpc/README.md index 09a54fdaf..6a0f40bce 100644 --- a/terraform/network/aws-vpc/README.md +++ b/terraform/network/aws-vpc/README.md @@ -4,14 +4,14 @@ | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >=1.8 | -| [aws](#requirement\_aws) | 6.18.0 | +| [aws](#requirement\_aws) | 6.25.0 | | [random](#requirement\_random) | 3.7.2 | ## Providers | Name | Version | |------|---------| -| [aws](#provider\_aws) | 6.18.0 | +| [aws](#provider\_aws) | 6.25.0 | | [null](#provider\_null) | 3.2.4 | | [random](#provider\_random) | 3.7.2 | @@ -23,32 +23,32 @@ No modules. | Name | Type | |------|------| -| [aws_cloudwatch_log_group.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/cloudwatch_log_group) | resource | -| [aws_default_security_group.default](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/default_security_group) | resource | -| [aws_eip.nat](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/eip) | resource | -| [aws_flow_log.main](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/flow_log) | resource | -| [aws_iam_role.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/iam_role) | resource | -| [aws_iam_role_policy.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/iam_role_policy) | resource | -| [aws_internet_gateway.main](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/internet_gateway) | resource | -| [aws_kms_alias.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/kms_alias) | resource | -| [aws_kms_key.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/kms_key) | resource | -| [aws_nat_gateway.main](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/nat_gateway) | resource | -| [aws_route53_zone.main](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route53_zone) | resource | -| [aws_route_table.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table) | resource | -| [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table) | resource | -| [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table) | resource | -| [aws_route_table_association.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table_association) | resource | -| [aws_route_table_association.private](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table_association) | resource | -| [aws_route_table_association.public](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/route_table_association) | resource | -| [aws_subnet.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/subnet) | resource | -| [aws_subnet.private](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/subnet) | resource | -| [aws_subnet.public](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/subnet) | resource | -| [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/resources/vpc) | resource | +| [aws_cloudwatch_log_group.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/cloudwatch_log_group) | resource | +| [aws_default_security_group.default](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/default_security_group) | resource | +| [aws_eip.nat](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/eip) | resource | +| [aws_flow_log.main](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/flow_log) | resource | +| [aws_iam_role.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/iam_role) | resource | +| [aws_iam_role_policy.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/iam_role_policy) | resource | +| [aws_internet_gateway.main](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/internet_gateway) | resource | +| [aws_kms_alias.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/kms_alias) | resource | +| [aws_kms_key.vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/kms_key) | resource | +| [aws_nat_gateway.main](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/nat_gateway) | resource | +| [aws_route53_zone.main](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route53_zone) | resource | +| [aws_route_table.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table) | resource | +| [aws_route_table.private](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table) | resource | +| [aws_route_table.public](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table) | resource | +| [aws_route_table_association.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table_association) | resource | +| [aws_route_table_association.private](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table_association) | resource | +| [aws_route_table_association.public](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/route_table_association) | resource | +| [aws_subnet.isolated](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/subnet) | resource | +| [aws_subnet.private](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/subnet) | resource | +| [aws_subnet.public](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/subnet) | resource | +| [aws_vpc.main](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/resources/vpc) | resource | | [null_resource.delete_vpc_flow_logs](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource | | [random_string.log_group_suffix](https://registry.terraform.io/providers/hashicorp/random/3.7.2/docs/resources/string) | resource | -| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/data-sources/availability_zones) | data source | -| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/data-sources/caller_identity) | data source | -| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/6.18.0/docs/data-sources/region) | data source | +| [aws_availability_zones.available](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/data-sources/availability_zones) | data source | +| [aws_caller_identity.current](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/data-sources/caller_identity) | data source | +| [aws_region.current](https://registry.terraform.io/providers/hashicorp/aws/6.25.0/docs/data-sources/region) | data source | ## Inputs diff --git a/terraform/network/azure-vnet/README.md b/terraform/network/azure-vnet/README.md index 49910754b..0be772f1d 100644 --- a/terraform/network/azure-vnet/README.md +++ b/terraform/network/azure-vnet/README.md @@ -4,13 +4,13 @@ | Name | Version | |------|---------| | [terraform](#requirement\_terraform) | >=1.8 | -| [azurerm](#requirement\_azurerm) | ~> 4.50.0 | +| [azurerm](#requirement\_azurerm) | ~> 4.55.0 | ## Providers | Name | Version | |------|---------| -| [azurerm](#provider\_azurerm) | 4.50.0 | +| [azurerm](#provider\_azurerm) | 4.55.0 | ## Modules @@ -24,10 +24,12 @@ No modules. | [azurerm_nat_gateway_public_ip_association.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/nat_gateway_public_ip_association) | resource | | [azurerm_public_ip.nat](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/public_ip) | resource | | [azurerm_resource_group.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/resource_group) | resource | +| [azurerm_route_table.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/route_table) | resource | | [azurerm_subnet.isolated](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | | [azurerm_subnet.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | | [azurerm_subnet.public](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet) | resource | | [azurerm_subnet_nat_gateway_association.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_nat_gateway_association) | resource | +| [azurerm_subnet_route_table_association.private](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/subnet_route_table_association) | resource | | [azurerm_virtual_network.main](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/virtual_network) | resource | ## Inputs diff --git a/terraform/network/azure-vnet/main.tf b/terraform/network/azure-vnet/main.tf index 8fee9e21a..664c7236a 100644 --- a/terraform/network/azure-vnet/main.tf +++ b/terraform/network/azure-vnet/main.tf @@ -125,7 +125,22 @@ resource "azurerm_nat_gateway_public_ip_association" "main" { public_ip_address_id = azurerm_public_ip.nat[count.index].id } -# Associate NAT Gateway with private subnet +resource "azurerm_route_table" "private" { + count = var.vnet_zones + name = "${var.name}-private-${count.index + 1}-${var.context_id}" + location = azurerm_resource_group.main.location + resource_group_name = azurerm_resource_group.main.name + tags = merge({ + Name = "${var.name}-private-${count.index + 1}-${var.context_id}" + }, local.tags) +} + +resource "azurerm_subnet_route_table_association" "private" { + count = var.vnet_zones + subnet_id = azurerm_subnet.private[count.index].id + route_table_id = azurerm_route_table.private[count.index].id +} + resource "azurerm_subnet_nat_gateway_association" "private" { count = var.enable_nat_gateway ? var.vnet_zones : 0 subnet_id = azurerm_subnet.private[count.index].id diff --git a/terraform/network/azure-vnet/test.tftest.hcl b/terraform/network/azure-vnet/test.tftest.hcl index 9963e5898..75c5e12ed 100644 --- a/terraform/network/azure-vnet/test.tftest.hcl +++ b/terraform/network/azure-vnet/test.tftest.hcl @@ -44,6 +44,21 @@ run "minimal_configuration" { condition = length(azurerm_nat_gateway.main) == 1 error_message = "One NAT Gateway should be created by default" } + + assert { + condition = length(azurerm_route_table.private) == 1 + error_message = "One route table should be created for private subnets by default" + } + + assert { + condition = length(azurerm_subnet_route_table_association.private) == 1 + error_message = "One route table association should be created for private subnets by default" + } + + assert { + condition = azurerm_route_table.private[0].name == "windsor-vnet-private-1-test" + error_message = "Route table name should follow naming convention" + } } # Tests a full configuration with all optional variables explicitly set. @@ -100,6 +115,26 @@ run "full_configuration" { condition = length(azurerm_nat_gateway.main) == 2 error_message = "Two NAT Gateways should be created" } + + assert { + condition = length(azurerm_route_table.private) == 2 + error_message = "Two route tables should be created for private subnets" + } + + assert { + condition = length(azurerm_subnet_route_table_association.private) == 2 + error_message = "Two route table associations should be created for private subnets" + } + + assert { + condition = azurerm_route_table.private[0].name == "custom-private-1-test" + error_message = "First route table name should follow naming convention" + } + + assert { + condition = azurerm_route_table.private[1].name == "custom-private-2-test" + error_message = "Second route table name should follow naming convention" + } } # Tests NAT Gateway configuration @@ -191,6 +226,31 @@ run "automatic_subnet_creation" { condition = azurerm_subnet.public[2].address_prefixes[0] == "10.0.53.0/24" error_message = "Third public subnet should be 10.0.53.0/24" } + + assert { + condition = length(azurerm_route_table.private) == 3 + error_message = "Three route tables should be created for private subnets when vnet_zones is 3" + } + + assert { + condition = length(azurerm_subnet_route_table_association.private) == 3 + error_message = "Three route table associations should be created for private subnets when vnet_zones is 3" + } + + assert { + condition = azurerm_route_table.private[0].name == "test-network-private-1-test" + error_message = "First route table name should follow naming convention" + } + + assert { + condition = azurerm_route_table.private[1].name == "test-network-private-2-test" + error_message = "Second route table name should follow naming convention" + } + + assert { + condition = azurerm_route_table.private[2].name == "test-network-private-3-test" + error_message = "Third route table name should follow naming convention" + } } # Tests validation rules for required variables From 4b38f677e2ac26cda7a9012e09fae24a63c44ff6 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:12:39 -0500 Subject: [PATCH 2/7] feat(aks): Leverage OIDC roles for kubelet and workloads * Enable oidc issuer and workload identity * Use system-assigned managed identities * Add required disk manager role (breaks cluster otherwise) Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/main.tf | 81 ++++++++++++++++----- terraform/cluster/azure-aks/test.tftest.hcl | 41 +++++------ terraform/cluster/azure-aks/variables.tf | 28 ++----- 3 files changed, 89 insertions(+), 61 deletions(-) diff --git a/terraform/cluster/azure-aks/main.tf b/terraform/cluster/azure-aks/main.tf index cc729630a..e23bdb700 100644 --- a/terraform/cluster/azure-aks/main.tf +++ b/terraform/cluster/azure-aks/main.tf @@ -55,9 +55,16 @@ data "azurerm_subnet" "private" { #----------------------------------------------------------------------------------------------------------------------- locals { - kubeconfig_path = "${var.context_path}/.kube/config" - rg_name = var.resource_group_name == null ? "${var.name}-${var.context_id}" : var.resource_group_name - cluster_name = var.cluster_name == null ? "${var.name}-${var.context_id}" : var.cluster_name + kubeconfig_path = "${var.context_path}/.kube/config" + rg_name = var.resource_group_name == null ? "${var.name}-${var.context_id}" : var.resource_group_name + cluster_name = var.cluster_name == null ? "${var.name}-${var.context_id}" : var.cluster_name + node_resource_group_name = split("/", azurerm_kubernetes_cluster.main.node_resource_group_id)[4] + node_pool_names = concat( + [var.default_node_pool.name], + var.autoscaled_node_pool.enabled ? [var.autoscaled_node_pool.name] : [] + ) + # Safely access kubelet identity (may not be available during plan in tests) + kubelet_object_id = try(azurerm_kubernetes_cluster.main.kubelet_identity[0].object_id, "00000000-0000-0000-0000-000000000000") tags = merge({ WindsorContextID = var.context_id }, var.tags) @@ -274,6 +281,9 @@ resource "azurerm_kubernetes_cluster" "main" { vertical_pod_autoscaler_enabled = var.workload_autoscaler_profile.vertical_pod_autoscaler_enabled } + oidc_issuer_enabled = var.oidc_issuer_enabled + workload_identity_enabled = var.workload_identity_enabled + network_profile { network_plugin = "azure" network_policy = "cilium" @@ -281,22 +291,11 @@ resource "azurerm_kubernetes_cluster" "main" { dns_service_ip = var.dns_service_ip } - oms_agent { - log_analytics_workspace_id = azurerm_log_analytics_workspace.aks_logs.id - } - + # Use system-assigned managed identity (Microsoft default and best practice) + # AKS automatically creates Contributor role on node RG for control plane + # AKS automatically creates Virtual Machine Contributor role on node RG for kubelet identity { - type = length(var.user_assigned_identity_ids) > 0 ? "UserAssigned" : "SystemAssigned" - identity_ids = var.user_assigned_identity_ids - } - - dynamic "kubelet_identity" { - for_each = var.kubelet_user_assigned_identity_id != null ? [1] : [] - content { - client_id = var.kubelet_client_id - object_id = var.kubelet_object_id - user_assigned_identity_id = var.kubelet_user_assigned_identity_id - } + type = "SystemAssigned" } tags = merge({ @@ -330,6 +329,52 @@ resource "azurerm_kubernetes_cluster_node_pool" "autoscaled" { }, local.tags) } +# AKS automatically creates Virtual Machine Contributor role assignment on node resource group for the kubelet identity. +# However, disk attachment operations require additional permissions beyond Virtual Machine Contributor. +# Create a custom role with minimal permissions for VMSS disk operations. +resource "azurerm_role_definition" "aks_kubelet_vmss_disk_manager" { + name = "AKS Kubelet VMSS Disk Manager - ${var.context_id}" + scope = azurerm_kubernetes_cluster.main.node_resource_group_id + description = "Minimal permissions for AKS kubelet identity to manage VMSS disk attachments" + + permissions { + actions = concat( + [ + # VMSS virtual machine operations for disk attachment (REQUIRED) + "Microsoft.Compute/virtualMachineScaleSets/virtualMachines/read", + "Microsoft.Compute/virtualMachineScaleSets/virtualMachines/write", + # Core disk operations (REQUIRED for basic disk attachment) + "Microsoft.Compute/disks/read", + "Microsoft.Compute/disks/write", + "Microsoft.Compute/disks/delete", + "Microsoft.Compute/disks/beginGetAccess/action", + "Microsoft.Compute/disks/endGetAccess/action", + # Location/operation queries (may be needed for operation status checks) + "Microsoft.Compute/locations/DiskOperations/read", + "Microsoft.Compute/locations/vmSizes/read", + "Microsoft.Compute/locations/operations/read" + ], + var.enable_volume_snapshots ? [ + # Snapshot operations (only included if volume snapshots are enabled) + "Microsoft.Compute/snapshots/read", + "Microsoft.Compute/snapshots/write", + "Microsoft.Compute/snapshots/delete" + ] : [] + ) + not_actions = [] + } + + assignable_scopes = [ + azurerm_kubernetes_cluster.main.node_resource_group_id + ] +} + +resource "azurerm_role_assignment" "kubelet_vmss_disk_manager" { + scope = azurerm_kubernetes_cluster.main.node_resource_group_id + role_definition_id = azurerm_role_definition.aks_kubelet_vmss_disk_manager.role_definition_resource_id + principal_id = local.kubelet_object_id +} + resource "local_file" "kube_config" { content = azurerm_kubernetes_cluster.main.kube_config_raw filename = local.kubeconfig_path diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index 3a3a6885e..cc3c38ce1 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -84,6 +84,16 @@ run "minimal_configuration" { condition = azurerm_kubernetes_cluster.main.identity[0].type == "SystemAssigned" error_message = "Cluster should use system-assigned identity by default" } + + assert { + condition = azurerm_kubernetes_cluster.main.oidc_issuer_enabled == true + error_message = "OIDC issuer should be enabled by default" + } + + assert { + condition = azurerm_kubernetes_cluster.main.workload_identity_enabled == true + error_message = "Workload Identity should be enabled by default" + } } # Tests a full configuration with all optional variables explicitly set, @@ -97,13 +107,8 @@ run "full_configuration" { cluster_name = "test-cluster" resource_group_name = "test-rg" kubernetes_version = "1.32" - user_assigned_identity_ids = [ - "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1", - "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-2" - ] - kubelet_client_id = "test-client-id" - kubelet_object_id = "test-object-id" - kubelet_user_assigned_identity_id = "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1" + oidc_issuer_enabled = true + workload_identity_enabled = true default_node_pool = { name = "system" vm_size = "Standard_D2s_v3" @@ -208,28 +213,18 @@ run "full_configuration" { } assert { - condition = azurerm_kubernetes_cluster.main.identity[0].type == "UserAssigned" - error_message = "Cluster should use user-assigned identity when IDs are provided" - } - - assert { - condition = length(azurerm_kubernetes_cluster.main.identity[0].identity_ids) == 2 - error_message = "Cluster should have 2 user-assigned identity IDs" - } - - assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].client_id == "test-client-id" - error_message = "Kubelet client ID should match input" + condition = azurerm_kubernetes_cluster.main.identity[0].type == "SystemAssigned" + error_message = "Cluster should use system-assigned identity" } assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].object_id == "test-object-id" - error_message = "Kubelet object ID should match input" + condition = azurerm_kubernetes_cluster.main.oidc_issuer_enabled == true + error_message = "OIDC issuer should be enabled" } assert { - condition = azurerm_kubernetes_cluster.main.kubelet_identity[0].user_assigned_identity_id == "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.ManagedIdentity/userAssignedIdentities/test-identity-1" - error_message = "Kubelet user-assigned identity ID should match input" + condition = azurerm_kubernetes_cluster.main.workload_identity_enabled == true + error_message = "Workload Identity should be enabled" } } diff --git a/terraform/cluster/azure-aks/variables.tf b/terraform/cluster/azure-aks/variables.tf index 44e0a5947..a2f149115 100644 --- a/terraform/cluster/azure-aks/variables.tf +++ b/terraform/cluster/azure-aks/variables.tf @@ -205,12 +205,6 @@ variable "expiration_date" { default = null } -variable "user_assigned_identity_ids" { - type = list(string) - description = "User assigned identity IDs for the AKS cluster. If provided, the cluster will use only user-assigned identities." - default = [] -} - variable "soft_delete_retention_days" { type = number description = "The number of days to retain the AKS cluster's key vault" @@ -241,20 +235,14 @@ variable "endpoint_private_access" { default = false } -variable "kubelet_client_id" { - description = "Client ID of the user-assigned identity to use for the kubelet. If not provided, the cluster will use the system-assigned identity." - type = string - default = null -} - -variable "kubelet_object_id" { - description = "Object ID of the user-assigned identity to use for the kubelet. If not provided, the cluster will use the system-assigned identity." - type = string - default = null +variable "oidc_issuer_enabled" { + description = "Enable OIDC issuer for the AKS cluster" + type = bool + default = true } -variable "kubelet_user_assigned_identity_id" { - description = "Resource ID of the user-assigned identity to use for the kubelet. If not provided, the cluster will use the system-assigned identity." - type = string - default = null +variable "workload_identity_enabled" { + description = "Enable Workload Identity for the AKS cluster" + type = bool + default = true } From 3be405255d884bc73ee3846165f68b1983f1c67f Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 11:20:44 -0500 Subject: [PATCH 3/7] fmt Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/test.tftest.hcl | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index cc3c38ce1..ebbe0a5da 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -102,12 +102,12 @@ run "full_configuration" { command = plan variables { - context_id = "test" - name = "windsor-aks" - cluster_name = "test-cluster" - resource_group_name = "test-rg" - kubernetes_version = "1.32" - oidc_issuer_enabled = true + context_id = "test" + name = "windsor-aks" + cluster_name = "test-cluster" + resource_group_name = "test-rg" + kubernetes_version = "1.32" + oidc_issuer_enabled = true workload_identity_enabled = true default_node_pool = { name = "system" From b4abe4ee48ad31100d5a5ecba65b2533a33bc3c7 Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:00:40 -0500 Subject: [PATCH 4/7] Add enable_volume_snapshots var Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/test.tftest.hcl | 54 +++++++++++++++++++++ terraform/cluster/azure-aks/variables.tf | 6 +++ 2 files changed, 60 insertions(+) diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index ebbe0a5da..ae6a90080 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -94,6 +94,16 @@ run "minimal_configuration" { condition = azurerm_kubernetes_cluster.main.workload_identity_enabled == true error_message = "Workload Identity should be enabled by default" } + + assert { + condition = contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/read") + error_message = "Snapshot permissions should be included when enable_volume_snapshots is true (default)" + } + + assert { + condition = contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/write") + error_message = "Snapshot write permissions should be included when enable_volume_snapshots is true (default)" + } } # Tests a full configuration with all optional variables explicitly set, @@ -135,6 +145,7 @@ run "full_configuration" { private_cluster_enabled = false azure_policy_enabled = true local_account_disabled = false + enable_volume_snapshots = true } assert { @@ -226,6 +237,16 @@ run "full_configuration" { condition = azurerm_kubernetes_cluster.main.workload_identity_enabled == true error_message = "Workload Identity should be enabled" } + + assert { + condition = contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/read") + error_message = "Snapshot permissions should be included when enable_volume_snapshots is true" + } + + assert { + condition = contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/write") + error_message = "Snapshot write permissions should be included when enable_volume_snapshots is true" + } } # Tests the private cluster configuration, ensuring that enabling the private_cluster_enabled @@ -295,3 +316,36 @@ run "multiple_invalid_inputs" { kubernetes_version = "v1.32" } } + +# Tests that when enable_volume_snapshots is false, snapshot permissions are not included in the role definition. +# This verifies the conditional logic that excludes snapshot operations when volume snapshots are disabled. +run "volume_snapshots_disabled" { + command = plan + + variables { + context_id = "test" + name = "windsor-aks" + kubernetes_version = "1.32" + enable_volume_snapshots = false + } + + assert { + condition = !contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/read") + error_message = "Snapshot read permissions should not be included when enable_volume_snapshots is false" + } + + assert { + condition = !contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/write") + error_message = "Snapshot write permissions should not be included when enable_volume_snapshots is false" + } + + assert { + condition = !contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/delete") + error_message = "Snapshot delete permissions should not be included when enable_volume_snapshots is false" + } + + assert { + condition = contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/disks/read") + error_message = "Core disk permissions should still be included when enable_volume_snapshots is false" + } +} diff --git a/terraform/cluster/azure-aks/variables.tf b/terraform/cluster/azure-aks/variables.tf index a2f149115..ae6203aaa 100644 --- a/terraform/cluster/azure-aks/variables.tf +++ b/terraform/cluster/azure-aks/variables.tf @@ -235,6 +235,12 @@ variable "endpoint_private_access" { default = false } +variable "enable_volume_snapshots" { + description = "Enable volume snapshot permissions for the kubelet identity. Set to false to use minimal permissions if volume snapshots are not needed." + type = bool + default = true +} + variable "oidc_issuer_enabled" { description = "Enable OIDC issuer for the AKS cluster" type = bool From cdb8a483d1654da1e0df979e85145b99b1a0005e Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:02:56 -0500 Subject: [PATCH 5/7] fmt Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/test.tftest.hcl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index ae6a90080..5c02fa529 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -145,7 +145,7 @@ run "full_configuration" { private_cluster_enabled = false azure_policy_enabled = true local_account_disabled = false - enable_volume_snapshots = true + enable_volume_snapshots = true } assert { @@ -323,9 +323,9 @@ run "volume_snapshots_disabled" { command = plan variables { - context_id = "test" - name = "windsor-aks" - kubernetes_version = "1.32" + context_id = "test" + name = "windsor-aks" + kubernetes_version = "1.32" enable_volume_snapshots = false } From 34841d26925f7b5e30a8c10baadfa8981b91d10f Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:03:34 -0500 Subject: [PATCH 6/7] checkov Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/main.tf | 1 + 1 file changed, 1 insertion(+) diff --git a/terraform/cluster/azure-aks/main.tf b/terraform/cluster/azure-aks/main.tf index e23bdb700..ae3f9525b 100644 --- a/terraform/cluster/azure-aks/main.tf +++ b/terraform/cluster/azure-aks/main.tf @@ -228,6 +228,7 @@ resource "azurerm_kubernetes_cluster" "main" { resource_group_name = azurerm_resource_group.aks.name dns_prefix = local.cluster_name # checkov:skip=CKV_AZURE_339: Kubernetes version is populated from the cloud provider's stable version via Renovate. + # checkov:skip=CKV_AZURE_4: Log Analytics workspace is created but diagnostic settings are configured separately or via alternative monitoring solutions kubernetes_version = var.kubernetes_version role_based_access_control_enabled = var.role_based_access_control_enabled automatic_upgrade_channel = var.automatic_upgrade_channel From 335d36b3828f5d77a3fadfaec7ef95579927f02e Mon Sep 17 00:00:00 2001 From: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> Date: Mon, 8 Dec 2025 12:16:12 -0500 Subject: [PATCH 7/7] clean test Signed-off-by: Ryan VanGundy <85766511+rmvangun@users.noreply.github.com> --- terraform/cluster/azure-aks/test.tftest.hcl | 75 --------------------- 1 file changed, 75 deletions(-) diff --git a/terraform/cluster/azure-aks/test.tftest.hcl b/terraform/cluster/azure-aks/test.tftest.hcl index e11e49c3c..e8af7a395 100644 --- a/terraform/cluster/azure-aks/test.tftest.hcl +++ b/terraform/cluster/azure-aks/test.tftest.hcl @@ -22,15 +22,6 @@ mock_provider "azurerm" { id = "/subscriptions/12345678-1234-9876-4563-123456789012/resourceGroups/example-resource-group/providers/Microsoft.Network/virtualNetworks/vnet-test/subnets/subnet-test" } } - mock_resource "azurerm_kubernetes_cluster" { - defaults = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } } @@ -45,17 +36,6 @@ run "minimal_configuration" { kubernetes_version = "1.32" } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = azurerm_kubernetes_cluster.main.name == "windsor-aks-test" error_message = "Cluster name should default to 'windsor-aks-test' when cluster_name is omitted" @@ -187,17 +167,6 @@ run "full_configuration" { enable_volume_snapshots = true } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = azurerm_kubernetes_cluster.main.name == "test-cluster" error_message = "Cluster name should match input" @@ -337,17 +306,6 @@ run "private_cluster" { kubernetes_version = "1.32" } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = azurerm_kubernetes_cluster.main.private_cluster_enabled == true error_message = "Private cluster should be enabled" @@ -366,17 +324,6 @@ run "config_file_created" { context_path = "/tmp" } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = length(local_file.kube_config) >= 1 error_message = "Kubeconfig file should be generated when context path is provided" @@ -392,17 +339,6 @@ run "network_configuration" { dns_service_ip = "10.0.0.10" } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = azurerm_kubernetes_cluster.main.network_profile[0].service_cidr == "10.0.0.0/16" error_message = "Service CIDR should match input value" @@ -439,17 +375,6 @@ run "volume_snapshots_disabled" { enable_volume_snapshots = false } - override_resource { - target = azurerm_kubernetes_cluster.main - values = { - kubelet_identity = [{ - client_id = "44444444-4444-4444-4444-444444444444" - object_id = "55555555-5555-5555-5555-555555555555" - user_assigned_identity_id = "" - }] - } - } - assert { condition = !contains(azurerm_role_definition.aks_kubelet_vmss_disk_manager.permissions[0].actions, "Microsoft.Compute/snapshots/read") error_message = "Snapshot read permissions should not be included when enable_volume_snapshots is false"