Skip to content

Commit f06a644

Browse files
Curtis GoolsbyCurtis Goolsby
authored andcommitted
terraform to deploy AKS cluster checkpoint #1
1 parent 63ac033 commit f06a644

File tree

9 files changed

+412
-0
lines changed

9 files changed

+412
-0
lines changed

terraform/aks/commands

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
az aks get-credentials --resource-group fullStack-cluster-rg --name fullStack-cluster --overwrite-existing
2+
3+
4+
5+
az aks nodepool update \
6+
--resource-group fullStack-cluster-rg \
7+
--cluster-name fullStack-cluster \
8+
--name default \
9+
--min-count 1 \
10+
--max-count 10 --update-cluster-autoscaler

terraform/aks/csi-identity.tf

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# Managed Identity for Azure Disk CSI Driver
2+
resource "azurerm_user_assigned_identity" "azure_disk_csi" {
3+
name = "${var.cluster_name}-azure-disk-csi-identity"
4+
resource_group_name = azurerm_resource_group.aks.name
5+
location = azurerm_resource_group.aks.location
6+
tags = var.tags
7+
}
8+
9+
# Federated credential for Azure Disk CSI Driver
10+
resource "azurerm_federated_identity_credential" "azure_disk_csi" {
11+
name = "azure-disk-csi-federated"
12+
resource_group_name = azurerm_resource_group.aks.name
13+
audience = ["api://AzureADTokenExchange"]
14+
parent_id = azurerm_user_assigned_identity.azure_disk_csi.id
15+
issuer = azurerm_kubernetes_cluster.aks.oidc_issuer_url
16+
subject = "system:serviceaccount:kube-system:csi-azuredisk-node-sa"
17+
}
18+
19+
# Role assignment for Azure Disk CSI to manage disks
20+
resource "azurerm_role_assignment" "azure_disk_csi_contributor" {
21+
scope = azurerm_resource_group.aks.id
22+
role_definition_name = "Contributor"
23+
principal_id = azurerm_user_assigned_identity.azure_disk_csi.principal_id
24+
}
25+
26+
# Managed Identity for Azure File CSI Driver
27+
resource "azurerm_user_assigned_identity" "azure_file_csi" {
28+
name = "${var.cluster_name}-azure-file-csi-identity"
29+
resource_group_name = azurerm_resource_group.aks.name
30+
location = azurerm_resource_group.aks.location
31+
tags = var.tags
32+
}
33+
34+
# Federated credential for Azure File CSI Driver
35+
resource "azurerm_federated_identity_credential" "azure_file_csi" {
36+
name = "azure-file-csi-federated"
37+
resource_group_name = azurerm_resource_group.aks.name
38+
audience = ["api://AzureADTokenExchange"]
39+
parent_id = azurerm_user_assigned_identity.azure_file_csi.id
40+
issuer = azurerm_kubernetes_cluster.aks.oidc_issuer_url
41+
subject = "system:serviceaccount:kube-system:csi-azurefile-node-sa"
42+
}
43+
44+
# Role assignment for Azure File CSI to manage storage accounts
45+
resource "azurerm_role_assignment" "azure_file_csi_contributor" {
46+
scope = azurerm_resource_group.aks.id
47+
role_definition_name = "Contributor"
48+
principal_id = azurerm_user_assigned_identity.azure_file_csi.principal_id
49+
}

terraform/aks/k8s-outputs.tf

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
# Create a ConfigMap with Terraform outputs for use by Flux
2+
resource "kubernetes_config_map" "terraform_outputs" {
3+
metadata {
4+
name = "terraform-outputs"
5+
namespace = "flux-system"
6+
}
7+
8+
data = {
9+
# Azure tenant and subscription information
10+
AZURE_TENANT_ID = data.azurerm_client_config.current.tenant_id
11+
AZURE_SUBSCRIPTION_ID = data.azurerm_client_config.current.subscription_id
12+
13+
# Cluster information
14+
CLUSTER_NAME = var.cluster_name
15+
RESOURCE_GROUP = azurerm_resource_group.aks.name
16+
LOCATION = azurerm_resource_group.aks.location
17+
18+
# Network information
19+
VNET_ID = azurerm_virtual_network.aks.id
20+
VNET_NAME = azurerm_virtual_network.aks.name
21+
SUBNET_ID = azurerm_subnet.aks.id
22+
23+
# OIDC information for workload identity
24+
OIDC_ISSUER_URL = azurerm_kubernetes_cluster.aks.oidc_issuer_url
25+
26+
# Managed Identity Client IDs (for workload identity)
27+
AZURE_DISK_CSI_CLIENT_ID = azurerm_user_assigned_identity.azure_disk_csi.client_id
28+
AZURE_FILE_CSI_CLIENT_ID = azurerm_user_assigned_identity.azure_file_csi.client_id
29+
30+
# Key Vault information
31+
KEY_VAULT_NAME = azurerm_key_vault.main.name
32+
KEY_VAULT_URI = azurerm_key_vault.main.vault_uri
33+
}
34+
35+
depends_on = [
36+
azurerm_kubernetes_cluster.aks,
37+
null_resource.create_flux_ns
38+
]
39+
}

