├── LICENSE ├── README.md ├── azure └── aks-aad-custom-vnet │ ├── aks.tf │ ├── datasource.tf │ ├── kubernetes.tf │ ├── main.tf │ ├── output.tf │ ├── variables.tf │ └── versions.tf ├── cnaf-demo └── aks.tf ├── conditions-for-each-demo ├── main.tf └── modules │ └── storage │ ├── main.tf │ ├── outputs.tf │ └── variables.tf └── modules ├── acr ├── main.tf ├── outputs.tf └── variables.tf ├── aks-windows ├── main.tf ├── outputs.tf └── variables.tf ├── aks ├── cluster-upgrade-fix.sh ├── main.tf ├── outputs.tf └── variables.tf ├── diagnostic_logs ├── main.tf ├── outputs.tf └── variables.tf ├── kubelogin └── main.tf ├── log_analytics ├── main.tf ├── outputs.tf └── variables.tf ├── microsoft_defender_continuous_export ├── main.tf ├── providers.tf └── variables.tf ├── resource_group ├── main.tf ├── outputs.tf └── variables.tf ├── storage_account ├── main.tf ├── outputs.tf └── variables.tf └── virtual_network ├── main.tf ├── outputs.tf └── variables.tf /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Daniel Neumann 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # terraform 2 | 3 | Terraform modules 4 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/aks.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_resource_group" "k8s" { 2 | lifecycle { 3 | prevent_destroy = true 4 | } 5 | 6 | name = var.resource_group_name 7 | location = var.location 8 | } 9 | 10 | resource "azurerm_kubernetes_cluster" "k8s" { 11 | name = var.cluster_name 12 | location = azurerm_resource_group.k8s.location 13 | resource_group_name = azurerm_resource_group.k8s.name 14 | dns_prefix = var.dns_prefix 15 | kubernetes_version = var.kubernetes_version 16 | node_resource_group = var.cluster_name 17 | 18 | linux_profile { 19 | admin_username = var.admin_username 20 | 21 | ssh_key { 22 | key_data = data.azurerm_key_vault_secret.ssh.value 23 | } 24 | } 25 | 26 | agent_pool_profile { 27 | name = "nodepool1" 28 | count = var.agent_count 29 | vm_size = var.vm_size 30 | type = var.vm_type 31 | availability_zones = var.zones 32 | max_pods = var.max_pods 33 | os_type = "Linux" 34 | os_disk_size_gb = var.os_disk_size_gb 35 | vnet_subnet_id = var.vnet_subnet_id 36 | } 37 | 38 | service_principal { 39 | client_id = data.azurerm_key_vault_secret.spid.value 40 | client_secret = data.azurerm_key_vault_secret.spsecret.value 41 | } 42 | 43 | role_based_access_control { 44 | enabled = true 45 | 46 | azure_active_directory { 47 | client_app_id = data.azurerm_key_vault_secret.aadclient.value 48 | server_app_id = data.azurerm_key_vault_secret.aadserver.value 49 | server_app_secret = data.azurerm_key_vault_secret.aadserversecret.value 50 | tenant_id = data.azurerm_key_vault_secret.aadtenant.value 51 | } 52 | } 53 | 54 | addon_profile { 55 | oms_agent { 56 | enabled = true 57 | log_analytics_workspace_id = var.log_analytics_workspace_id 58 | } 59 | } 60 | 61 | network_profile { 62 | load_balancer_sku = var.lb_sku 63 | network_plugin = var.network_plugin 64 | network_policy = var.network_policy 65 | dns_service_ip = var.dns_service_ip 66 | docker_bridge_cidr = var.docker_bridge_cidr 67 | service_cidr = var.service_cidr 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/datasource.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_key_vault" "k8s" { 2 | name = var.key_vault_name 3 | resource_group_name = var.key_vault_resource_group_name 4 | } 5 | 6 | data "azurerm_key_vault_secret" "ssh" { 7 | name = "sshpublic" 8 | key_vault_id = data.azurerm_key_vault.k8s.id 9 | } 10 | 11 | data "azurerm_key_vault_secret" "spid" { 12 | name = "aksspid" 13 | key_vault_id = data.azurerm_key_vault.k8s.id 14 | } 15 | 16 | data "azurerm_key_vault_secret" "spsecret" { 17 | name = "aksspsecret" 18 | key_vault_id = data.azurerm_key_vault.k8s.id 19 | } 20 | 21 | data "azurerm_key_vault_secret" "aadclient" { 22 | name = "aadClientAppId" 23 | key_vault_id = data.azurerm_key_vault.k8s.id 24 | } 25 | 26 | data "azurerm_key_vault_secret" "aadserver" { 27 | name = "aadServerAppId" 28 | key_vault_id = data.azurerm_key_vault.k8s.id 29 | } 30 | 31 | data "azurerm_key_vault_secret" "aadserversecret" { 32 | name = "aadServerAppSecret" 33 | key_vault_id = data.azurerm_key_vault.k8s.id 34 | } 35 | 36 | data "azurerm_key_vault_secret" "aadtenant" { 37 | name = "aadTenantId" 38 | key_vault_id = data.azurerm_key_vault.k8s.id 39 | } 40 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/kubernetes.tf: -------------------------------------------------------------------------------- 1 | resource "kubernetes_cluster_role_binding" "k8s" { 2 | metadata { 3 | name = var.cluster_role_binding_name 4 | } 5 | 6 | role_ref { 7 | api_group = "rbac.authorization.k8s.io" 8 | kind = "ClusterRole" 9 | name = "cluster-admin" 10 | } 11 | 12 | subject { 13 | api_group = "rbac.authorization.k8s.io" 14 | kind = "Group" 15 | name = var.aad_group_guid 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/main.tf: -------------------------------------------------------------------------------- 1 | provider "azurerm" { 2 | } 3 | 4 | provider "kubernetes" { 5 | host = azurerm_kubernetes_cluster.k8s.kube_admin_config[0].host 6 | username = azurerm_kubernetes_cluster.k8s.kube_admin_config[0].username 7 | password = azurerm_kubernetes_cluster.k8s.kube_admin_config[0].password 8 | client_certificate = base64decode( 9 | azurerm_kubernetes_cluster.k8s.kube_admin_config[0].client_certificate, 10 | ) 11 | client_key = base64decode( 12 | azurerm_kubernetes_cluster.k8s.kube_admin_config[0].client_key, 13 | ) 14 | cluster_ca_certificate = base64decode( 15 | azurerm_kubernetes_cluster.k8s.kube_admin_config[0].cluster_ca_certificate, 16 | ) 17 | } 18 | 19 | terraform { 20 | backend "remote" { 21 | organization = "REDACTED" 22 | 23 | workspaces { 24 | name = "aks_prod_terraform" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/output.tf: -------------------------------------------------------------------------------- 1 | output "fqdn" { 2 | value = azurerm_kubernetes_cluster.k8s.fqdn 3 | } 4 | 5 | output "id" { 6 | value = azurerm_kubernetes_cluster.k8s.id 7 | } 8 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/variables.tf: -------------------------------------------------------------------------------- 1 | variable "log_analytics_workspace_id" { 2 | default = "/subscriptions/REDACTED/resourcegroups/operations-management/providers/microsoft.operationalinsights/workspaces/REDACTED" 3 | } 4 | 5 | variable "kubernetes_version" { 6 | default = "1.14.6" 7 | } 8 | 9 | variable "key_vault_name" { 10 | default = "REDACTED" 11 | } 12 | 13 | variable "key_vault_resource_group_name" { 14 | default = "REDACTED" 15 | } 16 | 17 | variable "agent_count" { 18 | default = 3 19 | } 20 | 21 | variable "vm_size" { 22 | default = "Standard_D2_v3" 23 | } 24 | 25 | variable "admin_username" { 26 | default = "REDACTED" 27 | } 28 | 29 | variable "dns_prefix" { 30 | default = "aks" 31 | } 32 | 33 | variable "cluster_name" { 34 | default = "aks" 35 | } 36 | 37 | variable "resource_group_name" { 38 | default = "aks" 39 | } 40 | 41 | variable "location" { 42 | default = "North Europe" 43 | } 44 | 45 | variable "max_pods" { 46 | default = 250 47 | } 48 | 49 | variable "os_disk_size_gb" { 50 | default = 128 51 | } 52 | 53 | variable "vm_type" { 54 | default = "VirtualMachineScaleSets" 55 | } 56 | 57 | variable "zones" { 58 | default = ["1", "2", "3"] 59 | } 60 | 61 | variable "vnet_subnet_id" { 62 | default = "/subscriptions/REDACTED/resourceGroups/aks/providers/Microsoft.Network/virtualNetworks/aks-vnet/subnets/aks-subnet" 63 | } 64 | 65 | variable "network_plugin" { 66 | default = "azure" 67 | } 68 | 69 | variable "network_policy" { 70 | default = "calico" 71 | } 72 | 73 | variable "lb_sku" { 74 | default = "standard" 75 | } 76 | 77 | variable "dns_service_ip" { 78 | default = "10.0.0.10" 79 | } 80 | 81 | variable "docker_bridge_cidr" { 82 | default = "172.17.0.1/16" 83 | } 84 | 85 | variable "service_cidr" { 86 | default = "10.0.0.0/16" 87 | } 88 | 89 | variable "cluster_role_binding_name" { 90 | default = "aks-cluster-admins" 91 | } 92 | 93 | variable "aad_group_guid" { 94 | default = "REDACTED" 95 | } 96 | -------------------------------------------------------------------------------- /azure/aks-aad-custom-vnet/versions.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_version = ">= 0.12" 3 | } 4 | -------------------------------------------------------------------------------- /cnaf-demo/aks.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_resource_group" "k8s" { 2 | name = "${var.resource_group_name}" 3 | location = "${var.location}" 4 | } 5 | 6 | resource "azurerm_kubernetes_cluster" "k8s" { 7 | name = "${var.cluster_name}" 8 | location = "${azurerm_resource_group.k8s.location}" 9 | resource_group_name = "${azurerm_resource_group.k8s.name}" 10 | dns_prefix = "${var.dns_prefix}" 11 | kubernetes_version = "${var.kubernetes_version}" 12 | 13 | linux_profile { 14 | admin_username = "${var.admin_username}" 15 | 16 | ssh_key { 17 | key_data = "${data.azurerm_key_vault_secret.ssh.value}" 18 | } 19 | } 20 | 21 | agent_pool_profile { 22 | name = "agentpool" 23 | count = "${var.agent_count}" 24 | vm_size = "${var.vm_size}" 25 | max_pods = "${var.max_pods}" 26 | os_type = "Linux" 27 | os_disk_size_gb = "${var.os_disk_size_gb}" 28 | } 29 | 30 | service_principal { 31 | client_id = "${data.azurerm_key_vault_secret.spid.value}" 32 | client_secret = "${data.azurerm_key_vault_secret.spsecret.value}" 33 | } 34 | 35 | role_based_access_control { 36 | enabled = true 37 | 38 | azure_active_directory { 39 | client_app_id = "${data.azurerm_key_vault_secret.aadclient.value}" 40 | server_app_id = "${data.azurerm_key_vault_secret.aadserver.value}" 41 | server_app_secret = "${data.azurerm_key_vault_secret.aadserversecret.value}" 42 | tenant_id = "${data.azurerm_key_vault_secret.aadtenant.value}" 43 | } 44 | } 45 | 46 | addon_profile { 47 | oms_agent { 48 | enabled = true 49 | log_analytics_workspace_id = "${var.log_analytics_workspace_id}" 50 | } 51 | } 52 | } 53 | 54 | resource "kubernetes_cluster_role_binding" "k8s" { 55 | 56 | metadata { 57 | name = "${var.cluster_role_binding_name}" 58 | } 59 | 60 | role_ref { 61 | api_group = "rbac.authorization.k8s.io" 62 | kind = "ClusterRole" 63 | name = "cluster-admin" 64 | } 65 | 66 | subject { 67 | api_group = "rbac.authorization.k8s.io" 68 | kind = "Group" 69 | name = "${var.aad_group_guid}" 70 | } 71 | } 72 | 73 | data "azurerm_key_vault_secret" "ssh" { 74 | name = "sshpublic" 75 | vault_uri = "${var.vault_uri}" 76 | } 77 | 78 | data "azurerm_key_vault_secret" "spid" { 79 | name = "aksspid" 80 | vault_uri = "${var.vault_uri}" 81 | } 82 | 83 | data "azurerm_key_vault_secret" "spsecret" { 84 | name = "aksspsecret" 85 | vault_uri = "${var.vault_uri}" 86 | } 87 | 88 | data "azurerm_key_vault_secret" "aadclient" { 89 | name = "aadClientAppId" 90 | vault_uri = "${var.vault_uri}" 91 | } 92 | 93 | data "azurerm_key_vault_secret" "aadserver" { 94 | name = "aadServerAppId" 95 | vault_uri = "${var.vault_uri}" 96 | } 97 | 98 | data "azurerm_key_vault_secret" "aadserversecret" { 99 | name = "aadServerAppSecret" 100 | vault_uri = "${var.vault_uri}" 101 | } 102 | 103 | data "azurerm_key_vault_secret" "aadtenant" { 104 | name = "aadTenantId" 105 | vault_uri = "${var.vault_uri}" 106 | } 107 | -------------------------------------------------------------------------------- /conditions-for-each-demo/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | source = "hashicorp/azurerm" 5 | version = "3.9.0" 6 | } 7 | } 8 | } 9 | 10 | provider "azurerm" { 11 | features {} 12 | } 13 | 14 | module "storage1" { 15 | source = "./modules/storage" 16 | resource_group_name = "rg12345" 17 | location = "northeurope" 18 | storage_account_name = "azcdmdn12345" 19 | lock = true 20 | } 21 | 22 | module "storage2" { 23 | source = "./modules/storage" 24 | resource_group = false 25 | resource_group_name = module.storage1.resource_group_name 26 | location = "westeurope" 27 | storage_account_name = "azcdmdn67890" 28 | identity = true 29 | } 30 | 31 | output "storage_account_id_1" { 32 | value = module.storage1.storage_account_id 33 | } 34 | 35 | output "storage_account_id_2" { 36 | value = module.storage2.storage_account_id 37 | } 38 | 39 | output "identity_2" { 40 | value = module.storage2.identity 41 | } 42 | -------------------------------------------------------------------------------- /conditions-for-each-demo/modules/storage/main.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_resource_group" "rg" { 2 | for_each = var.resource_group == true ? toset([var.resource_group_name]) : toset([]) 3 | name = var.resource_group_name 4 | location = var.location 5 | } 6 | 7 | resource "azurerm_management_lock" "lock" { 8 | for_each = var.lock == true && var.resource_group == true ? toset([var.resource_group_name]) : toset([]) 9 | name = "rg-level" 10 | scope = azurerm_resource_group.rg[var.resource_group_name].id 11 | lock_level = "CanNotDelete" 12 | } 13 | 14 | resource "azurerm_storage_account" "storage" { 15 | name = var.storage_account_name 16 | resource_group_name = var.resource_group == true ? azurerm_resource_group.rg[var.resource_group_name].name : var.resource_group_name 17 | location = var.resource_group == true ? azurerm_resource_group.rg[var.resource_group_name].location : var.location 18 | account_tier = "Standard" 19 | account_replication_type = "LRS" 20 | 21 | dynamic "identity" { 22 | for_each = var.identity == true ? toset([var.storage_account_name]) : toset([]) 23 | content { 24 | type = "SystemAssigned" 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /conditions-for-each-demo/modules/storage/outputs.tf: -------------------------------------------------------------------------------- 1 | output "resource_group_name" { 2 | value = var.resource_group == true ? azurerm_resource_group.rg[var.resource_group_name].name : null 3 | } 4 | 5 | output "storage_account_id" { 6 | value = azurerm_storage_account.storage.id 7 | } 8 | 9 | output "identity" { 10 | value = var.identity == true ? azurerm_storage_account.storage.identity.0.principal_id : null 11 | } 12 | -------------------------------------------------------------------------------- /conditions-for-each-demo/modules/storage/variables.tf: -------------------------------------------------------------------------------- 1 | variable "resource_group" { 2 | type = bool 3 | default = true 4 | } 5 | 6 | variable "resource_group_name" {} 7 | 8 | variable "location" {} 9 | 10 | variable "lock" { 11 | type = bool 12 | default = false 13 | } 14 | 15 | variable "storage_account_name" {} 16 | 17 | variable "identity" { 18 | type = bool 19 | default = false 20 | } 21 | -------------------------------------------------------------------------------- /modules/acr/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_container_registry" "acr" { 12 | name = var.name 13 | location = var.location 14 | resource_group_name = var.resource_group_name 15 | sku = var.sku 16 | admin_enabled = var.admin 17 | georeplication_locations = var.geo_replication 18 | } 19 | -------------------------------------------------------------------------------- /modules/acr/outputs.tf: -------------------------------------------------------------------------------- 1 | output "login_server" { 2 | value = azurerm_container_registry.acr.login_server 3 | } 4 | 5 | output "id" { 6 | value = azurerm_container_registry.acr.id 7 | } 8 | -------------------------------------------------------------------------------- /modules/acr/variables.tf: -------------------------------------------------------------------------------- 1 | variable "resource_group_name" { 2 | description = "Name of the ACR resource group" 3 | type = string 4 | } 5 | 6 | variable "location" { 7 | description = "Azure region of the ACR" 8 | type = string 9 | } 10 | 11 | variable "name" { 12 | description = "The name of the ACR" 13 | type = string 14 | } 15 | 16 | variable "sku" { 17 | description = "The SKU of the ACR" 18 | type = string 19 | } 20 | 21 | variable "admin" { 22 | description = "Admin access enabled" 23 | type = bool 24 | } 25 | 26 | variable "geo_replication" { 27 | description = "Azure regions for ACR geo replication" 28 | type = list(string) 29 | } 30 | -------------------------------------------------------------------------------- /modules/aks-windows/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = "~> 2.4.0" 6 | } 7 | 8 | provider "azuread" { 9 | version = ">= 0.6" 10 | } 11 | 12 | provider "kubernetes" { 13 | version = ">= 1.9" 14 | 15 | host = azurerm_kubernetes_cluster.aks.kube_admin_config[0].host 16 | client_certificate = base64decode( 17 | azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_certificate, 18 | ) 19 | client_key = base64decode( 20 | azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_key, 21 | ) 22 | cluster_ca_certificate = base64decode( 23 | azurerm_kubernetes_cluster.aks.kube_admin_config[0].cluster_ca_certificate, 24 | ) 25 | } 26 | 27 | provider "random" { 28 | version = ">= 2.2" 29 | } 30 | 31 | provider "null" {} 32 | ######################## 33 | # Data sources section # 34 | ######################## 35 | data "azuread_group" "aks" { 36 | name = var.aad_group_name 37 | } 38 | ##################### 39 | # Resources section # 40 | ##################### 41 | resource "random_password" "aks" { 42 | length = 20 43 | special = true 44 | } 45 | 46 | resource "azuread_application" "aks" { 47 | name = var.name 48 | } 49 | 50 | resource "azuread_service_principal" "aks" { 51 | application_id = azuread_application.aks.application_id 52 | } 53 | 54 | resource "azuread_service_principal_password" "aks" { 55 | service_principal_id = azuread_service_principal.aks.id 56 | value = random_password.aks.result 57 | end_date_relative = "8760h" 58 | } 59 | 60 | resource "azurerm_kubernetes_cluster" "aks" { 61 | lifecycle { 62 | ignore_changes = [ 63 | default_node_pool[0].node_count 64 | ] 65 | } 66 | 67 | name = var.name 68 | location = var.location 69 | resource_group_name = var.resource_group_name 70 | dns_prefix = var.name 71 | kubernetes_version = var.kubernetes_version 72 | node_resource_group = "${var.name}-worker" 73 | api_server_authorized_ip_ranges = var.api_auth_ips 74 | 75 | windows_profile { 76 | admin_username = "azureuser" 77 | admin_password = random_password.aks.result 78 | } 79 | 80 | default_node_pool { 81 | name = substr(var.default_node_pool.name, 0, 12) 82 | node_count = var.default_node_pool.node_count 83 | vm_size = var.default_node_pool.vm_size 84 | type = "VirtualMachineScaleSets" 85 | availability_zones = var.default_node_pool.zones 86 | max_pods = 250 87 | os_disk_size_gb = 128 88 | vnet_subnet_id = var.vnet_subnet_id 89 | node_taints = var.default_node_pool.taints 90 | enable_auto_scaling = var.default_node_pool.cluster_auto_scaling 91 | min_count = var.default_node_pool.cluster_auto_scaling_min_count 92 | max_count = var.default_node_pool.cluster_auto_scaling_max_count 93 | } 94 | 95 | service_principal { 96 | client_id = azuread_service_principal.aks.application_id 97 | client_secret = azuread_service_principal_password.aks.value 98 | } 99 | 100 | role_based_access_control { 101 | enabled = true 102 | 103 | azure_active_directory { 104 | client_app_id = var.aad_client_application_id 105 | server_app_id = var.aad_server_application_id 106 | server_app_secret = var.aad_server_application_secret 107 | tenant_id = var.aad_tenant_id 108 | } 109 | } 110 | 111 | addon_profile { 112 | oms_agent { 113 | enabled = true 114 | log_analytics_workspace_id = var.log_analytics_workspace_id 115 | } 116 | kube_dashboard { 117 | enabled = false 118 | } 119 | azure_policy { 120 | enabled = false 121 | } 122 | } 123 | 124 | network_profile { 125 | load_balancer_sku = "standard" 126 | network_plugin = "azure" 127 | network_policy = "calico" 128 | dns_service_ip = "10.0.0.10" 129 | docker_bridge_cidr = "172.17.0.1/16" 130 | service_cidr = "10.0.0.0/16" 131 | } 132 | } 133 | 134 | resource "null_resource" "aks" { 135 | triggers = { 136 | aks_kubernetes_version = azurerm_kubernetes_cluster.aks.kubernetes_version 137 | } 138 | 139 | provisioner "local-exec" { 140 | command = "./cluster-upgrade-fix.sh ${var.name} ${var.resource_group_name}" 141 | working_dir = path.module 142 | } 143 | } 144 | 145 | resource "azurerm_kubernetes_cluster_node_pool" "aks" { 146 | lifecycle { 147 | ignore_changes = [ 148 | node_count 149 | ] 150 | } 151 | 152 | for_each = var.additional_node_pools 153 | 154 | kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id 155 | name = each.value.node_os == "Windows" ? substr(each.key, 0, 6) : substr(each.key, 0, 12) 156 | node_count = each.value.node_count 157 | vm_size = each.value.vm_size 158 | availability_zones = each.value.zones 159 | max_pods = 250 160 | os_disk_size_gb = 128 161 | os_type = each.value.node_os 162 | vnet_subnet_id = var.vnet_subnet_id 163 | node_taints = each.value.taints 164 | enable_auto_scaling = each.value.cluster_auto_scaling 165 | min_count = each.value.cluster_auto_scaling_min_count 166 | max_count = each.value.cluster_auto_scaling_max_count 167 | } 168 | 169 | resource "azurerm_role_assignment" "aks" { 170 | scope = azurerm_kubernetes_cluster.aks.id 171 | role_definition_name = "Monitoring Metrics Publisher" 172 | principal_id = azuread_service_principal.aks.id 173 | } 174 | 175 | resource "azurerm_role_assignment" "aks_subnet" { 176 | scope = var.vnet_subnet_id 177 | role_definition_name = "Network Contributor" 178 | principal_id = azuread_service_principal.aks.id 179 | } 180 | 181 | resource "azurerm_role_assignment" "aks_acr" { 182 | scope = var.container_registry_id 183 | role_definition_name = "AcrPull" 184 | principal_id = azuread_service_principal.aks.id 185 | } 186 | 187 | resource "kubernetes_cluster_role_binding" "aks" { 188 | metadata { 189 | name = "aks-cluster-admins" 190 | } 191 | 192 | role_ref { 193 | api_group = "rbac.authorization.k8s.io" 194 | kind = "ClusterRole" 195 | name = "cluster-admin" 196 | } 197 | 198 | subject { 199 | api_group = "rbac.authorization.k8s.io" 200 | kind = "Group" 201 | name = data.azuread_group.aks.id 202 | } 203 | } 204 | -------------------------------------------------------------------------------- /modules/aks-windows/outputs.tf: -------------------------------------------------------------------------------- 1 | output "fqdn" { 2 | value = azurerm_kubernetes_cluster.aks.fqdn 3 | } 4 | 5 | output "name" { 6 | value = azurerm_kubernetes_cluster.aks.name 7 | } 8 | 9 | output "id" { 10 | value = azurerm_kubernetes_cluster.aks.id 11 | } 12 | 13 | output "sp_id" { 14 | value = azuread_service_principal.aks.id 15 | } 16 | 17 | output "host" { 18 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].host 19 | } 20 | 21 | output "client_certificate" { 22 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_certificate 23 | sensitive = true 24 | } 25 | 26 | output "client_key" { 27 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_key 28 | sensitive = true 29 | } 30 | 31 | output "cluster_ca_certificate" { 32 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].cluster_ca_certificate 33 | sensitive = true 34 | } 35 | -------------------------------------------------------------------------------- /modules/aks-windows/variables.tf: -------------------------------------------------------------------------------- 1 | variable "container_registry_id" { 2 | description = "Resource id of the ACR" 3 | type = string 4 | } 5 | 6 | variable "log_analytics_workspace_id" { 7 | description = "Resource id of the Log Analytics workspace" 8 | type = string 9 | } 10 | 11 | variable "kubernetes_version" { 12 | description = "Kubernetes version" 13 | type = string 14 | } 15 | 16 | variable "name" { 17 | description = "The name of the AKS cluster" 18 | type = string 19 | } 20 | 21 | variable "resource_group_name" { 22 | description = "Name of the AKS cluster resource group" 23 | type = string 24 | } 25 | 26 | variable "location" { 27 | description = "Azure region of the AKS cluster" 28 | type = string 29 | } 30 | 31 | variable "vnet_subnet_id" { 32 | description = "Resource id of the Virtual Network subnet" 33 | type = string 34 | } 35 | 36 | variable "aad_client_application_id" { 37 | description = "Client application id for AAD integration" 38 | type = string 39 | } 40 | 41 | variable "aad_server_application_id" { 42 | description = "Server application id for AAD integration" 43 | type = string 44 | } 45 | 46 | variable "aad_server_application_secret" { 47 | description = "Server application secret for AAD integration" 48 | type = string 49 | } 50 | 51 | variable "aad_tenant_id" { 52 | description = "AAD tenant id for AAD integration" 53 | type = string 54 | } 55 | 56 | variable "aad_group_name" { 57 | description = "Name of the Azure AD group for cluster-admin access" 58 | type = string 59 | } 60 | 61 | variable "api_auth_ips" { 62 | description = "Whitelist of IP addresses that are allowed to access the AKS Master Control Plane API" 63 | type = list(string) 64 | } 65 | 66 | variable "default_node_pool" { 67 | description = "The object to configure the default node pool with number of worker nodes, worker node VM size and Availability Zones." 68 | type = object({ 69 | name = string 70 | node_count = number 71 | vm_size = string 72 | zones = list(string) 73 | taints = list(string) 74 | cluster_auto_scaling = bool 75 | cluster_auto_scaling_min_count = number 76 | cluster_auto_scaling_max_count = number 77 | }) 78 | } 79 | 80 | variable "additional_node_pools" { 81 | description = "The map object to configure one or several additional node pools with number of worker nodes, worker node VM size and Availability Zones." 82 | type = map(object({ 83 | node_count = number 84 | vm_size = string 85 | zones = list(string) 86 | node_os = string 87 | taints = list(string) 88 | cluster_auto_scaling = bool 89 | cluster_auto_scaling_min_count = number 90 | cluster_auto_scaling_max_count = number 91 | })) 92 | } 93 | -------------------------------------------------------------------------------- /modules/aks/cluster-upgrade-fix.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CLUSTER_NAME=$1 4 | RESOURCE_GROUP=$2 5 | 6 | CLUSTER_VERSION=$(az aks show --name $CLUSTER_NAME --resource-group $RESOURCE_GROUP | jq -r .kubernetesVersion) 7 | NODE_POOLS=$(az aks nodepool list --cluster-name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --query '[].name' -o tsv) 8 | 9 | for NODE_POOL in $NODE_POOLS; do 10 | NODE_VERSION=$(az aks nodepool show --cluster-name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --name $NODE_POOL | jq -r .orchestratorVersion) 11 | if [[ $CLUSTER_VERSION != $NODE_VERSION ]]; then 12 | az aks nodepool upgrade --kubernetes-version $CLUSTER_VERSION --cluster-name $CLUSTER_NAME --resource-group $RESOURCE_GROUP --name $NODE_POOL --verbose 13 | fi 14 | done -------------------------------------------------------------------------------- /modules/aks/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.21.0" 6 | features {} 7 | } 8 | 9 | provider "azuread" { 10 | version = ">= 0.6" 11 | } 12 | ######################## 13 | # Data sources section # 14 | ######################## 15 | data "azuread_group" "aks" { 16 | name = var.aad_group_name 17 | } 18 | ##################### 19 | # Resources section # 20 | ##################### 21 | resource "azurerm_kubernetes_cluster" "aks" { 22 | lifecycle { 23 | ignore_changes = [ 24 | default_node_pool[0].node_count 25 | ] 26 | } 27 | 28 | name = var.name 29 | location = var.location 30 | resource_group_name = var.resource_group_name 31 | dns_prefix = var.name 32 | kubernetes_version = var.kubernetes_version 33 | node_resource_group = "${var.name}-worker" 34 | private_cluster_enabled = var.private_cluster 35 | sku_tier = var.sla_sku 36 | api_server_authorized_ip_ranges = var.api_auth_ips 37 | 38 | default_node_pool { 39 | name = substr(var.default_node_pool.name, 0, 12) 40 | orchestrator_version = var.kubernetes_version 41 | node_count = var.default_node_pool.node_count 42 | vm_size = var.default_node_pool.vm_size 43 | type = "VirtualMachineScaleSets" 44 | availability_zones = var.default_node_pool.zones 45 | max_pods = 250 46 | os_disk_size_gb = 128 47 | vnet_subnet_id = var.vnet_subnet_id 48 | node_labels = var.default_node_pool.labels 49 | node_taints = var.default_node_pool.taints 50 | enable_auto_scaling = var.default_node_pool.cluster_auto_scaling 51 | min_count = var.default_node_pool.cluster_auto_scaling_min_count 52 | max_count = var.default_node_pool.cluster_auto_scaling_max_count 53 | enable_node_public_ip = false 54 | } 55 | 56 | identity { 57 | type = "SystemAssigned" 58 | } 59 | 60 | role_based_access_control { 61 | enabled = true 62 | 63 | azure_active_directory { 64 | managed = true 65 | admin_group_object_ids = [ 66 | data.azuread_group.aks.id 67 | ] 68 | } 69 | } 70 | 71 | addon_profile { 72 | oms_agent { 73 | enabled = var.addons.oms_agent 74 | log_analytics_workspace_id = var.log_analytics_workspace_id 75 | } 76 | kube_dashboard { 77 | enabled = var.addons.kubernetes_dashboard 78 | } 79 | azure_policy { 80 | enabled = var.addons.azure_policy 81 | } 82 | } 83 | 84 | network_profile { 85 | load_balancer_sku = "standard" 86 | outbound_type = "loadBalancer" 87 | network_plugin = "azure" 88 | network_policy = "calico" 89 | dns_service_ip = "10.0.0.10" 90 | docker_bridge_cidr = "172.17.0.1/16" 91 | service_cidr = "10.0.0.0/16" 92 | } 93 | } 94 | 95 | resource "azurerm_kubernetes_cluster_node_pool" "aks" { 96 | lifecycle { 97 | ignore_changes = [ 98 | node_count 99 | ] 100 | } 101 | 102 | for_each = var.additional_node_pools 103 | 104 | kubernetes_cluster_id = azurerm_kubernetes_cluster.aks.id 105 | name = each.value.node_os == "Windows" ? substr(each.key, 0, 6) : substr(each.key, 0, 12) 106 | orchestrator_version = var.kubernetes_version 107 | node_count = each.value.node_count 108 | vm_size = each.value.vm_size 109 | availability_zones = each.value.zones 110 | max_pods = 250 111 | os_disk_size_gb = 128 112 | os_type = each.value.node_os 113 | vnet_subnet_id = var.vnet_subnet_id 114 | node_labels = each.value.labels 115 | node_taints = each.value.taints 116 | enable_auto_scaling = each.value.cluster_auto_scaling 117 | min_count = each.value.cluster_auto_scaling_min_count 118 | max_count = each.value.cluster_auto_scaling_max_count 119 | enable_node_public_ip = false 120 | } 121 | 122 | resource "azurerm_role_assignment" "aks" { 123 | scope = azurerm_kubernetes_cluster.aks.id 124 | role_definition_name = "Monitoring Metrics Publisher" 125 | principal_id = azurerm_kubernetes_cluster.aks.addon_profile[0].oms_agent[0].oms_agent_identity[0].object_id 126 | } 127 | 128 | resource "azurerm_role_assignment" "aks_subnet" { 129 | scope = var.vnet_subnet_id 130 | role_definition_name = "Network Contributor" 131 | principal_id = azurerm_kubernetes_cluster.aks.identity[0].principal_id 132 | } 133 | 134 | resource "azurerm_role_assignment" "aks_acr" { 135 | scope = var.container_registry_id 136 | role_definition_name = "AcrPull" 137 | principal_id = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id 138 | } 139 | -------------------------------------------------------------------------------- /modules/aks/outputs.tf: -------------------------------------------------------------------------------- 1 | output "fqdn" { 2 | value = azurerm_kubernetes_cluster.aks.fqdn 3 | } 4 | 5 | output "name" { 6 | value = azurerm_kubernetes_cluster.aks.name 7 | } 8 | 9 | output "id" { 10 | value = azurerm_kubernetes_cluster.aks.id 11 | } 12 | 13 | output "mi_principal_id" { 14 | value = azurerm_kubernetes_cluster.aks.identity[0].principal_id 15 | } 16 | 17 | output "mi_tenant_id" { 18 | value = azurerm_kubernetes_cluster.aks.identity[0].tenant_id 19 | } 20 | 21 | output "kubelet_client_id" { 22 | value = azurerm_kubernetes_cluster.aks.kubelet_identity[0].client_id 23 | } 24 | 25 | output "kubelet_object_id" { 26 | value = azurerm_kubernetes_cluster.aks.kubelet_identity[0].object_id 27 | } 28 | 29 | output "kubelet_user_assigned_identity_id" { 30 | value = azurerm_kubernetes_cluster.aks.kubelet_identity[0].user_assigned_identity_id 31 | } 32 | 33 | output "host" { 34 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].host 35 | } 36 | 37 | output "client_certificate" { 38 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_certificate 39 | sensitive = true 40 | } 41 | 42 | output "client_key" { 43 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].client_key 44 | sensitive = true 45 | } 46 | 47 | output "cluster_ca_certificate" { 48 | value = azurerm_kubernetes_cluster.aks.kube_admin_config[0].cluster_ca_certificate 49 | sensitive = true 50 | } 51 | -------------------------------------------------------------------------------- /modules/aks/variables.tf: -------------------------------------------------------------------------------- 1 | variable "container_registry_id" { 2 | description = "Resource id of the ACR" 3 | type = string 4 | } 5 | 6 | variable "log_analytics_workspace_id" { 7 | description = "Resource id of the Log Analytics workspace" 8 | type = string 9 | } 10 | 11 | variable "kubernetes_version" { 12 | description = "Kubernetes version" 13 | type = string 14 | } 15 | 16 | variable "name" { 17 | description = "The name of the AKS cluster" 18 | type = string 19 | } 20 | 21 | variable "resource_group_name" { 22 | description = "Name of the AKS cluster resource group" 23 | type = string 24 | } 25 | 26 | variable "location" { 27 | description = "Azure region of the AKS cluster" 28 | type = string 29 | } 30 | 31 | variable "vnet_subnet_id" { 32 | description = "Resource id of the Virtual Network subnet" 33 | type = string 34 | } 35 | 36 | variable "aad_group_name" { 37 | description = "Name of the Azure AD group for cluster-admin access" 38 | type = string 39 | } 40 | 41 | variable "api_auth_ips" { 42 | description = "Whitelist of IP addresses that are allowed to access the AKS Master Control Plane API" 43 | type = list(string) 44 | } 45 | 46 | variable "private_cluster" { 47 | description = "Deploy an AKS cluster without a public accessible API endpoint." 48 | type = bool 49 | } 50 | 51 | variable "sla_sku" { 52 | description = "Define the SLA under which the managed master control plane of AKS is running." 53 | type = string 54 | } 55 | 56 | variable "default_node_pool" { 57 | description = "The object to configure the default node pool with number of worker nodes, worker node VM size and Availability Zones." 58 | type = object({ 59 | name = string 60 | node_count = number 61 | vm_size = string 62 | zones = list(string) 63 | labels = map(string) 64 | taints = list(string) 65 | cluster_auto_scaling = bool 66 | cluster_auto_scaling_min_count = number 67 | cluster_auto_scaling_max_count = number 68 | }) 69 | } 70 | 71 | variable "additional_node_pools" { 72 | description = "The map object to configure one or several additional node pools with number of worker nodes, worker node VM size and Availability Zones." 73 | type = map(object({ 74 | node_count = number 75 | vm_size = string 76 | zones = list(string) 77 | labels = map(string) 78 | taints = list(string) 79 | node_os = string 80 | cluster_auto_scaling = bool 81 | cluster_auto_scaling_min_count = number 82 | cluster_auto_scaling_max_count = number 83 | })) 84 | } 85 | 86 | variable "addons" { 87 | description = "Defines which addons will be activated." 88 | type = object({ 89 | oms_agent = bool 90 | kubernetes_dashboard = bool 91 | azure_policy = bool 92 | }) 93 | } 94 | -------------------------------------------------------------------------------- /modules/diagnostic_logs/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_monitor_diagnostic_setting" "diagnostic_logs" { 12 | name = var.name 13 | target_resource_id = var.target_resource_id 14 | storage_account_id = var.storage_account_id 15 | 16 | dynamic "log" { 17 | for_each = var.diagnostic_logs 18 | content { 19 | category = log.value 20 | enabled = true 21 | 22 | retention_policy { 23 | enabled = true 24 | days = var.retention 25 | } 26 | } 27 | } 28 | 29 | metric { 30 | category = "AllMetrics" 31 | enabled = false 32 | 33 | retention_policy { 34 | days = 0 35 | enabled = false 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /modules/diagnostic_logs/outputs.tf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/neumanndaniel/terraform/78a62804c5e4ce72d76d4d504913d4b51bd1c702/modules/diagnostic_logs/outputs.tf -------------------------------------------------------------------------------- /modules/diagnostic_logs/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "The name of the diagnostic logs configuration" 3 | type = string 4 | } 5 | 6 | variable "target_resource_id" { 7 | description = "The resource id of the target resource for which diagnostic logs will be enabled" 8 | type = string 9 | } 10 | 11 | variable "storage_account_id" { 12 | description = "The resource id of the Storage Account where the diagnostic logs will be stored" 13 | type = string 14 | } 15 | 16 | variable "diagnostic_logs" { 17 | description = "The list of diagnostic logs that should be enabled" 18 | type = list(string) 19 | } 20 | 21 | variable "retention" { 22 | description = "The retention time for all diagnostic logs" 23 | type = number 24 | } 25 | -------------------------------------------------------------------------------- /modules/kubelogin/main.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | source = "hashicorp/azurerm" 5 | version = "~>3.32.0" 6 | } 7 | azuread = { 8 | source = "hashicorp/azuread" 9 | version = "~>2.30.0" 10 | } 11 | kubernetes = { 12 | source = "hashicorp/kubernetes" 13 | version = "~>2.16.0" 14 | } 15 | } 16 | } 17 | 18 | provider "azurerm" { 19 | features {} 20 | } 21 | 22 | provider "azuread" {} 23 | 24 | data "azurerm_kubernetes_cluster" "aks" { 25 | name = "azure-kubernetes-service" 26 | resource_group_name = "azure-kubernetes-service" 27 | } 28 | 29 | data "azurerm_key_vault" "kv" { 30 | name = "azure-key-vault" 31 | resource_group_name = "azure-key-vault" 32 | } 33 | 34 | data "azurerm_key_vault_secret" "id" { 35 | key_vault_id = data.azurerm_key_vault.kv.id 36 | name = "kubernetes-id" 37 | } 38 | 39 | data "azurerm_key_vault_secret" "secret" { 40 | key_vault_id = data.azurerm_key_vault.kv.id 41 | name = "kubernetes-secret" 42 | } 43 | 44 | data "azuread_service_principal" "aks" { 45 | display_name = "Azure Kubernetes Service AAD Server" 46 | } 47 | 48 | provider "kubernetes" { 49 | host = data.azurerm_kubernetes_cluster.aks.kube_config[0].host 50 | cluster_ca_certificate = base64decode( 51 | data.azurerm_kubernetes_cluster.aks.kube_config[0].cluster_ca_certificate, 52 | ) 53 | exec { 54 | api_version = "client.authentication.k8s.io/v1beta1" 55 | command = "./modules/exec/kubelogin" 56 | args = [ 57 | "get-token", 58 | "--login", 59 | "spn", 60 | "--environment", 61 | "AzurePublicCloud", 62 | "--tenant-id", 63 | data.azurerm_kubernetes_cluster.aks.azure_active_directory_role_based_access_control[0].tenant_id, 64 | "--server-id", 65 | data.azuread_service_principal.aks.application_id, 66 | "--client-id", 67 | data.azurerm_key_vault_secret.id.value, 68 | "--client-secret", 69 | data.azurerm_key_vault_secret.secret.value 70 | ] 71 | } 72 | } 73 | 74 | data "kubernetes_namespace" "kube_system" { 75 | metadata { 76 | name = "kube-system" 77 | } 78 | } 79 | 80 | output "namespace_uid" { 81 | value = data.kubernetes_namespace.kube_system.metadata[0].uid 82 | } 83 | 84 | output "namespace_name" { 85 | value = data.kubernetes_namespace.kube_system.metadata[0].name 86 | } 87 | -------------------------------------------------------------------------------- /modules/log_analytics/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_log_analytics_workspace" "log_analytics" { 12 | name = var.name 13 | location = var.location 14 | resource_group_name = var.resource_group_name 15 | sku = var.sku 16 | retention_in_days = var.retention 17 | } 18 | 19 | resource "azurerm_log_analytics_solution" "log_analytics" { 20 | solution_name = "ContainerInsights" 21 | location = azurerm_log_analytics_workspace.log_analytics.location 22 | resource_group_name = azurerm_log_analytics_workspace.log_analytics.resource_group_name 23 | workspace_resource_id = azurerm_log_analytics_workspace.log_analytics.id 24 | workspace_name = azurerm_log_analytics_workspace.log_analytics.name 25 | 26 | plan { 27 | publisher = "Microsoft" 28 | product = "OMSGallery/ContainerInsights" 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /modules/log_analytics/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = azurerm_log_analytics_workspace.log_analytics.id 3 | } 4 | 5 | output "workspace_id" { 6 | value = azurerm_log_analytics_workspace.log_analytics.workspace_id 7 | } 8 | -------------------------------------------------------------------------------- /modules/log_analytics/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "The name of the Log Analytics workspace" 3 | type = string 4 | } 5 | 6 | variable "resource_group_name" { 7 | description = "Name of the Log Analytics workspace resource group" 8 | type = string 9 | } 10 | 11 | variable "location" { 12 | description = "Azure region of the Log Analytics workspace" 13 | type = string 14 | } 15 | 16 | variable "sku" { 17 | description = "The SKU of the Log Analytics workspace" 18 | type = string 19 | } 20 | 21 | variable "retention" { 22 | description = "The retention time of the Log Analytics workspace" 23 | type = number 24 | } 25 | -------------------------------------------------------------------------------- /modules/microsoft_defender_continuous_export/main.tf: -------------------------------------------------------------------------------- 1 | data "azurerm_client_config" "current" { 2 | } 3 | 4 | resource "azurerm_security_center_automation" "continuous_export" { 5 | name = var.name 6 | location = var.location 7 | resource_group_name = var.resource_group_name 8 | 9 | enabled = true 10 | 11 | action { 12 | type = var.type 13 | resource_id = var.type == "loganalytics" ? var.log_analytics_workspace_id : var.eventhub_id 14 | connection_string = var.type == "eventhub" ? var.eventhub_connection_string : null 15 | } 16 | 17 | source { 18 | event_source = "Alerts" 19 | rule_set { 20 | rule { 21 | property_path = "Severity" 22 | operator = "Equals" 23 | expected_value = "high" 24 | property_type = "String" 25 | } 26 | } 27 | rule_set { 28 | rule { 29 | property_path = "Severity" 30 | operator = "Equals" 31 | expected_value = "medium" 32 | property_type = "String" 33 | } 34 | } 35 | rule_set { 36 | rule { 37 | property_path = "Severity" 38 | operator = "Equals" 39 | expected_value = "low" 40 | property_type = "String" 41 | } 42 | } 43 | } 44 | 45 | scopes = ["/subscriptions/${data.azurerm_client_config.current.subscription_id}"] 46 | } 47 | -------------------------------------------------------------------------------- /modules/microsoft_defender_continuous_export/providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | source = "hashicorp/azurerm" 5 | version = "~> 4.0" 6 | } 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /modules/microsoft_defender_continuous_export/variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | description = "The name of continuous export configuration" 3 | type = string 4 | } 5 | 6 | variable "resource_group_name" { 7 | description = "The name of the resource group in which the continuous export configuration is created" 8 | type = string 9 | } 10 | 11 | variable "location" { 12 | description = "The Azure region in which the continuous export configuration is created" 13 | type = string 14 | } 15 | 16 | variable "log_analytics_workspace_id" { 17 | description = "The resource id of the Log Analytics workspace" 18 | default = null 19 | } 20 | 21 | variable "type" { 22 | description = "The type of continuous export configuration" 23 | type = string 24 | default = "loganalytics" 25 | validation { 26 | condition = var.type == "loganalytics" || var.type == "eventhub" 27 | error_message = "The type of continuous export configuration must be either 'loganalytics' or 'eventhub'" 28 | } 29 | } 30 | 31 | variable "eventhub_id" { 32 | description = "The resource id of the Event Hub" 33 | default = null 34 | } 35 | 36 | variable "eventhub_connection_string" { 37 | description = "The connection string of the Event Hub" 38 | sensitive = true 39 | default = null 40 | } 41 | -------------------------------------------------------------------------------- /modules/resource_group/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_resource_group" "rg" { 12 | name = var.name 13 | location = var.location 14 | } 15 | -------------------------------------------------------------------------------- /modules/resource_group/outputs.tf: -------------------------------------------------------------------------------- 1 | output "name" { 2 | value = azurerm_resource_group.rg.name 3 | } 4 | 5 | output "location" { 6 | value = azurerm_resource_group.rg.location 7 | } 8 | -------------------------------------------------------------------------------- /modules/resource_group/variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "Azure region of the Resource Group" 3 | type = string 4 | } 5 | 6 | variable "name" { 7 | description = "The name of the Resource Group" 8 | type = string 9 | } 10 | -------------------------------------------------------------------------------- /modules/storage_account/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_storage_account" "storage" { 12 | name = var.name 13 | location = var.location 14 | resource_group_name = var.resource_group_name 15 | account_kind = var.kind 16 | account_tier = var.tier 17 | account_replication_type = var.replication_type 18 | access_tier = var.access_tier 19 | enable_https_traffic_only = true 20 | } 21 | -------------------------------------------------------------------------------- /modules/storage_account/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = azurerm_storage_account.storage.id 3 | } 4 | -------------------------------------------------------------------------------- /modules/storage_account/variables.tf: -------------------------------------------------------------------------------- 1 | variable "resource_group_name" { 2 | description = "Name of the Storage Account resource group" 3 | type = string 4 | } 5 | 6 | variable "location" { 7 | description = "Azure region of the Storage Account" 8 | type = string 9 | } 10 | 11 | variable "name" { 12 | description = "The name of the Storage Account" 13 | type = string 14 | } 15 | 16 | variable "kind" { 17 | description = "The kind of the Storage Account" 18 | type = string 19 | } 20 | 21 | variable "tier" { 22 | description = "The tier of the Storage Account" 23 | type = string 24 | } 25 | 26 | variable "replication_type" { 27 | description = "The replication type of the Storage Account" 28 | type = string 29 | } 30 | 31 | variable "access_tier" { 32 | description = "The access tier of the Storage Account" 33 | type = string 34 | } 35 | -------------------------------------------------------------------------------- /modules/virtual_network/main.tf: -------------------------------------------------------------------------------- 1 | #################### 2 | # Provider section # 3 | #################### 4 | provider "azurerm" { 5 | version = ">= 2.0.0" 6 | features {} 7 | } 8 | ##################### 9 | # Resources section # 10 | ##################### 11 | resource "azurerm_virtual_network" "network" { 12 | name = var.name 13 | location = var.location 14 | resource_group_name = var.resource_group_name 15 | address_space = var.address_space 16 | dns_servers = var.dns_servers 17 | 18 | subnet { 19 | name = var.subnet_name 20 | address_prefix = var.subnet_address_space 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /modules/virtual_network/outputs.tf: -------------------------------------------------------------------------------- 1 | output "id" { 2 | value = azurerm_virtual_network.network.id 3 | } 4 | 5 | output "subnet_id" { 6 | value = element(azurerm_virtual_network.network.subnet.*.id, 0) 7 | } 8 | -------------------------------------------------------------------------------- /modules/virtual_network/variables.tf: -------------------------------------------------------------------------------- 1 | variable "resource_group_name" { 2 | description = "Name of the Virtual Network resource group" 3 | type = string 4 | } 5 | 6 | variable "location" { 7 | description = "Azure region of the Virtual Network" 8 | type = string 9 | } 10 | 11 | variable "name" { 12 | description = "The name of the Virtual Network" 13 | type = string 14 | } 15 | 16 | variable "subnet_name" { 17 | description = "The name of the Virtual Network subnet" 18 | type = string 19 | } 20 | 21 | variable "address_space" { 22 | description = "The address space (CIDR notation) of the Virtual Network" 23 | type = list(string) 24 | } 25 | 26 | variable "subnet_address_space" { 27 | description = "The address space (CIDR notation) of the Virtual Network subnet" 28 | type = string 29 | } 30 | 31 | variable "dns_servers" { 32 | description = "The DNS servers" 33 | type = list(string) 34 | } 35 | --------------------------------------------------------------------------------