Skip to content
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
13 changes: 9 additions & 4 deletions terraform/cluster/azure-aks/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,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
Expand Down Expand Up @@ -297,10 +298,13 @@ resource "azurerm_kubernetes_cluster" "main" {
workload_identity_enabled = var.workload_identity_enabled

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
}

# Use system-assigned managed identity (Microsoft default and best practice)
Expand All @@ -324,6 +328,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)
Expand Down
48 changes: 47 additions & 1 deletion terraform/cluster/azure-aks/test.tftest.hcl
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ mock_provider "azurerm" {
}
}


# 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" {
Expand Down Expand Up @@ -125,6 +126,21 @@ run "minimal_configuration" {
error_message = "Workload Identity should be enabled 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'"
}

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)"
Expand Down Expand Up @@ -159,6 +175,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
Expand All @@ -170,11 +187,13 @@ 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"
authorized_ip_ranges = ["10.0.0.0/8"]
admin_object_ids = ["55555555-5555-5555-5555-555555555555"]
enable_volume_snapshots = true
Expand Down Expand Up @@ -252,14 +271,39 @@ 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"
}

assert {
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_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.network_profile[0].outbound_type == "loadBalancer"
error_message = "Outbound type should match input value"
}

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'"
}

assert {
condition = azurerm_kubernetes_cluster.main.oidc_issuer_enabled == true
error_message = "OIDC issuer should be enabled"
Expand Down Expand Up @@ -457,10 +501,12 @@ 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"
}
}

Expand Down
12 changes: 12 additions & 0 deletions terraform/cluster/azure-aks/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ variable "default_node_pool" {
max_count = number
node_count = number
only_critical_addons_enabled = bool
availability_zones = optional(list(string))
})
default = {
name = "system"
Expand All @@ -105,6 +106,7 @@ variable "autoscaled_node_pool" {
host_encryption_enabled = bool
min_count = number
max_count = number
availability_zones = optional(list(string))
})
default = {
enabled = true
Expand Down Expand Up @@ -247,6 +249,16 @@ variable "endpoint_private_access" {
default = false
}

variable "outbound_type" {
description = "The outbound (egress) routing method which should be used for this Kubernetes Cluster."
type = string
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 "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
Expand Down
1 change: 1 addition & 0 deletions terraform/network/aws-vpc/.terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 26 additions & 26 deletions terraform/network/aws-vpc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,14 @@
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >=1.8 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | 6.18.0 |
| <a name="requirement_aws"></a> [aws](#requirement\_aws) | 6.25.0 |
| <a name="requirement_random"></a> [random](#requirement\_random) | 3.7.2 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.18.0 |
| <a name="provider_aws"></a> [aws](#provider\_aws) | 6.25.0 |
| <a name="provider_null"></a> [null](#provider\_null) | 3.2.4 |
| <a name="provider_random"></a> [random](#provider\_random) | 3.7.2 |

Expand All @@ -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

Expand Down
6 changes: 4 additions & 2 deletions terraform/network/azure-vnet/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@
| Name | Version |
|------|---------|
| <a name="requirement_terraform"></a> [terraform](#requirement\_terraform) | >=1.8 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 4.50.0 |
| <a name="requirement_azurerm"></a> [azurerm](#requirement\_azurerm) | ~> 4.55.0 |

## Providers

| Name | Version |
|------|---------|
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 4.50.0 |
| <a name="provider_azurerm"></a> [azurerm](#provider\_azurerm) | 4.55.0 |

## Modules

Expand All @@ -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
Expand Down
17 changes: 16 additions & 1 deletion terraform/network/azure-vnet/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading
Loading