diff --git a/Terraform/README.md b/Terraform/README.md index 8ce3c7b9..0ec2cf8b 100644 --- a/Terraform/README.md +++ b/Terraform/README.md @@ -36,12 +36,14 @@ No modules. | [azurerm_private_dns_zone_virtual_network_link.dnszonelink](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/private_dns_zone_virtual_network_link) | resource | | [azurerm_private_endpoint.privateendpoint](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/private_endpoint) | resource | | [azurerm_private_endpoint.privateendpoint-gf](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/private_endpoint) | resource | +| [azurerm_private_endpoint.privateendpoint-sa](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/private_endpoint) | resource | | [azurerm_private_endpoint.searchprivateendpoint](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/private_endpoint) | resource | | [azurerm_search_service.ai-search](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/search_service) | resource | | [azurerm_service_plan.service-plan](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/service_plan) | resource | | [azurerm_service_plan.service-plan-gf](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/service_plan) | resource | | [azurerm_storage_account.gfsa](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/storage_account) | resource | | [azurerm_storage_share.gffileshare](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/storage_share) | resource | +| [azurerm_subnet.appstorage](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/subnet) | resource | | [azurerm_subnet.backend](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/subnet) | resource | | [azurerm_subnet.frontend](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/subnet) | resource | | [azurerm_subnet_network_security_group_association.blockall](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/resources/subnet_network_security_group_association) | resource | @@ -52,6 +54,7 @@ No modules. | [azurerm_log_analytics_workspace.log-analytics-ws](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/log_analytics_workspace) | data source | | [azurerm_public_ip.pip1](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/public_ip) | data source | | [azurerm_resource_group.rg](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/resource_group) | data source | +| [azurerm_user_assigned_identity.appsauai](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/user_assigned_identity) | data source | | [azurerm_user_assigned_identity.uai](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/user_assigned_identity) | data source | | [azurerm_virtual_network.vnet1](https://registry.terraform.io/providers/hashicorp/azurerm/3.90.0/docs/data-sources/virtual_network) | data source | @@ -81,7 +84,11 @@ No modules. | [autoscale\_max](#input\_autoscale\_max) | Maximum Autoscale Value | `map(string)` |
{| no | | [autoscale\_min](#input\_autoscale\_min) | Minimum Autoscale Value | `map(string)` |
"Dev": 2,
"Load-Test": 10,
"Pre-Prod": 2,
"Prod": 10,
"Test": 2
}
{| no | | [autoscale\_name](#input\_autoscale\_name) | Name of autoscale settings | `map(string)` |
"Dev": 1,
"Load-Test": 3,
"Pre-Prod": 1,
"Prod": 3,
"Test": 1
}
{| no | +| [azure\_managed\_identity\_name](#input\_azure\_managed\_identity\_name) | Azure Managed Identity Name to Read Storage Account | `map(string)` |
"Dev": "s185d01-app-autoscale",
"Load-Test": "s185d03-app-autoscale",
"Pre-Prod": "s185t01-app-autoscale",
"Prod": "s185p01-app-autoscale",
"Test": "s185d02-app-autoscale"
}
{| no | | [backend\_address\_pool\_name](#input\_backend\_address\_pool\_name) | Name of Backend Address Pool | `map(string)` |
"Dev": "s185d01-webapprole",
"Load-Test": "s185d03-webapprole",
"Pre-Prod": "s185t01-webapprole",
"Prod": "s185p01-webapprole",
"Test": "s185d02-webapprole"
}
{| no | +| [cpd\_azure\_data\_protection\_container\_name](#input\_cpd\_azure\_data\_protection\_container\_name) | Data Protection Container Name | `map(string)` |
"Dev": "s185d01-chidrens-social-care-cpd-bep",
"Load-Test": "s185d03-chidrens-social-care-cpd-bep",
"Pre-Prod": "s185t01-chidrens-social-care-cpd-bep",
"Prod": "s185p01-chidrens-social-care-cpd-bep",
"Test": "s185d02-chidrens-social-care-cpd-bep"
}
{| no | +| [cpd\_azure\_storage\_account](#input\_cpd\_azure\_storage\_account) | Storage Account Name for Application | `map(string)` |
"Dev": "data-protection",
"Load-Test": "data-protection",
"Pre-Prod": "data-protection",
"Prod": "data-protection",
"Test": "data-protection"
}
{| no | +| [cpd\_azure\_storage\_account\_uri\_format\_string](#input\_cpd\_azure\_storage\_account\_uri\_format\_string) | Storage Account Format String | `map(string)` |
"Dev": "s185d01webappsa",
"Load-Test": "s185d03webappsa",
"Pre-Prod": "s185t01webappsa",
"Prod": "s185p01webappsa",
"Test": "s185d03webappsa"
}
{| no | | [cpd\_clarity](#input\_cpd\_clarity) | MS Clarity Secret | `string` | n/a | yes | | [cpd\_contentful\_env](#input\_cpd\_contentful\_env) | Contentful Environment Name | `map(string)` |
"Dev": "https://{0}.blob.core.windows.net/{1}",
"Load-Test": "https://{0}.blob.core.windows.net/{1}",
"Pre-Prod": "https://{0}.blob.core.windows.net/{1}",
"Prod": "https://{0}.blob.core.windows.net/{1}",
"Test": "https://{0}.blob.core.windows.net/{1}"
}
{| no | | [cpd\_delivery\_key](#input\_cpd\_delivery\_key) | Contentful Delivery Key | `string` | n/a | yes | @@ -147,6 +154,8 @@ No modules. | [ssl\_listener\_name](#input\_ssl\_listener\_name) | Name of SSL HTTPS Listener | `map(string)` |
"Dev": "dev",
"Load-Test": "prod",
"Pre-Prod": "prod",
"Prod": "prod",
"Test": "test"
}
{| no | | [tenant\_id](#input\_tenant\_id) | The Tenant ID of the subscription being used | `string` | n/a | yes | | [vcs\_tag](#input\_vcs\_tag) | The application version | `string` | n/a | yes | +| [vnet\_appstorage\_name](#input\_vnet\_appstorage\_name) | Name of Application Storage VNET | `map(string)` |
"Dev": "s185d01-chidrens-social-care-cpd-listener-https",
"Load-Test": "s185d03-chidrens-social-care-cpd-listener-https",
"Pre-Prod": "s185t01-chidrens-social-care-cpd-listener-https",
"Prod": "s185p01-chidrens-social-care-cpd-listener-https",
"Test": "s185d02-chidrens-social-care-cpd-listener-https"
}
{| no | +| [vnet\_appstorage\_prefixes](#input\_vnet\_appstorage\_prefixes) | Subnets used for Application Storage VNET | `map(string)` |
"Dev": "s185d01-chidrens-social-care-cpd-sn03",
"Load-Test": "s185d03-chidrens-social-care-cpd-sn03",
"Pre-Prod": "s185t01-chidrens-social-care-cpd-sn03",
"Prod": "s185p01-chidrens-social-care-cpd-sn03",
"Test": "s185d02-chidrens-social-care-cpd-sn03"
}
{| no | | [vnet\_backend\_name](#input\_vnet\_backend\_name) | Name of Backend VNET | `map(string)` |
"Dev": "10.0.0.128/26",
"Load-Test": "10.2.0.128/26",
"Pre-Prod": "10.0.0.128/26",
"Prod": "10.0.0.128/26",
"Test": "10.1.0.128/26"
}
{| no | | [vnet\_backend\_prefixes](#input\_vnet\_backend\_prefixes) | Subnets used for Backend VNET | `map(string)` |
"Dev": "s185d01-chidrens-social-care-cpd-sn02",
"Load-Test": "s185d03-chidrens-social-care-cpd-sn02",
"Pre-Prod": "s185t01-chidrens-social-care-cpd-sn02",
"Prod": "s185p01-chidrens-social-care-cpd-sn02",
"Test": "s185d02-chidrens-social-care-cpd-sn02"
}
{| no | | [vnet\_frontend\_name](#input\_vnet\_frontend\_name) | Name of Frontend VNET | `map(string)` |
"Dev": "10.0.0.64/26",
"Load-Test": "10.2.0.64/26",
"Pre-Prod": "10.0.0.64/26",
"Prod": "10.0.0.64/26",
"Test": "10.1.0.64/26"
}
{| no | diff --git a/Terraform/application.tf b/Terraform/application.tf index 0722c357..52e10c5c 100644 --- a/Terraform/application.tf +++ b/Terraform/application.tf @@ -17,20 +17,25 @@ resource "azurerm_linux_web_app" "linux-web-app" { public_network_access_enabled = false app_settings = { - CPD_GOOGLEANALYTICSTAG = var.cpd_googleanalyticstag - CPD_SPACE_ID = var.cpd_space_id - CPD_PREVIEW_KEY = var.cpd_preview_key - CPD_DELIVERY_KEY = var.cpd_delivery_key - CPD_TENANTID = var.tenant_id - CPD_AZURE_ENVIRONMENT = lower(terraform.workspace) - CPD_CONTENTFUL_ENVIRONMENT = var.cpd_contentful_env[terraform.workspace] - CPD_INSTRUMENTATION_CONNECTIONSTRING = data.azurerm_application_insights.appinsights.connection_string - CPD_CLARITY = var.cpd_clarity - CPD_FEATURE_POLLING_INTERVAL = var.cpd_feature_polling_interval - CPD_SEARCH_CLIENT_API_KEY = var.cpd_search_client_api_key - CPD_SEARCH_ENDPOINT = var.cpd_search_endpoint - CPD_SEARCH_INDEX_NAME = var.cpd_search_index_name - DOCKER_ENABLE_CI = "true" + ASPNETCORE_HTTP_PORTS = 80 + CPD_GOOGLEANALYTICSTAG = var.cpd_googleanalyticstag + CPD_SPACE_ID = var.cpd_space_id + CPD_PREVIEW_KEY = var.cpd_preview_key + CPD_DELIVERY_KEY = var.cpd_delivery_key + CPD_TENANTID = var.tenant_id + CPD_AZURE_ENVIRONMENT = lower(terraform.workspace) + CPD_CONTENTFUL_ENVIRONMENT = var.cpd_contentful_env[terraform.workspace] + CPD_INSTRUMENTATION_CONNECTIONSTRING = data.azurerm_application_insights.appinsights.connection_string + CPD_CLARITY = var.cpd_clarity + CPD_FEATURE_POLLING_INTERVAL = var.cpd_feature_polling_interval + CPD_SEARCH_CLIENT_API_KEY = var.cpd_search_client_api_key + CPD_SEARCH_ENDPOINT = var.cpd_search_endpoint + CPD_SEARCH_INDEX_NAME = var.cpd_search_index_name + CPD_AZURE_DATA_PROTECTION_CONTAINER_NAME = var.cpd_azure_data_protection_container_name[terraform.workspace] + CPD_AZURE_STORAGE_ACCOUNT = var.cpd_azure_storage_account[terraform.workspace] + CPD_AZURE_MANAGED_IDENTITY_ID = data.azurerm_user_assigned_identity.appsauai.client_id + CPD_AZURE_STORAGE_ACCOUNT_URI_FORMAT_STRING = var.cpd_azure_storage_account_uri_format_string[terraform.workspace] + DOCKER_ENABLE_CI = "true" } site_config { @@ -38,8 +43,11 @@ resource "azurerm_linux_web_app" "linux-web-app" { docker_registry_url = "https://ghcr.io" docker_image_name = "dfe-digital/childrens-social-care-cpd:${nonsensitive(var.cpd_image_tag)}" } + vnet_route_all_enabled = true } + virtual_network_subnet_id = azurerm_subnet.appstorage.id + logs { http_logs { file_system { @@ -49,6 +57,11 @@ resource "azurerm_linux_web_app" "linux-web-app" { } } + identity { + identity_ids = [data.azurerm_user_assigned_identity.appsauai.id] + type = "UserAssigned" + } + tags = data.azurerm_resource_group.rg.tags } @@ -59,20 +72,25 @@ resource "azurerm_linux_web_app_slot" "staging" { count = terraform.workspace == "Prod" || terraform.workspace == "Load-Test" ? 1 : 0 app_settings = { - CPD_GOOGLEANALYTICSTAG = var.cpd_googleanalyticstag - CPD_SPACE_ID = var.cpd_space_id - CPD_PREVIEW_KEY = var.cpd_preview_key - CPD_DELIVERY_KEY = var.cpd_delivery_key - CPD_TENANTID = var.tenant_id - CPD_AZURE_ENVIRONMENT = lower(terraform.workspace) - CPD_CONTENTFUL_ENVIRONMENT = var.cpd_contentful_env[terraform.workspace] - CPD_INSTRUMENTATION_CONNECTIONSTRING = data.azurerm_application_insights.appinsights.connection_string - CPD_CLARITY = var.cpd_clarity - CPD_FEATURE_POLLING_INTERVAL = var.cpd_feature_polling_interval - CPD_SEARCH_CLIENT_API_KEY = var.cpd_search_client_api_key - CPD_SEARCH_ENDPOINT = var.cpd_search_endpoint - CPD_SEARCH_INDEX_NAME = var.cpd_search_index_name - DOCKER_ENABLE_CI = "true" + ASPNETCORE_HTTP_PORTS = 80 + CPD_GOOGLEANALYTICSTAG = var.cpd_googleanalyticstag + CPD_SPACE_ID = var.cpd_space_id + CPD_PREVIEW_KEY = var.cpd_preview_key + CPD_DELIVERY_KEY = var.cpd_delivery_key + CPD_TENANTID = var.tenant_id + CPD_AZURE_ENVIRONMENT = lower(terraform.workspace) + CPD_CONTENTFUL_ENVIRONMENT = var.cpd_contentful_env[terraform.workspace] + CPD_INSTRUMENTATION_CONNECTIONSTRING = data.azurerm_application_insights.appinsights.connection_string + CPD_CLARITY = var.cpd_clarity + CPD_FEATURE_POLLING_INTERVAL = var.cpd_feature_polling_interval + CPD_SEARCH_CLIENT_API_KEY = var.cpd_search_client_api_key + CPD_SEARCH_ENDPOINT = var.cpd_search_endpoint + CPD_SEARCH_INDEX_NAME = var.cpd_search_index_name + CPD_AZURE_DATA_PROTECTION_CONTAINER_NAME = var.cpd_azure_data_protection_container_name[terraform.workspace] + CPD_AZURE_STORAGE_ACCOUNT = var.cpd_azure_storage_account[terraform.workspace] + CPD_AZURE_MANAGED_IDENTITY_ID = data.azurerm_user_assigned_identity.appsauai.client_id + CPD_AZURE_STORAGE_ACCOUNT_URI_FORMAT_STRING = var.cpd_azure_storage_account_uri_format_string[terraform.workspace] + DOCKER_ENABLE_CI = "true" } site_config { diff --git a/Terraform/managed-identity.tf b/Terraform/managed-identity.tf index 371fc0db..c2a2a30e 100644 --- a/Terraform/managed-identity.tf +++ b/Terraform/managed-identity.tf @@ -28,3 +28,8 @@ data "azurerm_user_assigned_identity" "uai" { # "Get", "List", # ] # } + +data "azurerm_user_assigned_identity" "appsauai" { + resource_group_name = data.azurerm_resource_group.rg.name + name = var.azure_managed_identity_name[terraform.workspace] +} diff --git a/Terraform/networking.tf b/Terraform/networking.tf index 06ed28d6..629ffd28 100644 --- a/Terraform/networking.tf +++ b/Terraform/networking.tf @@ -22,6 +22,23 @@ resource "azurerm_subnet" "backend" { virtual_network_name = data.azurerm_virtual_network.vnet1.name address_prefixes = [var.vnet_backend_prefixes[terraform.workspace]] private_link_service_network_policies_enabled = false + service_endpoints = ["Microsoft.Storage"] +} + +# Private subnet for the applicaton storage +resource "azurerm_subnet" "appstorage" { + name = var.vnet_appstorage_name[terraform.workspace] + resource_group_name = data.azurerm_resource_group.rg.name + virtual_network_name = data.azurerm_virtual_network.vnet1.name + address_prefixes = [var.vnet_appstorage_prefixes[terraform.workspace]] + private_link_service_network_policies_enabled = false + service_endpoints = ["Microsoft.Web"] + delegation { + name = "delegation" + service_delegation { + name = "Microsoft.Web/serverFarms" + } + } } # The public IP address for this service diff --git a/Terraform/private-endpoint.tf b/Terraform/private-endpoint.tf index fc0ae996..f160249b 100644 --- a/Terraform/private-endpoint.tf +++ b/Terraform/private-endpoint.tf @@ -89,3 +89,25 @@ resource "azurerm_private_endpoint" "privateendpoint-gf" { tags = data.azurerm_resource_group.rg.tags } + +# Definition of the private end point for the application storage +resource "azurerm_private_endpoint" "privateendpoint-sa" { + name = "${var.private_endpoint_name[terraform.workspace]}-sa" + location = data.azurerm_resource_group.rg.location + resource_group_name = data.azurerm_resource_group.rg.name + subnet_id = azurerm_subnet.backend.id + + private_dns_zone_group { + name = var.private_dns_zone_group_name[terraform.workspace] + private_dns_zone_ids = [azurerm_private_dns_zone.dnsprivatezone.id] + } + + private_service_connection { + name = "${var.private_endpoint_conn_name[terraform.workspace]}-sa" + private_connection_resource_id = azurerm_storage_account.gfsa.id + subresource_names = ["blob"] + is_manual_connection = false + } + + tags = data.azurerm_resource_group.rg.tags +} diff --git a/Terraform/variables.tf b/Terraform/variables.tf index 00409b02..7fb01ada 100644 --- a/Terraform/variables.tf +++ b/Terraform/variables.tf @@ -132,6 +132,31 @@ variable "vnet_backend_prefixes" { description = "Subnets used for Backend VNET" } + +variable "vnet_appstorage_name" { + type = map(string) + default = { + Dev = "s185d01-chidrens-social-care-cpd-sn03" + Test = "s185d02-chidrens-social-care-cpd-sn03" + Load-Test = "s185d03-chidrens-social-care-cpd-sn03" + Pre-Prod = "s185t01-chidrens-social-care-cpd-sn03" + Prod = "s185p01-chidrens-social-care-cpd-sn03" + } + description = "Name of Application Storage VNET" +} + +variable "vnet_appstorage_prefixes" { + type = map(string) + default = { + Dev = "10.0.0.128/26" + Test = "10.1.0.128/26" + Load-Test = "10.2.0.128/26" + Pre-Prod = "10.0.0.128/26" + Prod = "10.0.0.128/26" + } + description = "Subnets used for Application Storage VNET" +} + variable "pip_name" { type = map(string) default = { @@ -696,6 +721,54 @@ variable "cpd_contentful_env" { description = "Contentful Environment Name" } +variable "cpd_azure_data_protection_container_name" { + type = map(string) + default = { + Dev = "data-protection" + Test = "data-protection" + Load-Test = "data-protection" + Pre-Prod = "data-protection" + Prod = "data-protection" + } + description = "Data Protection Container Name" +} + +variable "cpd_azure_storage_account" { + type = map(string) + default = { + Dev = "s185d01webappsa" + Test = "s185d03webappsa" + Load-Test = "s185d03webappsa" + Pre-Prod = "s185t01webappsa" + Prod = "s185p01webappsa" + } + description = "Storage Account Name for Application" +} + +variable "azure_managed_identity_name" { + type = map(string) + default = { + Dev = "s185d01-webapprole" + Test = "s185d02-webapprole" + Load-Test = "s185d03-webapprole" + Pre-Prod = "s185t01-webapprole" + Prod = "s185p01-webapprole" + } + description = "Azure Managed Identity Name to Read Storage Account" +} + +variable "cpd_azure_storage_account_uri_format_string" { + type = map(string) + default = { + Dev = "https://{0}.blob.core.windows.net/{1}" + Test = "https://{0}.blob.core.windows.net/{1}" + Load-Test = "https://{0}.blob.core.windows.net/{1}" + Pre-Prod = "https://{0}.blob.core.windows.net/{1}" + Prod = "https://{0}.blob.core.windows.net/{1}" + } + description = "Storage Account Format String" +} + variable "fw_diag_name" { type = map(string) default = { @@ -804,7 +877,6 @@ variable "search_private_endpoint_conn_name" { description = "Name of Private Endpoint Connection" } - variable "cpd_search_api_key" { description = "The Azure AI Search API key" sensitive = true
"Dev": "s185d01-chidrens-social-care-cpd-sn01",
"Load-Test": "s185d03-chidrens-social-care-cpd-sn01",
"Pre-Prod": "s185t01-chidrens-social-care-cpd-sn01",
"Prod": "s185p01-chidrens-social-care-cpd-sn01",
"Test": "s185d02-chidrens-social-care-cpd-sn01"
}