From f43f4e72ae2eff6c3cabbd769058cc0bf4c8fba2 Mon Sep 17 00:00:00 2001 From: Di Jiao Date: Wed, 8 Nov 2023 14:18:37 +0800 Subject: [PATCH 1/2] add environment definitions for todo terraform templates --- .../App_Service_with_Cosmos_using_TF/main.tf | 161 +++++++++++++++++ .../manifest.yaml | 31 ++++ .../modules/appservice/appservice_output.tf | 8 + .../appservice/appservice_variables.tf | 69 ++++++++ .../modules/appservice/appservicep.tf | 120 +++++++++++++ .../modules/keyvault/keyvault.tf | 75 ++++++++ .../modules/keyvault/keyvault_output.tf | 4 + .../modules/keyvault/keyvault_variables.tf | 41 +++++ .../output.tf | 42 +++++ .../provider.tf | 30 ++++ .../variables.tf | 28 +++ .../main.tf | 165 ++++++++++++++++++ .../manifest.yaml | 27 +++ .../modules/keyvault/keyvault.tf | 75 ++++++++ .../modules/keyvault/keyvault_output.tf | 4 + .../modules/keyvault/keyvault_variables.tf | 41 +++++ .../output.tf | 31 ++++ .../provider.tf | 30 ++++ .../variables.tf | 31 ++++ 19 files changed, 1013 insertions(+) create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/main.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_output.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_variables.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservicep.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_output.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_variables.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/output.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/provider.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/variables.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/main.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_output.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_variables.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/output.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/provider.tf create mode 100644 Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/variables.tf diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/main.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/main.tf new file mode 100644 index 0000000..39e1435 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/main.tf @@ -0,0 +1,161 @@ +locals { + tags = { azd-env-name : var.environment_name } + sha = base64encode(sha256("${var.environment_name}${var.location}${data.azurerm_client_config.current.subscription_id}")) + resource_token = substr(replace(lower(local.sha), "[^A-Za-z0-9_]", ""), 0, 13) + cosmos_connection_string_key = "AZURE-COSMOS-CONNECTION-STRING" + api_runtime = var.repoUrl=="https://github.com/azure-samples/todo-nodejs-mongo-terraform"?"18-lts":"3.10" +} +# ------------------------------------------------------------------------------------------------------ +# Deploy resource Group +# ------------------------------------------------------------------------------------------------------ +variable "resource_group_name" {} + +data "azurerm_resource_group" "rg" { + name = var.resource_group_name +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy application insights +# ------------------------------------------------------------------------------------------------------ +module "applicationinsights" { + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/applicationinsights" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + environment_name = var.environment_name + workspace_id = module.loganalytics.LOGANALYTICS_WORKSPACE_ID + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy log analytics +# ------------------------------------------------------------------------------------------------------ +module "loganalytics" { + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/loganalytics" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy key vault +# ------------------------------------------------------------------------------------------------------ +module "keyvault" { + source = "./modules/keyvault" + location = var.location + principal_id = var.principal_id + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token + access_policy_object_ids = [module.api.IDENTITY_PRINCIPAL_ID,var.env_principal_id] + secrets = [ + { + name = local.cosmos_connection_string_key + value = module.cosmos.AZURE_COSMOS_CONNECTION_STRING + } + ] +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy cosmos +# ------------------------------------------------------------------------------------------------------ +module "cosmos" { + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/cosmos" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service plan +# ------------------------------------------------------------------------------------------------------ +module "appserviceplan" { + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/appserviceplan" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service web app +# ------------------------------------------------------------------------------------------------------ +module "web" { + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/appservicenode" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + resource_token = local.resource_token + + tags = merge(local.tags, { azd-service-name : "web" }) + service_name = "web" + appservice_plan_id = module.appserviceplan.APPSERVICE_PLAN_ID + + app_settings = { + "SCM_DO_BUILD_DURING_DEPLOYMENT" = "false" + "REACT_APP_APPLICATIONINSIGHTS_CONNECTION_STRING" = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + "REACT_APP_API_BASE_URL" = "https://app-api-${local.resource_token}.azurewebsites.net" + } + + app_command_line = "./entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa" +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service api +# ------------------------------------------------------------------------------------------------------ +module "api" { + source = "./modules/appservice" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + resource_token = local.resource_token + runtime_version = local.api_runtime + + tags = merge(local.tags, { "azd-service-name" : "api" }) + service_name = "api" + appservice_plan_id = module.appserviceplan.APPSERVICE_PLAN_ID + app_settings = { + "AZURE_COSMOS_CONNECTION_STRING_KEY" = local.cosmos_connection_string_key + "AZURE_COSMOS_DATABASE_NAME" = module.cosmos.AZURE_COSMOS_DATABASE_NAME + "SCM_DO_BUILD_DURING_DEPLOYMENT" = "true" + "AZURE_KEY_VAULT_ENDPOINT" = module.keyvault.AZURE_KEY_VAULT_ENDPOINT + "APPLICATIONINSIGHTS_CONNECTION_STRING" = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + "API_ALLOW_ORIGINS" = "https://app-web-${local.resource_token}.azurewebsites.net" + } + + app_command_line = "" + + identity = [{ + type = "SystemAssigned" + }] +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service apim +# ------------------------------------------------------------------------------------------------------ +module "apim" { + count = var.useAPIM ? 1 : 0 + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/apim" + name = "apim-${local.resource_token}" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = merge(local.tags, { "azd-service-name" : var.environment_name }) + application_insights_name = module.applicationinsights.APPLICATIONINSIGHTS_NAME + sku = "Consumption" +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service apim-api +# ------------------------------------------------------------------------------------------------------ +module "apimApi" { + count = var.useAPIM ? 1 : 0 + source = "github.com/Azure-Samples/todo-python-mongo-terraform/infra/modules/apim-api" + name = module.apim[0].APIM_SERVICE_NAME + rg_name = data.azurerm_resource_group.rg.name + web_front_end_url = module.web.URI + api_management_logger_id = module.apim[0].API_MANAGEMENT_LOGGER_ID + api_name = "todo-api" + api_display_name = "Simple Todo API" + api_path = "todo" + api_backend_url = module.api.URI +} diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml new file mode 100644 index 0000000..c179db7 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml @@ -0,0 +1,31 @@ +name: App-Service-with-Cosmos-using-TF +summary: Creates App Service with Cosmos using TF +description: Deploys App Service with Cosmos environment using Terraform ,it is compatible with azd. +runner: Terraform +templatePath: main.tf +parameters: + - id: "environment_name" + name: "environment_name" + required: true + type: "string" + - id: "location" + name: "Location" + required: true + type: "string" + - id: "principal_id" + name: "principal_id" + required: true + type: "string" + - id: "env_principal_id" + name: "env_principal_id" + required: true + type: "string" + - id: "repoUrl" + name: "repoUrl" + required: true + type: "string" + description: Path the the application source code + allowed: + - "https://github.com/azure-samples/todo-nodejs-mongo-terraform" + - "https://github.com/azure-samples/todo-python-mongo-terraform" + \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_output.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_output.tf new file mode 100644 index 0000000..97037e9 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_output.tf @@ -0,0 +1,8 @@ +output "URI" { + value = var.runtime_version=="18-lts"?"https://${azurerm_linux_web_app.webnode[0].default_hostname}" :"https://${azurerm_linux_web_app.webpython[0].default_hostname}" +} + +output "IDENTITY_PRINCIPAL_ID" { + value = var.runtime_version=="18-lts"?(length(azurerm_linux_web_app.webnode[0].identity) == 0 ? "" : azurerm_linux_web_app.webnode[0].identity.0.principal_id):length(azurerm_linux_web_app.webpython[0].identity) == 0 ? "" : azurerm_linux_web_app.webpython[0].identity.0.principal_id + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_variables.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_variables.tf new file mode 100644 index 0000000..9f1d6b1 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservice_variables.tf @@ -0,0 +1,69 @@ +variable "location" { + description = "The supported Azure location where the resource deployed" + type = string +} + +variable "rg_name" { + description = "The name of the resource group to deploy resources into" + type = string +} + +variable "appservice_plan_id" { + description = "The id of the appservice plan to use." + type = string +} + +variable "service_name" { + description = "A name to reflect the type of the app service e.g: web, api." + type = string +} + +variable "app_settings" { + description = "A list of app settings pairs to be assigned to the app service" + type = map(string) +} + +variable "identity" { + description = "A list of application identity" + type = list(any) + default = [] +} + +variable "app_command_line" { + description = "The cmd line to configure the app to run." + type = string +} + +variable "tags" { + description = "A list of tags used for deployed services." + type = map(string) +} + +variable "resource_token" { + description = "A suffix string to centrally mitigate resource name collisions." + type = string +} + +variable "runtime_version" { + description = "the application stack python version to set for the app service." + type = string + default = "3.10" +} + +variable "always_on" { + description = "The always on setting for the app service." + type = bool + default = true +} + +variable "use_32_bit_worker" { + description = "The use 32 bit worker setting for the app service." + type = bool + default = false +} + +variable "health_check_path" { + description = "The path to the health check endpoint" + type = string + default = "" +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservicep.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservicep.tf new file mode 100644 index 0000000..e650445 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/appservice/appservicep.tf @@ -0,0 +1,120 @@ +terraform { + required_providers { + azurerm = { + version = "~>3.47.0" + source = "hashicorp/azurerm" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.2.24" + } + } +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service web app +# ------------------------------------------------------------------------------------------------------ +resource "azurecaf_name" "web_name" { + name = "${var.service_name}-${var.resource_token}" + resource_type = "azurerm_app_service" + random_length = 0 + clean_input = true +} + + +resource "azurerm_linux_web_app" "webpython" { + count = var.runtime_version=="3.10"?1:0 + name = azurecaf_name.web_name.result + location = var.location + resource_group_name = var.rg_name + service_plan_id = var.appservice_plan_id + https_only = true + tags = var.tags + + site_config { + always_on = var.always_on + use_32_bit_worker = var.use_32_bit_worker + ftps_state = "FtpsOnly" + app_command_line = var.app_command_line + application_stack { + python_version = var.runtime_version + } + health_check_path = var.health_check_path + } + + app_settings = var.app_settings + + dynamic "identity" { + for_each = { for k, v in var.identity : k => v if var.identity != [] } + content { + type = identity.value["type"] + } + } + + logs { + application_logs { + file_system_level = "Verbose" + } + detailed_error_messages = true + failed_request_tracing = true + http_logs { + file_system { + retention_in_days = 1 + retention_in_mb = 35 + } + } + } +} +resource "azurerm_linux_web_app" "webnode" { + count = var.runtime_version=="18-lts"?1:0 + name = azurecaf_name.web_name.result + location = var.location + resource_group_name = var.rg_name + service_plan_id = var.appservice_plan_id + https_only = true + tags = var.tags + + site_config { + always_on = var.always_on + use_32_bit_worker = var.use_32_bit_worker + ftps_state = "FtpsOnly" + app_command_line = var.app_command_line + application_stack { + node_version = var.runtime_version + } + health_check_path = var.health_check_path + } + + app_settings = var.app_settings + + dynamic "identity" { + for_each = { for k, v in var.identity : k => v if var.identity != [] } + content { + type = identity.value["type"] + } + } + + logs { + application_logs { + file_system_level = "Verbose" + } + detailed_error_messages = true + failed_request_tracing = true + http_logs { + file_system { + retention_in_days = 1 + retention_in_mb = 35 + } + } + } +} + +# This is a temporary solution until the azurerm provider supports the basicPublishingCredentialsPolicies resource type +resource "null_resource" "webapp_basic_auth_disable" { + triggers = { + account = var.runtime_version=="18-lts"?azurerm_linux_web_app.webnode[0].name:azurerm_linux_web_app.webpython[0].name + } + provisioner "local-exec" { + command = "az resource update --resource-group ${var.rg_name} --name ftp --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${var.runtime_version=="18-lts"?azurerm_linux_web_app.webnode[0].name:azurerm_linux_web_app.webpython[0].name} --set properties.allow=false && az resource update --resource-group ${var.rg_name} --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${var.runtime_version=="18-lts"?azurerm_linux_web_app.webnode[0].name:azurerm_linux_web_app.webpython[0].name} --set properties.allow=false" + } +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault.tf new file mode 100644 index 0000000..a575f26 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault.tf @@ -0,0 +1,75 @@ +terraform { + required_providers { + azurerm = { + version = "~>3.47.0" + source = "hashicorp/azurerm" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.2.24" + } + } +} + +data "azurerm_client_config" "current" {} +# ------------------------------------------------------------------------------------------------------ +# DEPLOY AZURE KEYVAULT +# ------------------------------------------------------------------------------------------------------ +resource "azurecaf_name" "kv_name" { + name = var.resource_token + resource_type = "azurerm_key_vault" + random_length = 0 + clean_input = true +} + +resource "azurerm_key_vault" "kv" { + name = azurecaf_name.kv_name.result + location = var.location + resource_group_name = var.rg_name + tenant_id = data.azurerm_client_config.current.tenant_id + purge_protection_enabled = false + sku_name = "standard" + + tags = var.tags +} + +resource "azurerm_key_vault_access_policy" "app" { + count = length(var.access_policy_object_ids) + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = var.access_policy_object_ids[count.index] + + secret_permissions = [ + "Get", + "Set", + "List", + "Delete", + "Purge" + ] +} + +resource "azurerm_key_vault_access_policy" "user" { + count = var.principal_id == "" ? 0 : 1 + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = var.principal_id + + secret_permissions = [ + "Get", + "Set", + "List", + "Delete", + "Purge" + ] +} + +resource "azurerm_key_vault_secret" "secrets" { + count = length(var.secrets) + name = var.secrets[count.index].name + value = var.secrets[count.index].value + key_vault_id = azurerm_key_vault.kv.id + depends_on = [ + azurerm_key_vault_access_policy.user, + azurerm_key_vault_access_policy.app + ] +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_output.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_output.tf new file mode 100644 index 0000000..745966f --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_output.tf @@ -0,0 +1,4 @@ +output "AZURE_KEY_VAULT_ENDPOINT" { + value = azurerm_key_vault.kv.vault_uri + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_variables.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_variables.tf new file mode 100644 index 0000000..ed7d6d8 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/modules/keyvault/keyvault_variables.tf @@ -0,0 +1,41 @@ +variable "location" { + description = "The supported Azure location where the resource deployed" + type = string +} + +variable "rg_name" { + description = "The name of the resource group to deploy resources into" + type = string +} + +variable "tags" { + description = "A list of tags used for deployed services." + type = map(string) +} + +variable "resource_token" { + description = "A suffix string to centrally mitigate resource name collisions." + type = string +} + +variable "principal_id" { + description = "The Id of the service principal to add to deployed keyvault access policies" + sensitive = true + type = string +} + +variable "access_policy_object_ids" { + description = "A list of object ids to be be added to the keyvault access policies" + type = list(string) + sensitive = true + default = [] +} + +variable "secrets" { + description = "A list of secrets to be added to the keyvault" + type = list(object({ + name = string + value = string + })) + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/output.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/output.tf new file mode 100644 index 0000000..0a7a507 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/output.tf @@ -0,0 +1,42 @@ +output "AZURE_COSMOS_CONNECTION_STRING_KEY" { + value = local.cosmos_connection_string_key +} + +output "AZURE_COSMOS_DATABASE_NAME" { + value = module.cosmos.AZURE_COSMOS_DATABASE_NAME +} + +output "AZURE_KEY_VAULT_ENDPOINT" { + value = module.keyvault.AZURE_KEY_VAULT_ENDPOINT + sensitive = true +} + +output "REACT_APP_WEB_BASE_URL" { + value = module.web.URI +} + +output "REACT_APP_API_BASE_URL" { + value = var.useAPIM ? module.apimApi[0].SERVICE_API_URI : module.api.URI +} + +output "AZURE_LOCATION" { + value = var.location +} + +output "APPLICATIONINSIGHTS_CONNECTION_STRING" { + value = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + sensitive = true +} + +output "REACT_APP_APPLICATIONINSIGHTS_CONNECTION_STRING" { + value = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + sensitive = true +} + +output "USE_APIM" { + value = var.useAPIM +} + +output "SERVICE_API_ENDPOINTS" { + value = var.useAPIM ? [ module.apimApi[0].SERVICE_API_URI, module.api.URI ] : [] +} diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/provider.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/provider.tf new file mode 100644 index 0000000..7cee933 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/provider.tf @@ -0,0 +1,30 @@ +#Set the terraform required version, and Configure the Azure Provider.Use local storage + +# Configure the Azure Provider +terraform { + required_version = ">= 1.1.7, < 2.0.0" + required_providers { + azurerm = { + version = "~>3.47.0" + source = "hashicorp/azurerm" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.2.24" + } + } +} + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +# Make client_id, tenant_id, subscription_id and object_id variables +data "azurerm_client_config" "current" {} diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/variables.tf b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/variables.tf new file mode 100644 index 0000000..95b3df0 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/variables.tf @@ -0,0 +1,28 @@ +variable "location" { + description = "The supported Azure location where the resource deployed" + type = string +} + +variable "environment_name" { + description = "The name of the azd environment to be deployed" + type = string +} + +variable "principal_id" { + description = "The Id of the azd service principal to add to deployed keyvault access policies" + type = string +} +variable "env_principal_id" { + description = "The Id of the Devcenter environment Type to add to deployed keyvault access policies" + type = string +} + +variable "useAPIM" { + description = "Flag to use Azure API Management to mediate the calls between the Web frontend and the backend API." + type = bool + default = false +} +variable "repoUrl" { + description = "Path the the application source code" + type = string +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/main.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/main.tf new file mode 100644 index 0000000..bd237f0 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/main.tf @@ -0,0 +1,165 @@ +locals { + tags = { azd-env-name : var.environment_name, spring-cloud-azure : true } + sha = base64encode(sha256("${var.environment_name}${var.location}${data.azurerm_client_config.current.subscription_id}")) + resource_token = substr(replace(lower(local.sha), "[^A-Za-z0-9_]", ""), 0, 13) + psql_connection_string_key = "AZURE-POSTGRESQL-URL" +} +# ------------------------------------------------------------------------------------------------------ +# Deploy resource Group +# ------------------------------------------------------------------------------------------------------ +variable "resource_group_name" {} + +data "azurerm_resource_group" "rg" { + name = var.resource_group_name +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy application insights +# ------------------------------------------------------------------------------------------------------ +module "applicationinsights" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/applicationinsights" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + environment_name = var.environment_name + workspace_id = module.loganalytics.LOGANALYTICS_WORKSPACE_ID + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy log analytics +# ------------------------------------------------------------------------------------------------------ +module "loganalytics" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/loganalytics" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy PostgreSQL +# ------------------------------------------------------------------------------------------------------ +module "postgresql" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/postgresql" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service plan +# ------------------------------------------------------------------------------------------------------ +module "appserviceplan" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/appserviceplan" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service web app +# ------------------------------------------------------------------------------------------------------ +module "web" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/appservicenode" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + resource_token = local.resource_token + + tags = merge(local.tags, { azd-service-name : "web" }) + service_name = "web" + appservice_plan_id = module.appserviceplan.APPSERVICE_PLAN_ID + app_settings = { + "SCM_DO_BUILD_DURING_DEPLOYMENT" = "false" + "REACT_APP_APPLICATIONINSIGHTS_CONNECTION_STRING" = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + "REACT_APP_API_BASE_URL" = "https://app-api-${local.resource_token}.azurewebsites.net" + } + + app_command_line = "./entrypoint.sh -o ./env-config.js && pm2 serve /home/site/wwwroot --no-daemon --spa" +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service api +# ------------------------------------------------------------------------------------------------------ +module "api" { + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/appservicejava" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + resource_token = local.resource_token + + tags = merge(local.tags, { "azd-service-name" : "api" }) + service_name = "api" + appservice_plan_id = module.appserviceplan.APPSERVICE_PLAN_ID + + app_settings = { + "SCM_DO_BUILD_DURING_DEPLOYMENT" = "true" + "APPLICATIONINSIGHTS_CONNECTION_STRING" = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + "AZURE_KEY_VAULT_ENDPOINT" = module.keyvault.AZURE_KEY_VAULT_ENDPOINT + "JAVA_OPTS" = "-Djdk.attach.allowAttachSelf=true" + } + + app_command_line = "" + + identity = [{ + type = "SystemAssigned" + }] +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy key vault +# ------------------------------------------------------------------------------------------------------ +module "keyvault" { + source = "./modules/keyvault" + location = var.location + principal_id = var.principal_id + rg_name = data.azurerm_resource_group.rg.name + tags = local.tags + resource_token = local.resource_token + access_policy_object_ids = [module.api.IDENTITY_PRINCIPAL_ID,var.env_principal_id] + secrets = [ + { + name = local.psql_connection_string_key + value = module.postgresql.AZURE_POSTGRESQL_SPRING_DATASOURCE_URL + }, + { + name = "AZURE-POSTGRESQL-USERNAME" + value = module.postgresql.AZURE_POSTGRESQL_USERNAME + }, + { + name = "AZURE-POSTGRESQL-PASSWORD" + value = module.postgresql.AZURE_POSTGRESQL_PASSWORD + } + ] +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service apim +# ------------------------------------------------------------------------------------------------------ +module "apim" { + count = var.useAPIM ? 1 : 0 + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/apim" + name = "apim-${local.resource_token}" + location = var.location + rg_name = data.azurerm_resource_group.rg.name + tags = merge(local.tags, { "azd-service-name" : var.environment_name }) + application_insights_name = module.applicationinsights.APPLICATIONINSIGHTS_NAME + sku = "Consumption" +} + +# ------------------------------------------------------------------------------------------------------ +# Deploy app service apim-api +# ------------------------------------------------------------------------------------------------------ +module "apimApi" { + count = var.useAPIM ? 1 : 0 + source = "github.com/Azure-Samples/todo-java-postgresql-terraform/infra/modules/apim-api" + name = module.apim[0].APIM_SERVICE_NAME + rg_name = data.azurerm_resource_group.rg.name + web_front_end_url = module.web.URI + api_management_logger_id = module.apim[0].API_MANAGEMENT_LOGGER_ID + api_name = "todo-api" + api_display_name = "Simple Todo API" + api_path = "todo" + api_backend_url = module.api.URI +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml new file mode 100644 index 0000000..8330cd1 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml @@ -0,0 +1,27 @@ +name: App-service-with-PostgreSQL-using-TF +summary: Creates App service with PostgreSQL using TF +description: Deploys App service with PostgreSQL environment using Terraform, it is compatible with azd. +runner: Terraform +templatePath: main.tf +parameters: + - id: "environment_name" + name: "environment_name" + required: true + type: "string" + - id: "location" + name: "Location" + required: true + type: "string" + - id: "principal_id" + name: "principal_id" + required: true + type: "string" + - id: "env_principal_id" + name: "env_principal_id" + required: true + type: "string" + - id: repoUrl + name: repoUrl + type: string + description: Path the the application source code + default: "https://github.com/azure-samples/todo-java-postgresSQL-terraform" \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault.tf new file mode 100644 index 0000000..a575f26 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault.tf @@ -0,0 +1,75 @@ +terraform { + required_providers { + azurerm = { + version = "~>3.47.0" + source = "hashicorp/azurerm" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.2.24" + } + } +} + +data "azurerm_client_config" "current" {} +# ------------------------------------------------------------------------------------------------------ +# DEPLOY AZURE KEYVAULT +# ------------------------------------------------------------------------------------------------------ +resource "azurecaf_name" "kv_name" { + name = var.resource_token + resource_type = "azurerm_key_vault" + random_length = 0 + clean_input = true +} + +resource "azurerm_key_vault" "kv" { + name = azurecaf_name.kv_name.result + location = var.location + resource_group_name = var.rg_name + tenant_id = data.azurerm_client_config.current.tenant_id + purge_protection_enabled = false + sku_name = "standard" + + tags = var.tags +} + +resource "azurerm_key_vault_access_policy" "app" { + count = length(var.access_policy_object_ids) + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = var.access_policy_object_ids[count.index] + + secret_permissions = [ + "Get", + "Set", + "List", + "Delete", + "Purge" + ] +} + +resource "azurerm_key_vault_access_policy" "user" { + count = var.principal_id == "" ? 0 : 1 + key_vault_id = azurerm_key_vault.kv.id + tenant_id = data.azurerm_client_config.current.tenant_id + object_id = var.principal_id + + secret_permissions = [ + "Get", + "Set", + "List", + "Delete", + "Purge" + ] +} + +resource "azurerm_key_vault_secret" "secrets" { + count = length(var.secrets) + name = var.secrets[count.index].name + value = var.secrets[count.index].value + key_vault_id = azurerm_key_vault.kv.id + depends_on = [ + azurerm_key_vault_access_policy.user, + azurerm_key_vault_access_policy.app + ] +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_output.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_output.tf new file mode 100644 index 0000000..745966f --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_output.tf @@ -0,0 +1,4 @@ +output "AZURE_KEY_VAULT_ENDPOINT" { + value = azurerm_key_vault.kv.vault_uri + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_variables.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_variables.tf new file mode 100644 index 0000000..ed7d6d8 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/modules/keyvault/keyvault_variables.tf @@ -0,0 +1,41 @@ +variable "location" { + description = "The supported Azure location where the resource deployed" + type = string +} + +variable "rg_name" { + description = "The name of the resource group to deploy resources into" + type = string +} + +variable "tags" { + description = "A list of tags used for deployed services." + type = map(string) +} + +variable "resource_token" { + description = "A suffix string to centrally mitigate resource name collisions." + type = string +} + +variable "principal_id" { + description = "The Id of the service principal to add to deployed keyvault access policies" + sensitive = true + type = string +} + +variable "access_policy_object_ids" { + description = "A list of object ids to be be added to the keyvault access policies" + type = list(string) + sensitive = true + default = [] +} + +variable "secrets" { + description = "A list of secrets to be added to the keyvault" + type = list(object({ + name = string + value = string + })) + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/output.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/output.tf new file mode 100644 index 0000000..05814d4 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/output.tf @@ -0,0 +1,31 @@ +output "AZURE_POSTGRESQL_ENDPOINT" { + value = module.postgresql.AZURE_POSTGRESQL_FQDN + sensitive = true +} + +output "REACT_APP_WEB_BASE_URL" { + value = module.web.URI +} + +output "REACT_APP_API_BASE_URL" { + value = var.useAPIM ? module.apimApi[0].SERVICE_API_URI : module.api.URI +} + +output "AZURE_LOCATION" { + value = var.location +} + +output "APPLICATIONINSIGHTS_CONNECTION_STRING" { + value = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + sensitive = true +} + +output "REACT_APP_APPLICATIONINSIGHTS_CONNECTION_STRING" { + value = module.applicationinsights.APPLICATIONINSIGHTS_CONNECTION_STRING + sensitive = true +} + +output "AZURE_KEY_VAULT_ENDPOINT" { + value = module.keyvault.AZURE_KEY_VAULT_ENDPOINT + sensitive = true +} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/provider.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/provider.tf new file mode 100644 index 0000000..abc385c --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/provider.tf @@ -0,0 +1,30 @@ +#Set the terraform required version, and Configure the Azure Provider.Use local storage + +# Configure the Azure Provider +terraform { + required_version = ">= 1.1.7, < 2.0.0" + required_providers { + azurerm = { + version = "~>3.47.0" + source = "hashicorp/azurerm" + } + azurecaf = { + source = "aztfmod/azurecaf" + version = "~>1.2.24" + } + } +} + +provider "azurerm" { + features { + key_vault { + purge_soft_delete_on_destroy = false + } + resource_group { + prevent_deletion_if_contains_resources = false + } + } +} + +# Make client_id, tenant_id, subscription_id and object_id variables +data "azurerm_client_config" "current" {} \ No newline at end of file diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/variables.tf b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/variables.tf new file mode 100644 index 0000000..5090b97 --- /dev/null +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/variables.tf @@ -0,0 +1,31 @@ +variable "location" { + description = "The supported Azure location where the resource deployed" + type = string +} + +variable "environment_name" { + description = "The name of the azd environment to be deployed" + type = string +} + +variable "principal_id" { + description = "The Id of the azd service principal to add to deployed keyvault access policies" + type = string +} + +variable "env_principal_id" { + description = "The Id of the Devcenter environment Type to add to deployed keyvault access policies" + type = string +} + +variable "client_id" { + description = "Client id of current account" + type = string + default = "" +} + +variable "useAPIM" { + description = "Flag to use Azure API Management to mediate the calls between the Web frontend and the backend API." + type = bool + default = false +} \ No newline at end of file From c492619a7975003a7041a51759dfe67f35a7f61f Mon Sep 17 00:00:00 2001 From: Di Jiao Date: Wed, 15 Nov 2023 11:13:37 +0800 Subject: [PATCH 2/2] canonical name --- .../App_Service_with_Cosmos_using_TF/manifest.yaml | 10 +++++----- .../App_Service_with_PostgreSQL_using_TF/manifest.yaml | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml index c179db7..33dd24d 100644 --- a/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml +++ b/Environment-Definitions/Terraform/App_Service_with_Cosmos_using_TF/manifest.yaml @@ -1,11 +1,11 @@ name: App-Service-with-Cosmos-using-TF summary: Creates App Service with Cosmos using TF -description: Deploys App Service with Cosmos environment using Terraform ,it is compatible with azd. +description: Deploys App Service with Cosmos environment using Terraform, it is compatible with azd. runner: Terraform templatePath: main.tf parameters: - id: "environment_name" - name: "environment_name" + name: "Environment Name" required: true type: "string" - id: "location" @@ -13,15 +13,15 @@ parameters: required: true type: "string" - id: "principal_id" - name: "principal_id" + name: "Principal Id" required: true type: "string" - id: "env_principal_id" - name: "env_principal_id" + name: "Env Principal Id" required: true type: "string" - id: "repoUrl" - name: "repoUrl" + name: "Repository URL" required: true type: "string" description: Path the the application source code diff --git a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml index 8330cd1..1884dd0 100644 --- a/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml +++ b/Environment-Definitions/Terraform/App_Service_with_PostgreSQL_using_TF/manifest.yaml @@ -5,7 +5,7 @@ runner: Terraform templatePath: main.tf parameters: - id: "environment_name" - name: "environment_name" + name: "Environment Name" required: true type: "string" - id: "location" @@ -13,15 +13,15 @@ parameters: required: true type: "string" - id: "principal_id" - name: "principal_id" + name: "Principal Id" required: true type: "string" - id: "env_principal_id" - name: "env_principal_id" + name: "Env Principal Id" required: true type: "string" - - id: repoUrl - name: repoUrl + - id: "repoUrl" + name: "Repository URL" type: string description: Path the the application source code default: "https://github.com/azure-samples/todo-java-postgresSQL-terraform" \ No newline at end of file