diff --git a/terraform/azure/azure-aks-k8s/README.md b/terraform/azure/azure-aks-k8s/README.md new file mode 100644 index 0000000..c87e1a5 --- /dev/null +++ b/terraform/azure/azure-aks-k8s/README.md @@ -0,0 +1,71 @@ +# azure-aks-k8s + +This example creates the following: + +- a Virtual Network with appropriate subnets using the [Azure RM Module for Network](https://registry.terraform.io/modules/Azure/network/azurerm/latest) +from the Terraform Registry +- an Azure Kubernetes Service (AKS) cluster with default node pool +- a system-assigned managed identity for the AKS cluster +- Azure CNI networking for better network performance +- Optional Log Analytics workspace for monitoring + +## Prerequisites + +- [Azure CLI](https://docs.microsoft.com/en-us/cli/azure/install-azure-cli) installed +- [Terraform](https://www.terraform.io/downloads.html) installed (version >= 1.0) +- Azure subscription and appropriate permissions + +## To use + +Follow the documentation to configure the Azure provider: + +- [Azure](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) + +### Deploy + +```shell +terraform init +terraform apply +``` + +## To destroy + +```shell +terraform destroy +``` + +## Configuration + +The example uses variables with default values that can be overridden. You can create a `terraform.tfvars` file to customize the deployment: + +```hcl +resource_group_name = "my-aks-rg" +location = "westeurope" +cluster_name = "my-production-cluster" +node_count = 3 +vm_size = "Standard_D4s_v3" +``` + +## Outputs + +After applying the configuration, Terraform will output: +- `kube_config`: The Kubernetes config file (sensitive) +- `cluster_endpoint`: The AKS cluster endpoint +- `cluster_ca_certificate`: The cluster CA certificate (sensitive) +- `cluster_name`: The name of the AKS cluster +- `resource_group_name`: The name of the resource group + +## Features + +- Azure CNI networking +- System-assigned managed identity +- Auto-scaling enabled by default +- Customizable node pool configuration +- Network security through VNet integration +- Resource tagging support + +## Notes + +- The default configuration uses `Standard_D2_v2` VMs which are suitable for development/testing +- For production workloads, consider using larger VM sizes and enabling additional security features +- The network configuration uses Azure CNI for better network performance and security \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/cluster.tf b/terraform/azure/azure-aks-k8s/cluster.tf new file mode 100644 index 0000000..0b7040f --- /dev/null +++ b/terraform/azure/azure-aks-k8s/cluster.tf @@ -0,0 +1,78 @@ +# AKS Resources + +resource "azurerm_resource_group" "aks" { + name = "${local.name}-rg" + location = var.location + tags = local.tags +} + +module "vpc" { + source = "../internal-modules/azure-network" + + name = local.name + tags = local.tags + + location = var.location + resource_group_name = azurerm_resource_group.aks.name + + cidrs = var.vnet_address_space + subnet_cidrs = var.subnet_address_prefixes + subnet_name_public = "aks-nodes" + subnet_name_private = "aks-private" + subnet_name_private_dns_resolver = "dns-resolver" +} + +# AKS Cluster +resource "azurerm_kubernetes_cluster" "aks" { + name = local.name + location = azurerm_resource_group.aks.location + resource_group_name = azurerm_resource_group.aks.name + dns_prefix = local.name + kubernetes_version = var.kubernetes_version + + # Add node resource group name + node_resource_group = "${local.name}-node-rg" + + default_node_pool { + name = "default" + vm_size = var.vm_size + vnet_subnet_id = module.vpc.public_subnet_id + enable_auto_scaling = var.enable_auto_scaling + min_count = var.min_count + max_count = var.max_count + os_disk_size_gb = 50 + zones = [1, 2, 3] + } + + identity { + type = "SystemAssigned" + } + + network_profile { + network_plugin = "azure" + service_cidr = var.service_cidr + dns_service_ip = var.dns_service_ip + load_balancer_sku = "standard" + } + + # Use oms_agent addon directly instead of addon_profile + dynamic "oms_agent" { + for_each = var.enable_log_analytics_workspace ? [1] : [] + content { + log_analytics_workspace_id = azurerm_log_analytics_workspace.aks[0].id + } + } + + tags = local.tags +} + +# Conditionally create Log Analytics workspace if monitoring is enabled +resource "azurerm_log_analytics_workspace" "aks" { + count = var.enable_log_analytics_workspace ? 1 : 0 + name = "${local.name}-logs" + location = azurerm_resource_group.aks.location + resource_group_name = azurerm_resource_group.aks.name + sku = "PerGB2018" + retention_in_days = var.log_retention_in_days + tags = local.tags +} \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/main.tf b/terraform/azure/azure-aks-k8s/main.tf new file mode 100644 index 0000000..b84f42d --- /dev/null +++ b/terraform/azure/azure-aks-k8s/main.tf @@ -0,0 +1,9 @@ +locals { + name = var.cluster_name != "" ? var.cluster_name : "example-${basename(path.cwd)}" + + tags = merge({ + Name = local.name + Environment = var.environment + ManagedBy = "Terraform" + }, var.tags) +} \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/outputs.tf b/terraform/azure/azure-aks-k8s/outputs.tf new file mode 100644 index 0000000..67d05ac --- /dev/null +++ b/terraform/azure/azure-aks-k8s/outputs.tf @@ -0,0 +1,43 @@ +# Output the cluster's credentials +output "kube_config" { + description = "Raw kubeconfig content for the AKS cluster" + value = azurerm_kubernetes_cluster.aks.kube_config_raw + sensitive = true +} + +output "cluster_endpoint" { + description = "Kubernetes API server endpoint" + value = azurerm_kubernetes_cluster.aks.kube_config.0.host + sensitive = true +} + +output "cluster_ca_certificate" { + description = "Base64 encoded certificate authority of the Kubernetes cluster" + value = azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate + sensitive = true +} + +output "cluster_name" { + description = "Name of the AKS cluster" + value = azurerm_kubernetes_cluster.aks.name +} + +output "resource_group_name" { + description = "Name of the resource group containing the AKS cluster" + value = azurerm_resource_group.aks.name +} + +output "vnet_id" { + description = "ID of the virtual network" + value = module.vpc.vnet_id +} + +output "principal_id" { + description = "Principal ID of the AKS cluster identity" + value = azurerm_kubernetes_cluster.aks.identity[0].principal_id +} + +output "node_resource_group" { + description = "Auto-generated resource group for the AKS cluster nodes" + value = azurerm_kubernetes_cluster.aks.node_resource_group +} \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/providers.tf b/terraform/azure/azure-aks-k8s/providers.tf new file mode 100644 index 0000000..917742a --- /dev/null +++ b/terraform/azure/azure-aks-k8s/providers.tf @@ -0,0 +1,8 @@ +provider "azurerm" { + skip_provider_registration = true + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/variables.tf b/terraform/azure/azure-aks-k8s/variables.tf new file mode 100644 index 0000000..b050b2a --- /dev/null +++ b/terraform/azure/azure-aks-k8s/variables.tf @@ -0,0 +1,118 @@ +variable "location" { + description = "Azure region where resources will be created" + type = string + default = "eastus" +} + +variable "cluster_name" { + description = "Name of the AKS cluster (will generate one if empty)" + type = string +} + +variable "environment" { + description = "Environment for the resources (e.g., dev, test, prod)" + type = string + default = "dev" +} + +variable "tags" { + description = "A map of tags to add to all resources" + type = map(string) + default = {} +} + +variable "kubernetes_version" { + description = "Kubernetes version to use for the AKS cluster" + type = string + default = "1.31.6" +} + +variable "vm_size" { + description = "VM size for the AKS node pool" + type = string + default = "Standard_DS2_v2" +} + +variable "enable_auto_scaling" { + description = "Enable auto scaling for the AKS node pool" + type = bool + default = true +} + +variable "min_count" { + description = "Minimum number of nodes in the AKS node pool" + type = number + default = 1 +} + +variable "max_count" { + description = "Maximum number of nodes in the AKS node pool" + type = number + default = 3 +} + +variable "vnet_address_space" { + description = "Address space for the virtual network" + type = list(string) + default = ["10.0.0.0/16"] +} + +variable "subnet_address_prefixes" { + description = "Address prefixes for the subnets (requires 3 subnets for nodes, private, and DNS resolver)" + type = list(string) + default = ["10.0.1.0/24", "10.0.2.0/24", "10.0.3.0/24"] +} + +variable "service_cidr" { + description = "CIDR range for Kubernetes services" + type = string + default = "172.16.0.0/16" +} + +variable "dns_service_ip" { + description = "IP address for Kubernetes DNS service (must be within service_cidr)" + type = string + default = "172.16.0.10" +} + +variable "docker_bridge_cidr" { + description = "CIDR notation IP for Docker bridge" + type = string + default = "172.17.0.1/16" +} + +variable "availability_zones" { + description = "List of availability zones to use for the node pool" + type = list(number) + default = [1, 2, 3] +} + +variable "os_disk_size_gb" { + description = "Disk size for nodes in GB" + type = number + default = 50 +} + +variable "os_disk_type" { + description = "Disk type for nodes" + type = string + default = "Managed" +} + +variable "node_labels" { + description = "Labels to apply to nodes in the default node pool" + type = map(string) + default = {} +} + +variable "enable_log_analytics_workspace" { + description = "Enable the creation of a Log Analytics workspace for the AKS cluster" + type = bool + default = false +} + +variable "log_retention_in_days" { + description = "Number of days to retain logs in Log Analytics" + type = number + default = 30 +} \ No newline at end of file diff --git a/terraform/azure/azure-aks-k8s/versions.tf b/terraform/azure/azure-aks-k8s/versions.tf new file mode 100644 index 0000000..0b9234e --- /dev/null +++ b/terraform/azure/azure-aks-k8s/versions.tf @@ -0,0 +1,8 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "~> 3.0" + } + } +} \ No newline at end of file