terraform/aks/key-vault.tf

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Create a Key Vault for storing secrets
2+
resource "azurerm_key_vault" "main" {
3+
name = "${substr(replace(var.cluster_name, "-", ""), 0, 20)}kv"
4+
resource_group_name = azurerm_resource_group.aks.name
5+
location = azurerm_resource_group.aks.location
6+
tenant_id = data.azurerm_client_config.current.tenant_id
7+
sku_name = "standard"
8+
9+
# Enable RBAC authorization
10+
enable_rbac_authorization = true
11+
12+
# Soft delete and purge protection
13+
soft_delete_retention_days = 7
14+
purge_protection_enabled = false # Set to true in production
15+
16+
tags = var.tags
17+
}
18+
19+
# Grant the current user/service principal access to manage secrets
20+
resource "azurerm_role_assignment" "current_user_key_vault_admin" {
21+
scope = azurerm_key_vault.main.id
22+
role_definition_name = "Key Vault Administrator"
23+
principal_id = data.azurerm_client_config.current.object_id
24+
}

terraform/aks/main.tf

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
terraform {
2+
required_version = ">= 1.0"
3+
4+
required_providers {
5+
azurerm = {
6+
source = "hashicorp/azurerm"
7+
version = "~> 3.0"
8+
}
9+
kubernetes = {
10+
source = "hashicorp/kubernetes"
11+
version = "~> 2.0"
12+
}
13+
}
14+
15+
# You'll want to change this to your preferred backend
16+
backend "local" {
17+
path = "terraform.tfstate"
18+
}
19+
}
20+
21+
provider "azurerm" {
22+
features {}
23+
}
24+
25+
# Get current Azure client configuration
26+
data "azurerm_client_config" "current" {}
27+
28+
# Configure the Kubernetes provider
29+
provider "kubernetes" {
30+
host = azurerm_kubernetes_cluster.aks.kube_config.0.host
31+
client_certificate = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_certificate)
32+
client_key = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.client_key)
33+
cluster_ca_certificate = base64decode(azurerm_kubernetes_cluster.aks.kube_config.0.cluster_ca_certificate)
34+
}
35+
36+
# Resource group
37+
resource "azurerm_resource_group" "aks" {
38+
name = "${var.cluster_name}-rg"
39+
location = var.location
40+
tags = var.tags
41+
}
42+
43+
# AKS Cluster
44+
resource "azurerm_kubernetes_cluster" "aks" {
45+
name = var.cluster_name
46+
location = azurerm_resource_group.aks.location
47+
resource_group_name = azurerm_resource_group.aks.name
48+
dns_prefix = var.cluster_name
49+
kubernetes_version = var.kubernetes_version
50+
51+
# Enable workload identity and OIDC for pod authentication
52+
oidc_issuer_enabled = true
53+
workload_identity_enabled = true
54+
55+
default_node_pool {
56+
name = "default"
57+
node_count = var.node_count
58+
vm_size = var.node_size
59+
60+
# Use Azure CNI for better integration
61+
vnet_subnet_id = azurerm_subnet.aks.id
62+
63+
enable_auto_scaling = true
64+
min_count = var.min_node_count
65+
max_count = var.max_node_count
66+
}
67+
68+
identity {
69+
type = "SystemAssigned"
70+
}
71+
72+
network_profile {
73+
network_plugin = "azure"
74+
network_policy = "azure"
75+
load_balancer_sku = "standard"
76+
service_cidr = var.service_cidr
77+
dns_service_ip = var.dns_service_ip
78+
}
79+
80+
tags = var.tags
81+
}

terraform/aks/namespace.tf

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
resource "null_resource" "create_flux_ns" {
2+
provisioner "local-exec" {
3+
command = <<-EOT
4+
export KUBECONFIG="$(mktemp)"
5+
echo '${azurerm_kubernetes_cluster.aks.kube_config_raw}' > "$KUBECONFIG"
6+
kubectl get ns flux-system || kubectl create ns flux-system
7+
EOT
8+
interpreter = ["/bin/bash", "-c"]
9+
}
10+
11+
triggers = {
12+
cluster_endpoint = azurerm_kubernetes_cluster.aks.kube_config.0.host
13+
}
14+
15+
depends_on = [azurerm_kubernetes_cluster.aks]
16+
}

