diff --git a/infrastructure/.terraform.lock.hcl b/infrastructure/.terraform.lock.hcl new file mode 100644 index 000000000..b790bb249 --- /dev/null +++ b/infrastructure/.terraform.lock.hcl @@ -0,0 +1,42 @@ +# This file is maintained automatically by "terraform init". +# Manual edits may be lost in future updates. + +provider "registry.terraform.io/hashicorp/azurerm" { + version = "3.69.0" + constraints = "3.69.0" + hashes = [ + "h1:Y9P5uiObriBw8Ky39QPu/+I3P9om2M07xBfrhge06c0=", + "zh:00de2580c92828edf5ac02c1287dd247f647ceaa34f8a1e5bf0e2962a99240e4", + "zh:074412944b7d0f5aaf65c0d30c8c82dfb35f0f987a6c94ddfc0e0d9989ea35c2", + "zh:09e1a23ef5331191cee641a71a525c77418e16f666a1c9c82baf01d44d5db66c", + "zh:1c2172a661130d17d982bb6e9228e338bec92763a8cb86bba799357c85238003", + "zh:2f9c7a3a2c269dd3b62dec4a94495694f0ed29b3d7a16bcc6baf8ded9af734d1", + "zh:3d75d487e03ea2f711ffc760aab29aa5a67a19948a4430e61da658edcd2ecb86", + "zh:6e9c98be1768f2b53d43178638832b336e405e65bfa9feb3ec6b7b9444ebd4ea", + "zh:7bbdbb7448147a380077fbf8a356ab9a0e279043a6e7e4beef8cdbebd6243d30", + "zh:ad22c8472f5ec4133860a690ce0b0091a2a834523a0d05e57006b5d86cf0b78e", + "zh:dffe3bce5564841bec9039005aedb464048dad55942e01756d08362b7e81999a", + "zh:e63928a70be9a7afe26b9276b5f1825157670596dec974923759c98fd7e68208", + "zh:f569b65999264a9416862bca5cd2a6177d94ccb0424f3a4ef424428912b9cb3c", + ] +} + +provider "registry.terraform.io/hashicorp/random" { + version = "3.5.1" + constraints = "~> 3.5.1" + hashes = [ + "h1:VSnd9ZIPyfKHOObuQCaKfnjIHRtR7qTw19Rz8tJxm+k=", + "zh:04e3fbd610cb52c1017d282531364b9c53ef72b6bc533acb2a90671957324a64", + "zh:119197103301ebaf7efb91df8f0b6e0dd31e6ff943d231af35ee1831c599188d", + "zh:4d2b219d09abf3b1bb4df93d399ed156cadd61f44ad3baf5cf2954df2fba0831", + "zh:6130bdde527587bbe2dcaa7150363e96dbc5250ea20154176d82bc69df5d4ce3", + "zh:6cc326cd4000f724d3086ee05587e7710f032f94fc9af35e96a386a1c6f2214f", + "zh:78d5eefdd9e494defcb3c68d282b8f96630502cac21d1ea161f53cfe9bb483b3", + "zh:b6d88e1d28cf2dfa24e9fdcc3efc77adcdc1c3c3b5c7ce503a423efbdd6de57b", + "zh:ba74c592622ecbcef9dc2a4d81ed321c4e44cddf7da799faa324da9bf52a22b2", + "zh:c7c5cde98fe4ef1143bd1b3ec5dc04baf0d4cc3ca2c5c7d40d17c0e9b2076865", + "zh:dac4bad52c940cd0dfc27893507c1e92393846b024c5a9db159a93c534a3da03", + "zh:de8febe2a2acd9ac454b844a4106ed295ae9520ef54dc8ed2faf29f12716b602", + "zh:eab0d0495e7e711cca367f7d4df6e322e6c562fc52151ec931176115b83ed014", + ] +} diff --git a/infrastructure/appserviceplan.tf b/infrastructure/appserviceplan.tf new file mode 100644 index 000000000..6f785cc3f --- /dev/null +++ b/infrastructure/appserviceplan.tf @@ -0,0 +1,13 @@ +module "app-plan" { + source = ".//modules/app-service-plan" + + names = module.config.names + resource_group_name = module.baseline.resource_group_names[var.app_service_plan.resource_group_index] + location = module.baseline.resource_group_locations[var.app_service_plan.resource_group_index] + + os_type = var.app_service_plan.os_type + sku_name = var.app_service_plan.sku_name + + tags = var.tags + +} diff --git a/infrastructure/backend.tf b/infrastructure/backend.tf new file mode 100644 index 000000000..1bdfe32f7 --- /dev/null +++ b/infrastructure/backend.tf @@ -0,0 +1,6 @@ + +terraform { + backend "azurerm" { + + } +} diff --git a/infrastructure/baseline.tf b/infrastructure/baseline.tf new file mode 100644 index 000000000..2e60f0685 --- /dev/null +++ b/infrastructure/baseline.tf @@ -0,0 +1,9 @@ +module "baseline" { + source = ".//modules/baseline" + + location = var.location + names = module.config.names + tags = var.tags + resource_groups = var.resource_groups + +} diff --git a/infrastructure/environments/dtos_dev.tfvars.config b/infrastructure/environments/dtos_dev.tfvars.config new file mode 100644 index 000000000..da9ae9ab7 --- /dev/null +++ b/infrastructure/environments/dtos_dev.tfvars.config @@ -0,0 +1,128 @@ +application = "DToS" +environment = "DEV" +location = "uksouth" + +tags = { + Project = "DToS" +} + +resource_groups = { + + # Baseline RG + baseline = { + + name = "rg-dtos-dev-suk-baseline" + # Is is worth leaving location as a parameter for RG? + # location = "uksouth" + } + +} + +storage_accounts = { + + fnapp = { + name_suffix = "fnappstor" + resource_group_index = "baseline" + account_tier = "Standard" + replication_type = "LRS" + public_network_access_enabled = true + } + +} + +key_vault = { + + #name_suffix = "" + resource_group_index = "baseline" + disk_encryption = true + soft_del_ret_days = 7 + purge_prot = false + sku_name = "standard" + +} + +sqlserver = { + + #name_suffix = "" + resource_group_index = "baseline" + sqlversion = "12.0" + tlsversion = 1.2 + + # Baseline database + db_name_suffix = "baseline" + collation = "SQL_Latin1_General_CP1_CI_AS" + licence_type = "LicenseIncluded" + max_gb = 5 + read_scale = false + sku = "S0" + +} + +app_service_plan = { + + + resource_group_index = "baseline" + + sku_name = "B1" + os_type = "Windows" + +} + +function_app = { + + resource_group_index = "baseline" + + fa_config = { + + receiveCaasFile = { + name_suffix = "receiveCaasFile" + } + + ProcessCaasFile = { + name_suffix = "ProcessCaasFile" + } + + AddNewParticipant = { + name_suffix = "AddNewParticipant" + } + + MarkParticipantAsIneligible = { + name_suffix = "MarkParticipantAsIneligible" + } + + CreateParticipantDS = { + name_suffix = "CreateParticipantDS" + } + + MarkParticipantEligibleDS = { + name_suffix = "MarkParticipantEligibleDS" + } + + MarkParticipantIneligibleDS = { + name_suffix = "MarkParticipantIneligibleDS" + } + + UpdateParticipant = { + name_suffix = "UpdateParticipant" + } + + UpdateParticipantDS = { + name_suffix = "UpdateParticipantDS" + } + + BusinessAuditDS = { + name_suffix = "BusinessAuditDS" + } + + } + +} + +event_grid = { + + topic = { + + resource_group_index = "baseline" + name_suffix = "baseline" + } +} diff --git a/infrastructure/eventgrid.tf b/infrastructure/eventgrid.tf new file mode 100644 index 000000000..6489f75bc --- /dev/null +++ b/infrastructure/eventgrid.tf @@ -0,0 +1,13 @@ +module "eventgrid" { + source = ".//modules/event-grid" + + names = module.config.names + + resource_group_name = module.baseline.resource_group_names[var.event_grid.topic.resource_group_index] + location = module.baseline.resource_group_locations[var.event_grid.topic.resource_group_index] + + name_suffix = var.event_grid.topic.name_suffix + + tags = var.tags + +} diff --git a/infrastructure/fnapp.tf b/infrastructure/fnapp.tf new file mode 100644 index 000000000..36d773ec8 --- /dev/null +++ b/infrastructure/fnapp.tf @@ -0,0 +1,16 @@ +module "functionapp" { + source = ".//modules/function-app" + + names = module.config.names + + function_app = var.function_app.fa_config + resource_group_name = module.baseline.resource_group_names[var.function_app.resource_group_index] + location = module.baseline.resource_group_locations[var.function_app.resource_group_index] + + asp_id = module.app-plan.app_service_plan_id + sa_name = module.storage.storage_account_name + sa_prm_key = module.storage.storage_account_primary_access_key + + tags = var.tags + +} diff --git a/infrastructure/keyvault.tf b/infrastructure/keyvault.tf new file mode 100644 index 000000000..5d9b316c7 --- /dev/null +++ b/infrastructure/keyvault.tf @@ -0,0 +1,14 @@ +module "key_vault" { + source = ".//modules/key-vault" + + names = module.config.names + resource_group_name = module.baseline.resource_group_names[var.key_vault.resource_group_index] + location = module.baseline.resource_group_locations[var.key_vault.resource_group_index] + disk_encryption = var.key_vault.disk_encryption + soft_delete_retention = var.key_vault.soft_del_ret_days + purge_protection_enabled = var.key_vault.purge_prot + sku_name = var.key_vault.sku_name + + tags = var.tags + +} diff --git a/infrastructure/modules/app-service-plan/main.tf b/infrastructure/modules/app-service-plan/main.tf new file mode 100644 index 000000000..1b19df881 --- /dev/null +++ b/infrastructure/modules/app-service-plan/main.tf @@ -0,0 +1,16 @@ +resource "azurerm_service_plan" "appserviceplan" { + + name = var.names.app-service-plan + resource_group_name = var.resource_group_name + location = var.location + + os_type = var.os_type + sku_name = var.sku_name + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + } + +} diff --git a/infrastructure/modules/app-service-plan/output.tf b/infrastructure/modules/app-service-plan/output.tf new file mode 100644 index 000000000..1d3e1c9e2 --- /dev/null +++ b/infrastructure/modules/app-service-plan/output.tf @@ -0,0 +1,9 @@ + +output "app_service_plan_name" { + value = azurerm_service_plan.appserviceplan.name +} + +output "app_service_plan_id" { + value = azurerm_service_plan.appserviceplan.id +} + diff --git a/infrastructure/modules/app-service-plan/variables.tf b/infrastructure/modules/app-service-plan/variables.tf new file mode 100644 index 000000000..39c193a8a --- /dev/null +++ b/infrastructure/modules/app-service-plan/variables.tf @@ -0,0 +1,31 @@ +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the App Service Plan. Changing this forces a new resource to be created." +} + +variable "location" { + type = string + description = "The location/region where the App Service Plan is created." +} + +variable "names" { + type = map(string) + description = "Standard naming configuration object for sub-resources." +} + +variable "os_type" { + type = string + description = "OS type for deployed App Service Plan." + default = "Windows" +} + +variable "sku_name" { + type = string + description = "SKU name for deployed App Service Plan." + default = "B1" +} +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/modules/azure-sql-server/database.tf b/infrastructure/modules/azure-sql-server/database.tf new file mode 100644 index 000000000..0b6b65d1f --- /dev/null +++ b/infrastructure/modules/azure-sql-server/database.tf @@ -0,0 +1,18 @@ + +resource "azurerm_mssql_database" "defaultdb" { + name = "${var.names.sql-server-db}-${var.db_name_suffix}" + server_id = azurerm_mssql_server.sqlserver.id + collation = var.collation + license_type = var.licence_type + max_size_gb = var.max_gb + read_scale = var.read_scale + sku_name = var.sku + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + # prevent the possibility of accidental data loss + prevent_destroy = true + } +} diff --git a/infrastructure/modules/azure-sql-server/main.tf b/infrastructure/modules/azure-sql-server/main.tf new file mode 100644 index 000000000..950431c7f --- /dev/null +++ b/infrastructure/modules/azure-sql-server/main.tf @@ -0,0 +1,42 @@ + +resource "azurerm_key_vault_secret" "sqllogin" { + name = "az-sql-login" + value = "sqldtosadmin" + key_vault_id = var.kv_id + + lifecycle { + ignore_changes = [tags] + } +} + +## Random administrator password +resource "random_password" "randompass" { + length = 16 + special = true +} + +resource "azurerm_key_vault_secret" "sqlpass" { + name = "az-sql-pass" + value = random_password.randompass.result + key_vault_id = var.kv_id + + lifecycle { + ignore_changes = [tags] + } +} + +resource "azurerm_mssql_server" "sqlserver" { + name = var.names.sql-server + resource_group_name = var.resource_group_name + location = var.location + version = var.sqlversion + administrator_login = azurerm_key_vault_secret.sqllogin.value + administrator_login_password = azurerm_key_vault_secret.sqlpass.value + minimum_tls_version = var.tlsver + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + } +} diff --git a/infrastructure/modules/azure-sql-server/variables.tf b/infrastructure/modules/azure-sql-server/variables.tf new file mode 100644 index 000000000..a5a69a280 --- /dev/null +++ b/infrastructure/modules/azure-sql-server/variables.tf @@ -0,0 +1,74 @@ +variable "names" { + type = map(string) +} + +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the SQL Server. Changing this forces a new resource to be created." +} + +variable "location" { + type = string + description = "The location/region where the SQL Server is created." +} + +variable "sqlversion" { + type = string #checkType + description = "Varsion of SQL to be created" + default = "12.0" +} + +variable "tlsver" { + type = number + description = " The Minimum TLS Version for all SQL Database and SQL Data Warehouse databases associated with the server" + default = 1.2 +} + +variable "kv_id" { + type = string + description = "Name of the Key Vault in which the admin credentials are put" +} + +#db + +variable "db_name_suffix" { + type = string + description = "The name of the MS SQL Database. Changing this forces a new resource to be created." + default = "baseline" +} + +variable "collation" { + type = string + description = "Specifies the collation of the database. Changing this forces a new resource to be created." + default = "SQL_Latin1_General_CP1_CI_AS" +} + +variable "licence_type" { + type = string + description = " Specifies the license type applied to this database. Possible values are LicenseIncluded and BasePrice" + default = "LicenseIncluded" +} + +variable "max_gb" { + type = number + description = "The max size of the database in gigabytes" + default = 5 +} + +variable "read_scale" { + type = bool + description = "If enabled, connections that have application intent set to readonly in their connection string may be routed to a readonly secondary replica. This property is only settable for Premium and Business Critical databases." + default = false +} + +variable "sku" { + type = string #checkType + description = "Specifies the name of the SKU used by the database. For example, GP_S_Gen5_2,HS_Gen4_1,BC_Gen5_2, ElasticPool, Basic,S0, P2 ,DW100c, DS100. Changing this from the HyperScale service tier to another service tier will create a new resource." + default = "50" +} + +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/modules/baseline/base-network.tf b/infrastructure/modules/baseline/base-network.tf new file mode 100644 index 000000000..e69de29bb diff --git a/infrastructure/modules/baseline/base-rg.tf b/infrastructure/modules/baseline/base-rg.tf new file mode 100644 index 000000000..8cc70cb89 --- /dev/null +++ b/infrastructure/modules/baseline/base-rg.tf @@ -0,0 +1,11 @@ + +resource "azurerm_resource_group" "rg" { + for_each = var.resource_groups + + name = each.value.name + location = var.location + + lifecycle { + ignore_changes = [tags] + } +} diff --git a/infrastructure/modules/baseline/outputs.tf b/infrastructure/modules/baseline/outputs.tf new file mode 100644 index 000000000..eea11574c --- /dev/null +++ b/infrastructure/modules/baseline/outputs.tf @@ -0,0 +1,19 @@ +output "resource_groups" { + value = length(var.resource_groups) > 0 ? azurerm_resource_group.rg : {} +} + +output "resource_group_names" { + description = "The names of the created resource groups" + value = { for k, rg in azurerm_resource_group.rg : k => rg.name } +} + +output "resource_group_ids" { + description = "The IDs of the created resource groups" + value = { for k, rg in azurerm_resource_group.rg : k => rg.id } +} + +output "resource_group_locations" { + description = "The locations of the created resource groups" + value = { for k, rg in azurerm_resource_group.rg : k => rg.location } +} + diff --git a/infrastructure/modules/baseline/variables.tf b/infrastructure/modules/baseline/variables.tf new file mode 100644 index 000000000..77eefff85 --- /dev/null +++ b/infrastructure/modules/baseline/variables.tf @@ -0,0 +1,10 @@ +variable "location" {} +variable "names" { + type = map(string) +} +variable "tags" { + default = {} +} + +variable "resource_groups" { +} diff --git a/infrastructure/modules/event-grid/main.tf b/infrastructure/modules/event-grid/main.tf new file mode 100644 index 000000000..d788d6040 --- /dev/null +++ b/infrastructure/modules/event-grid/main.tf @@ -0,0 +1,12 @@ +resource "azurerm_eventgrid_topic" "egtopic" { + + name = "${var.names.event-grid-topic}-${var.name_suffix}" + resource_group_name = var.resource_group_name + location = var.location + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + } +} diff --git a/infrastructure/modules/event-grid/variables.tf b/infrastructure/modules/event-grid/variables.tf new file mode 100644 index 000000000..5978fbf78 --- /dev/null +++ b/infrastructure/modules/event-grid/variables.tf @@ -0,0 +1,26 @@ + +variable "names" { + type = map(string) +} + +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the Event Grid Topic. Changing this forces a new resource to be created." +} + +variable "location" { + type = string + description = "The location/region where the Event Grid Topic is created." +} + +variable "name_suffix" { + type = string + description = "The name suffix of the Event Grid Topic. Changing this forces a new resource to be created." + default = "baseline" +} + +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/modules/function-app/main.tf b/infrastructure/modules/function-app/main.tf new file mode 100644 index 000000000..5eb8c3d2b --- /dev/null +++ b/infrastructure/modules/function-app/main.tf @@ -0,0 +1,21 @@ + +resource "azurerm_windows_function_app" "function" { + for_each = var.function_app + + name = "${var.names.function-app}-${lower(each.value.name_suffix)}" + resource_group_name = var.resource_group_name + location = var.location + service_plan_id = var.asp_id + + storage_account_name = var.sa_name + storage_account_access_key = var.sa_prm_key + + site_config {} + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + } + +} diff --git a/infrastructure/modules/function-app/variables.tf b/infrastructure/modules/function-app/variables.tf new file mode 100644 index 000000000..e31e49c26 --- /dev/null +++ b/infrastructure/modules/function-app/variables.tf @@ -0,0 +1,40 @@ + +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the Function App. Changing this forces a new resource to be created." +} + +variable "names" { + type = map(string) + description = "The basic part of the Function App name." +} + +variable "function_app" { + description = "Definition of Function Apps configuration" +} + +variable "location" { + type = string + description = "The location/region where the Function App is created." +} + +variable "asp_id" { + type = string + description = "The ID of the AppServicePlan." +} + +variable "sa_name" { + type = string + description = "The name of the Storage Account." +} + +variable "sa_prm_key" { + type = string + description = "The Storage Account Primary Access Key." +} + +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/modules/key-vault/main.tf b/infrastructure/modules/key-vault/main.tf new file mode 100644 index 000000000..7c451eb76 --- /dev/null +++ b/infrastructure/modules/key-vault/main.tf @@ -0,0 +1,32 @@ +data "azurerm_client_config" "current" {} + +resource "azurerm_key_vault" "keyvault" { + name = var.names.key-vault + location = var.location + resource_group_name = var.resource_group_name + enabled_for_disk_encryption = var.disk_encryption + tenant_id = data.azurerm_client_config.current.tenant_id + soft_delete_retention_days = var.soft_delete_retention + purge_protection_enabled = var.purge_protection_enabled + sku_name = var.sku_name + + public_network_access_enabled = true + + access_policy { + + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = data.azurerm_client_config.current.object_id + + certificate_permissions = ["Get", "List"] + key_permissions = ["Get", "List"] + secret_permissions = ["Get", "Set", "List"] + storage_permissions = ["Get", "List"] + } + + tags = var.tags + + lifecycle { + ignore_changes = [tags, contact] + } +} + diff --git a/infrastructure/modules/key-vault/output.tf b/infrastructure/modules/key-vault/output.tf new file mode 100644 index 000000000..085b7007c --- /dev/null +++ b/infrastructure/modules/key-vault/output.tf @@ -0,0 +1,7 @@ +output "key_vault_name" { + value = azurerm_key_vault.keyvault.name +} + +output "key_vault_id" { + value = azurerm_key_vault.keyvault.id +} diff --git a/infrastructure/modules/key-vault/variables.tf b/infrastructure/modules/key-vault/variables.tf new file mode 100644 index 000000000..017340139 --- /dev/null +++ b/infrastructure/modules/key-vault/variables.tf @@ -0,0 +1,43 @@ +variable "names" { + type = map(string) +} + +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the Key Vault. Changing this forces a new resource to be created." +} + +variable "location" { + type = string + description = "The location/region where the Key Vault is created." +} + +variable "disk_encryption" { + type = bool + description = "Should the disk encryption be enabled" + default = true +} + +variable "soft_delete_retention" { + type = number + description = "Name of the Key Vault which is created." + default = "7" +} + +variable "purge_protection_enabled" { + type = bool + description = "Should the purge protection be enabled." + default = false +} + +variable "sku_name" { + type = string + description = "Type of the Key Vault's SKU." + default = "standard" +} + +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/modules/shared-config/main.tf b/infrastructure/modules/shared-config/main.tf new file mode 100644 index 000000000..e69de29bb diff --git a/infrastructure/modules/shared-config/output.tf b/infrastructure/modules/shared-config/output.tf new file mode 100644 index 000000000..c5b18db40 --- /dev/null +++ b/infrastructure/modules/shared-config/output.tf @@ -0,0 +1,107 @@ +locals { + names = { + availability-set = lower("AVS-${var.env}-${var.location_map[var.location]}-${var.application}") + app-insights = upper("AI-${var.env}-${var.location_map[var.location]}") + app-service-plan = lower("ASP-${var.application}-${var.env}-${var.location_map[var.location]}") + app-service = lower("AS-${var.env}-${var.location_map[var.location]}-${var.application}") + connection = upper("CON-${var.env}-${var.location_map[var.location]}-${var.application}") + custom-image = upper("IMAGE-${var.env}-${var.location_map[var.location]}") + dns-zone = "${lower(var.application)}.${lower(var.env)}.net" + docker-dtr = upper("DTR-${var.env}-${var.location_map[var.location]}-${var.application}") + docker-manager = upper("UCP-${var.env}-${var.location_map[var.location]}-${var.application}") + docker-worker = upper("LWK-${var.env}-${var.location_map[var.location]}-${var.application}") + docker-worker-windows = upper("WWK-${var.env}-${var.location_map[var.location]}-${var.application}") + docker-worker-windows-nb = upper("WWK${var.env}${var.location_map[var.location]}${var.application}") + external-load-balancer = upper("ELB-${var.env}-${var.location_map[var.location]}-${var.application}") + event-grid-topic = lower("EVGT-${var.env}-${var.location_map[var.location]}") + function-app = lower("${var.env}-${var.location_map[var.location]}") + internal-load-balancer = upper("ILB-${var.env}-${var.location_map[var.location]}-${var.application}") + key-vault = upper("KV-${var.application}-${var.env}-${var.location_map[var.location]}") + kubernetes-service = lower("AKS-${var.env}-${var.location_map[var.location]}-${var.application}") + load-balancer = upper("LB-${var.env}-${var.location_map[var.location]}-${var.application}") + local-network-gateway = upper("LNG-${var.env}-${var.location_map[var.location]}-${var.application}") + log-analytics-workspace = upper("LOG-${var.env}-${var.location_map[var.location]}") + logic-app = lower("LA-${var.env}-${var.location_map[var.location]}-${var.application}") + network-interface = upper("${var.env}-${var.location_map[var.location]}-${var.application}") + network-security-group = upper("NSG-${var.env}-${var.location_map[var.location]}-${var.application}") + private-ssh-key = lower("ssh-pri-${var.env}${var.location_map[var.location]}${var.application}") + public-ip-address = upper("PIP-${var.env}-${var.location_map[var.location]}-${var.application}") + public-ip-dns = lower("${var.env}${var.location_map[var.location]}${var.application}") + public-ssh-key = lower("ssh-pub-${var.env}${var.location_map[var.location]}${var.application}") + redis-cache = lower("RC-${var.location_map[var.location]}-${var.env}-${var.application}") + resource-group = lower("RG-${var.application}-${var.env}-${var.location_map[var.location]}") + resource-application = upper("${var.env}-${var.location_map[var.location]}-${var.application}") + route-table = upper("RT-${var.env}-${var.location_map[var.location]}-${var.application}") + service-bus = lower("SB-${var.location_map[var.location]}-${var.env}-${var.application}") + service-principal = upper("SP-${var.env}-${var.application}") + sql-server = lower("SQLSVR-${var.application}-${var.env}-${var.location_map[var.location]}") + sql-server-db = lower("SQLDB-${var.application}-${var.env}-${var.location_map[var.location]}") + sql-server-managed-instance = lower("SQLMI-${var.env}-${var.location_map[var.location]}-${var.application}") + stack-dns-suffix = "${lower(var.env)}${lower(var.application)}" + storage-account = substr(lower("ST${var.application}${var.env}${var.location_map[var.location]}"), 0, 24) + storage-alerts = lower("STALERT${var.env}${var.location_map[var.location]}${var.application}") + storage-boot-diags = lower("STDIAG${var.env}${var.location_map[var.location]}${var.application}") + storage-flow-logs = lower("STFLOW${var.env}${var.location_map[var.location]}${var.application}") + storage-shared-state = lower("STSTATE${var.env}${var.location_map[var.location]}${var.application}") + subnet = upper("SN-${var.env}-${var.location_map[var.location]}-${var.application}") + virtual-machine = upper("${var.env}-${var.application}") + win-virtual-machine = upper("${var.env}-${var.application}") + virtual-network = upper("VNET-${var.env}-${var.location_map[var.location]}-${var.application}") + vnet-gateway = upper("GWY-${var.env}-${var.location_map[var.location]}-${var.application}") + } + +} + +output "names" { + description = "Return list of calculated standard names for the deployment." + value = { + availability-set = local.names.availability-set + app-insights = local.names.app-insights + app-service-plan = local.names.app-service-plan + app-service = local.names.app-service + connection = local.names.connection + custom-image = local.names.custom-image + dns-zone = local.names.dns-zone + docker-dtr = local.names.docker-dtr + docker-manager = local.names.docker-manager + docker-worker = local.names.docker-worker + docker-worker-windows = local.names.docker-worker-windows + docker-worker-windows-nb = local.names.docker-worker-windows-nb + external-load-balancer = local.names.external-load-balancer + event-grid-topic = local.names.event-grid-topic + function-app = local.names.function-app + internal-load-balancer = local.names.internal-load-balancer + key-vault = local.names.key-vault + kubernetes-service = local.names.kubernetes-service + load-balancer = local.names.load-balancer + local-network-gateway = local.names.local-network-gateway + log-analytics-workspace = local.names.log-analytics-workspace + logic-app = local.names.logic-app + network-interface = local.names.network-interface + network-security-group = local.names.network-security-group + private-ssh-key = local.names.private-ssh-key + public-ip-address = local.names.public-ip-address + public-ip-dns = local.names.public-ip-dns + public-ssh-key = local.names.public-ssh-key + redis-cache = local.names.redis-cache + resource-group = local.names.resource-group + resource-application = local.names.resource-application + route-table = local.names.route-table + service-bus = local.names.service-bus + service-principal = local.names.service-principal + sql-server = local.names.sql-server + sql-server-db = local.names.sql-server-db + sql-server-managed-instance = local.names.sql-server-managed-instance + stack-dns-suffix = local.names.stack-dns-suffix + storage-account = local.names.storage-account + storage-alerts = local.names.storage-alerts + storage-boot-diags = local.names.storage-boot-diags + storage-flow-logs = local.names.storage-flow-logs + storage-shared-state = local.names.storage-shared-state + subnet = local.names.subnet + virtual-machine = local.names.virtual-machine + win-virtual-machine = local.names.win-virtual-machine + virtual-network = local.names.virtual-network + vnet-gateway = local.names.vnet-gateway + } +} diff --git a/infrastructure/modules/shared-config/variables.tf b/infrastructure/modules/shared-config/variables.tf new file mode 100644 index 000000000..ca83f2a52 --- /dev/null +++ b/infrastructure/modules/shared-config/variables.tf @@ -0,0 +1,95 @@ +variable "env" { + description = "Environment acronym for deployment" +} + +variable "location" { + description = "Location for the deployment" +} + +variable "location_map" { + description = "Azure location map used for naming abberviations" + type = map(string) + default = { + "Australia Central 2" = "CAU2", + "Australia Central" = "CAU", + "Australia East" = "EAU", + "Australia Southeast" = "SEAU", + "australiacentral" = "CAU", + "australiacentral2" = "CAU2", + "australiaeast" = "EAU", + "australiasoutheast" = "SEAU", + "Brazil South" = "SBR", + "brazilsouth" = "SBR", + "Canada Central" = "CAC", + "Canada East" = "ECA", + "canadacentral" = "CAC", + "canadaeast" = "ECA", + "Central India" = "CIN", + "Central US" = "CUS", + "centralindia" = "CIN", + "centralus" = "CUS", + "East Asia" = "EAA", + "East US 2" = "EUS2", + "East US" = "EUS", + "eastasia" = "EAA", + "eastus" = "EUS", + "eastus2" = "EUS2", + "France Central" = "CFR", + "France South" = "SFR", + "francecentral" = "CFR", + "francesouth" = "SFR", + "Germany North" = "NGE", + "Germany West Central" = "WCGE", + "germanynorth" = "NGE", + "germanywestcentral" = "WCGE", + "Japan East" = "EJA", + "Japan West" = "WJA", + "japaneast" = "EJA", + "japanwest" = "WJA", + "Korea Central" = "CKO", + "Korea South" = "SKO", + "koreacentral" = "CKO", + "koreasouth" = "SKO", + "North Central US" = "NCUS", + "North Europe" = "NEU", + "northcentralus" = "NCUS", + "northeurope" = "NEU", + "South Africa North" = "NSA", + "South Africa West" = "WSA", + "South Central US" = "SCUS", + "South India" = "SIN", + "southafricanorth" = "NSA", + "southafricawest" = "WSA", + "southcentralus" = "SCUS", + "Southeast Asia" = "SEA", + "southeastasia" = "SEA", + "southindia" = "SIN", + "UAE Central" = "CUA", + "UAE North" = "NUA", + "uaecentral" = "CUA", + "uaenorth" = "NUA", + "UK South" = "UKS", + "UK West" = "WUK", + "uksouth" = "SUK", + "ukwest" = "WUK", + "West Central US" = "WCUS", + "West Europe" = "WEU", + "West India" = "WIN", + "West US 2" = "WUS2", + "West US" = "WUS", + "westcentralus" = "WCUS", + "westeurope" = "WEU", + "westindia" = "WIN", + "westus" = "WUS", + "westus2" = "WUS2" + } +} + +variable "application" { + description = "Unique identifier for the deployment" +} + +variable "tags" { + type = map(string) + description = "Default tags for the deployment" +} diff --git a/infrastructure/modules/storage/main.tf b/infrastructure/modules/storage/main.tf new file mode 100644 index 000000000..e2226459b --- /dev/null +++ b/infrastructure/modules/storage/main.tf @@ -0,0 +1,15 @@ +resource "azurerm_storage_account" "sa" { + + name = var.name + resource_group_name = var.resource_group_name + location = var.location + account_tier = var.account_tier + account_replication_type = var.sa_replication_type + public_network_access_enabled = var.public_access + + tags = var.tags + + lifecycle { + ignore_changes = [tags] + } +} diff --git a/infrastructure/modules/storage/output.tf b/infrastructure/modules/storage/output.tf new file mode 100644 index 000000000..63be656b4 --- /dev/null +++ b/infrastructure/modules/storage/output.tf @@ -0,0 +1,9 @@ + +output "storage_account_name" { + value = azurerm_storage_account.sa.name +} + +output "storage_account_primary_access_key" { + sensitive = true + value = azurerm_storage_account.sa.primary_access_key +} diff --git a/infrastructure/modules/storage/variables.tf b/infrastructure/modules/storage/variables.tf new file mode 100644 index 000000000..6727bac5d --- /dev/null +++ b/infrastructure/modules/storage/variables.tf @@ -0,0 +1,37 @@ + +variable "resource_group_name" { + type = string + description = "The name of the resource group in which to create the Storage Account. Changing this forces a new resource to be created." +} + +variable "location" { + type = string + description = "The location/region where the Storage Account is created." +} + +variable "name" { + type = string + description = "The name of the Storage Account." +} + +variable "account_tier" { + description = "." + default = {} +} + +variable "sa_replication_type" { + description = "." + default = {} +} + +variable "public_access" { + description = "." + default = {} +} + + +variable "tags" { + type = map(string) + description = "Resource tags to be applied throughout the deployment." + default = {} +} diff --git a/infrastructure/output.tf b/infrastructure/output.tf new file mode 100644 index 000000000..e69de29bb diff --git a/infrastructure/provider.tf b/infrastructure/provider.tf new file mode 100644 index 000000000..238f662d9 --- /dev/null +++ b/infrastructure/provider.tf @@ -0,0 +1,20 @@ +terraform { + required_version = ">= 1.4.2" + required_providers { + azurerm = "= 3.69.0" + random = "~> 3.5.1" + } +} + +provider "azurerm" { + + features {} +} + +module "config" { + source = ".//modules/shared-config" + location = var.location + application = var.application + env = var.environment + tags = var.tags +} diff --git a/infrastructure/sqlserver.tf b/infrastructure/sqlserver.tf new file mode 100644 index 000000000..a790499a7 --- /dev/null +++ b/infrastructure/sqlserver.tf @@ -0,0 +1,23 @@ +module "azuresql" { + source = ".//modules/azure-sql-server" + + # Azure SQL Server + names = module.config.names + resource_group_name = module.baseline.resource_group_names[var.sqlserver.resource_group_index] + location = module.baseline.resource_group_locations[var.sqlserver.resource_group_index] + sqlversion = var.sqlserver.sqlversion + tlsver = var.sqlserver.tlsversion + kv_id = module.key_vault.key_vault_id + + tags = var.tags + + # Default database + db_name_suffix = var.sqlserver.db_name_suffix + collation = var.sqlserver.collation + licence_type = var.sqlserver.licence_type + max_gb = var.sqlserver.max_gb + read_scale = var.sqlserver.read_scale + sku = var.sqlserver.sku + +} + diff --git a/infrastructure/storage.tf b/infrastructure/storage.tf new file mode 100644 index 000000000..fdd070b34 --- /dev/null +++ b/infrastructure/storage.tf @@ -0,0 +1,14 @@ +module "storage" { + source = ".//modules/storage" + + name = substr("${module.config.names.storage-account}${lower(var.storage_accounts.fnapp.name_suffix)}", 0, 24) + resource_group_name = module.baseline.resource_group_names[var.storage_accounts.fnapp.resource_group_index] + location = module.baseline.resource_group_locations[var.storage_accounts.fnapp.resource_group_index] + + account_tier = var.storage_accounts.fnapp.account_tier + sa_replication_type = var.storage_accounts.fnapp.replication_type + public_access = var.storage_accounts.fnapp.public_network_access_enabled + + tags = var.tags + +} diff --git a/infrastructure/variables.tf b/infrastructure/variables.tf new file mode 100644 index 000000000..770200dc9 --- /dev/null +++ b/infrastructure/variables.tf @@ -0,0 +1,101 @@ + +variable "application" { + description = "Project/Application code for deployment" + type = string + default = "DToS" +} +variable "environment" { + description = "Environment code for deployments" + type = string + default = "DEV" +} + +variable "location" { + description = "Location code for deployments" + type = string + default = "uksouth" +} + +variable "tags" { + description = "Default tags to be applied to resources" + type = map(string) +} + +variable "resource_groups" { + description = "Map of resource groups" + type = map(object({ + name = optional(string, "rg-dtos-dev-suk-baseline") + })) +} + +variable "storage_accounts" { + description = "Configuration for the Storage Account, currently used for Function Apps" + type = object({ + fnapp = object({ + name_suffix = optional(string, "fnappstor") + resource_group_index = optional(string, "baseline") + account_tier = optional(string, "Standard") + replication_type = optional(string, "LRS") + public_network_access_enabled = optional(bool, true) + }) + }) +} + +variable "key_vault" { + description = "Configuration for the baseline key vault" + type = object({ + resource_group_index = optional(string, "baseline") + disk_encryption = optional(bool, true) + soft_del_ret_days = optional(number, 7) + purge_prot = optional(bool, false) + sku_name = optional(string, "standard") + }) +} + +variable "sqlserver" { + description = "Configuration for the Azure MSSQL server instance and a default database " + type = object({ + # Server Instance + resource_group_index = optional(string, "baseline") + sqlversion = optional(string, "12.0") + tlsversion = optional(number, 1.2) + + # Database + db_name_suffix = optional(string, "baseline") + collation = optional(string, "SQL_Latin1_General_CP1_CI_AS") + licence_type = optional(string, "LicenseIncluded") + max_gb = optional(number, 5) + read_scale = optional(bool, false) + sku = optional(string, "S0") + }) + +} + +variable "app_service_plan" { + description = "Configuration for the app service plan" + type = object({ + resource_group_index = optional(string, "baseline") + sku_name = optional(string, "B1") + os_type = optional(string, "Windows") + }) +} + +variable "function_app" { + description = "Configuration for the function app" + type = object({ + resource_group_index = optional(string, "baseline") + fa_config = map(object({ + name_suffix = string + })) + }) +} + +variable "event_grid" { + description = "Configuration for the event grid" + type = object({ + topic = object({ + resource_group_index = optional(string, "baseline") + name_suffix = optional(string, "baseline") + }) + }) +}