terraform/aks/outputs.tf

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
output "cluster_name" {
2+
description = "Name of the AKS cluster"
3+
value = azurerm_kubernetes_cluster.aks.name
4+
}
5+
6+
output "cluster_id" {
7+
description = "ID of the AKS cluster"
8+
value = azurerm_kubernetes_cluster.aks.id
9+
}
10+
11+
output "kube_config" {
12+
description = "Kubernetes config for connecting to the cluster"
13+
value = azurerm_kubernetes_cluster.aks.kube_config_raw
14+
sensitive = true
15+
}
16+
17+
output "kube_config_host" {
18+
description = "Kubernetes API server endpoint"
19+
value = azurerm_kubernetes_cluster.aks.kube_config.0.host
20+
sensitive = true
21+
}
22+
23+
output "resource_group_name" {
24+
description = "Name of the resource group"
25+
value = azurerm_resource_group.aks.name
26+
}
27+
28+
output "vnet_id" {
29+
description = "ID of the Virtual Network"
30+
value = azurerm_virtual_network.aks.id
31+
}
32+
33+
output "vnet_name" {
34+
description = "Name of the Virtual Network"
35+
value = azurerm_virtual_network.aks.name
36+
}
37+
38+
output "aks_subnet_id" {
39+
description = "ID of the AKS subnet"
40+
value = azurerm_subnet.aks.id
41+
}
42+
43+
output "cluster_identity_principal_id" {
44+
description = "Principal ID of the cluster managed identity"
45+
value = azurerm_kubernetes_cluster.aks.identity.0.principal_id
46+
}
47+
48+
output "node_resource_group" {
49+
description = "Name of the auto-generated resource group for AKS nodes"
50+
value = azurerm_kubernetes_cluster.aks.node_resource_group
51+
}
52+
53+
# Workload Identity outputs
54+
output "oidc_issuer_url" {
55+
description = "OIDC issuer URL for workload identity"
56+
value = azurerm_kubernetes_cluster.aks.oidc_issuer_url
57+
}
58+
59+
output "azure_disk_csi_identity_client_id" {
60+
description = "Client ID of the Azure Disk CSI managed identity"
61+
value = azurerm_user_assigned_identity.azure_disk_csi.client_id
62+
}
63+
64+
output "azure_file_csi_identity_client_id" {
65+
description = "Client ID of the Azure File CSI managed identity"
66+
value = azurerm_user_assigned_identity.azure_file_csi.client_id
67+
}
68+
69+
output "key_vault_name" {
70+
description = "Name of the Key Vault"
71+
value = azurerm_key_vault.main.name
72+
}
73+
74+
output "key_vault_uri" {
75+
description = "URI of the Key Vault"
76+
value = azurerm_key_vault.main.vault_uri
77+
}

terraform/aks/variables.tf

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
variable "cluster_name" {
2+
description = "Name of the AKS cluster"
3+
type = string
4+
default = "fullStack-cluster"
5+
}
6+
7+
variable "location" {
8+
description = "Azure region"
9+
type = string
10+
default = "eastus"
11+
}
12+
13+
variable "vnet_cidr" {
14+
description = "CIDR block for Virtual Network"
15+
type = string
16+
default = "10.0.0.0/16"
17+
}
18+
19+
variable "service_cidr" {
20+
description = "CIDR block for Kubernetes services"
21+
type = string
22+
default = "10.1.0.0/16"
23+
}
24+
25+
variable "dns_service_ip" {
26+
description = "DNS service IP address (must be within service_cidr)"
27+
type = string
28+
default = "10.1.0.10"
29+
}
30+
31+
variable "kubernetes_version" {
32+
description = "Kubernetes version for AKS"
33+
type = string
34+
default = "1.31"
35+
}
36+
37+
variable "node_count" {
38+
description = "Initial number of nodes"
39+
type = number
40+
default = 2
41+
}
42+
43+
variable "min_node_count" {
44+
description = "Minimum number of nodes for autoscaling"
45+
type = number
46+
default = 1
47+
}
48+
49+
variable "max_node_count" {
50+
description = "Maximum number of nodes for autoscaling"
51+
type = number
52+
default = 3
53+
}
54+
55+
variable "node_size" {
56+
description = "Size of the nodes"
57+
type = string
58+
default = "Standard_D2_v3"
59+
}
60+
61+
variable "tags" {
62+
description = "Tags to apply to all resources"
63+
type = map(string)
64+
default = {
65+
Environment = "dev"
66+
Project = "fullStack-cluster"
67+
ManagedBy = "terraform"
68+
}
69+
}

0 commit comments

Comments
 (0)