├── .gitignore ├── infra ├── main.tfvars.json ├── core │ ├── monitor │ │ ├── loganalytics │ │ │ ├── loganalytics_output.tf │ │ │ ├── loganalytics_variables.tf │ │ │ └── loganalytics.tf │ │ └── applicationinsights │ │ │ ├── applicationinsights_output.tf │ │ │ ├── applicationinsights_variables.tf │ │ │ └── applicationinsights.tf │ ├── gateway │ │ ├── apim-api │ │ │ ├── apim-api_output.tf │ │ │ ├── apim-api_variables.tf │ │ │ └── apim-api.tf │ │ └── apim │ │ │ ├── apim_output.tf │ │ │ ├── apim_variables.tf │ │ │ └── apim.tf │ ├── host │ │ ├── appserviceplan │ │ │ ├── appserviceplan_output.tf │ │ │ ├── appserviceplan_variables.tf │ │ │ └── appserviceplan.tf │ │ └── appservice │ │ │ ├── appservicejava │ │ │ ├── appservicejava_output.tf │ │ │ ├── appservicejava_variables.tf │ │ │ └── appservicejava.tf │ │ │ ├── appservicenode │ │ │ ├── appservicenode_output.tf │ │ │ ├── appservicenode_variables.tf │ │ │ └── appservicenode.tf │ │ │ └── appservicepython │ │ │ ├── appservicepython_output.tf │ │ │ ├── appservicepython_variables.tf │ │ │ └── appservicepython.tf │ ├── security │ │ └── keyvault │ │ │ ├── keyvault_output.tf │ │ │ ├── keyvault_variables.tf │ │ │ └── keyvault.tf │ └── database │ │ ├── cosmos │ │ ├── cosmos_output.tf │ │ ├── cosmos_variables.tf │ │ └── cosmos.tf │ │ └── postgresql │ │ ├── postgresql_output.tf │ │ ├── postgresql_variables.tf │ │ └── postgresql.tf ├── variables.tf ├── output.tf ├── provider.tf └── main.tf ├── azure.yaml ├── .devcontainer └── devcontainer.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | .azure -------------------------------------------------------------------------------- /infra/main.tfvars.json: -------------------------------------------------------------------------------- 1 | { 2 | "location": "${AZURE_LOCATION}", 3 | "environment_name": "${AZURE_ENV_NAME}" 4 | } 5 | -------------------------------------------------------------------------------- /infra/core/monitor/loganalytics/loganalytics_output.tf: -------------------------------------------------------------------------------- 1 | output "LOGANALYTICS_WORKSPACE_ID" { 2 | value = azurerm_log_analytics_workspace.workspace.id 3 | } -------------------------------------------------------------------------------- /infra/core/gateway/apim-api/apim-api_output.tf: -------------------------------------------------------------------------------- 1 | output "SERVICE_API_URI" { 2 | value = "${data.azurerm_api_management.apim.gateway_url}/${var.api_path}" 3 | } 4 | -------------------------------------------------------------------------------- /infra/core/host/appserviceplan/appserviceplan_output.tf: -------------------------------------------------------------------------------- 1 | output "APPSERVICE_PLAN_ID" { 2 | value = azurerm_service_plan.plan.id 3 | sensitive = true 4 | } -------------------------------------------------------------------------------- /infra/core/security/keyvault/keyvault_output.tf: -------------------------------------------------------------------------------- 1 | output "AZURE_KEY_VAULT_ENDPOINT" { 2 | value = azurerm_key_vault.kv.vault_uri 3 | sensitive = true 4 | } -------------------------------------------------------------------------------- /infra/core/gateway/apim/apim_output.tf: -------------------------------------------------------------------------------- 1 | output "APIM_SERVICE_NAME" { 2 | value = azurerm_api_management.apim.name 3 | } 4 | 5 | output "API_MANAGEMENT_LOGGER_ID" { 6 | value = azurerm_api_management_logger.logger.id 7 | } 8 | -------------------------------------------------------------------------------- /infra/core/database/cosmos/cosmos_output.tf: -------------------------------------------------------------------------------- 1 | output "AZURE_COSMOS_CONNECTION_STRING" { 2 | value = azurerm_cosmosdb_account.db.connection_strings[0] 3 | sensitive = true 4 | } 5 | 6 | output "AZURE_COSMOS_DATABASE_NAME" { 7 | value = azurerm_cosmosdb_mongo_database.mongodb.name 8 | } -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicejava/appservicejava_output.tf: -------------------------------------------------------------------------------- 1 | output "URI" { 2 | value = "https://${azurerm_linux_web_app.web.default_hostname}" 3 | } 4 | 5 | output "IDENTITY_PRINCIPAL_ID" { 6 | value = length(azurerm_linux_web_app.web.identity) == 0 ? "" : azurerm_linux_web_app.web.identity.0.principal_id 7 | sensitive = true 8 | } -------------------------------------------------------------------------------- /infra/variables.tf: -------------------------------------------------------------------------------- 1 | # Input variables for the module 2 | 3 | variable "location" { 4 | description = "The supported Azure location where the resource deployed" 5 | type = string 6 | } 7 | 8 | variable "environment_name" { 9 | description = "The name of the azd environment to be deployed" 10 | type = string 11 | } 12 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicenode/appservicenode_output.tf: -------------------------------------------------------------------------------- 1 | output "URI" { 2 | value = "https://${azurerm_linux_web_app.web.default_hostname}" 3 | } 4 | 5 | output "IDENTITY_PRINCIPAL_ID" { 6 | value = length(azurerm_linux_web_app.web.identity) == 0 ? "" : azurerm_linux_web_app.web.identity.0.principal_id 7 | sensitive = true 8 | } 9 | 10 | output "APPSERVICE_NAME" { 11 | value = azurerm_linux_web_app.web.name 12 | } 13 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicepython/appservicepython_output.tf: -------------------------------------------------------------------------------- 1 | output "URI" { 2 | value = "https://${azurerm_linux_web_app.web.default_hostname}" 3 | } 4 | 5 | output "IDENTITY_PRINCIPAL_ID" { 6 | value = length(azurerm_linux_web_app.web.identity) == 0 ? "" : azurerm_linux_web_app.web.identity.0.principal_id 7 | sensitive = true 8 | } 9 | output "APPSERVICE_NAME" { 10 | value = azurerm_linux_web_app.web.name 11 | } 12 | -------------------------------------------------------------------------------- /infra/core/monitor/applicationinsights/applicationinsights_output.tf: -------------------------------------------------------------------------------- 1 | output "APPLICATIONINSIGHTS_CONNECTION_STRING" { 2 | value = azurerm_application_insights.applicationinsights.connection_string 3 | sensitive = true 4 | } 5 | 6 | output "APPLICATIONINSIGHTS_NAME" { 7 | value = azurerm_application_insights.applicationinsights.name 8 | sensitive = false 9 | } 10 | 11 | output "APPLICATIONINSIGHTS_INSTRUMENTATION_KEY" { 12 | value = azurerm_application_insights.applicationinsights.instrumentation_key 13 | sensitive = true 14 | } 15 | -------------------------------------------------------------------------------- /infra/core/database/cosmos/cosmos_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "tags" { 12 | description = "A list of tags used for deployed services." 13 | type = map(string) 14 | } 15 | 16 | variable "resource_token" { 17 | description = "A suffix string to centrally mitigate resource name collisions." 18 | type = string 19 | } -------------------------------------------------------------------------------- /infra/core/monitor/loganalytics/loganalytics_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "resource_token" { 12 | description = "A suffix string to centrally mitigate resource name collisions." 13 | type = string 14 | } 15 | 16 | variable "tags" { 17 | description = "A list of tags used for deployed services." 18 | type = map(string) 19 | } -------------------------------------------------------------------------------- /infra/output.tf: -------------------------------------------------------------------------------- 1 | # Declare output values for the main terraform module. 2 | # 3 | # This allows the main terraform module outputs to be referenced by other modules, 4 | # or by the local machine as a way to reference created resources in Azure for local development. 5 | # Secrets should not be added here. 6 | # 7 | # Outputs are automatically saved in the local azd environment .env file. 8 | # To see these outputs, run `azd env get-values`. `azd env get-values --output json` for json output. 9 | 10 | output "AZURE_LOCATION" { 11 | value = var.location 12 | } 13 | 14 | output "AZURE_TENANT_ID" { 15 | value = data.azurerm_client_config.current.tenant_id 16 | } 17 | -------------------------------------------------------------------------------- /infra/core/database/postgresql/postgresql_output.tf: -------------------------------------------------------------------------------- 1 | output "AZURE_POSTGRESQL_DATABASE_NAME" { 2 | value = azurerm_postgresql_flexible_server_database.database.name 3 | sensitive = true 4 | } 5 | 6 | output "AZURE_POSTGRESQL_FQDN" { 7 | value = azurerm_postgresql_flexible_server.psql_server.fqdn 8 | } 9 | 10 | output "AZURE_POSTGRESQL_SPRING_DATASOURCE_URL" { 11 | value = "jdbc:postgresql://${azurerm_postgresql_flexible_server.psql_server.fqdn}:5432/${azurerm_postgresql_flexible_server_database.database.name}?sslmode=require" 12 | } 13 | 14 | output "AZURE_POSTGRESQL_USERNAME" { 15 | value = local.psqlUserName 16 | } 17 | 18 | output "AZURE_POSTGRESQL_PASSWORD" { 19 | value = random_password.password[1].result 20 | sensitive = true 21 | } -------------------------------------------------------------------------------- /infra/provider.tf: -------------------------------------------------------------------------------- 1 | # Configure desired versions of terraform, azurerm provider 2 | terraform { 3 | required_version = ">= 1.1.7, < 2.0.0" 4 | required_providers { 5 | azurerm = { 6 | version = "~>3.97.1" 7 | source = "hashicorp/azurerm" 8 | } 9 | azurecaf = { 10 | source = "aztfmod/azurecaf" 11 | version = "~>1.2.24" 12 | } 13 | } 14 | } 15 | 16 | # Enable features for azurerm 17 | provider "azurerm" { 18 | skip_provider_registration = "true" 19 | features { 20 | key_vault { 21 | purge_soft_delete_on_destroy = false 22 | } 23 | resource_group { 24 | prevent_deletion_if_contains_resources = false 25 | } 26 | } 27 | } 28 | 29 | # Access client_id, tenant_id, subscription_id and object_id configuration values 30 | data "azurerm_client_config" "current" {} 31 | -------------------------------------------------------------------------------- /infra/core/database/postgresql/postgresql_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "tags" { 12 | description = "A list of tags used for deployed services." 13 | type = map(string) 14 | } 15 | 16 | variable "resource_token" { 17 | description = "A suffix string to centrally mitigate resource name collisions." 18 | type = string 19 | } 20 | 21 | variable "administrator_login" { 22 | type = string 23 | description = "The PostgreSQL administrator login" 24 | default = "psqladmin" 25 | } 26 | 27 | variable "database_name" { 28 | type = string 29 | description = "The database name of PostgreSQL" 30 | default = "todo" 31 | } -------------------------------------------------------------------------------- /infra/core/monitor/applicationinsights/applicationinsights_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "environment_name" { 12 | description = "The name of the environment to be deployed" 13 | type = string 14 | } 15 | 16 | variable "workspace_id" { 17 | description = "The name of the Azure log analytics workspace" 18 | type = string 19 | } 20 | 21 | variable "tags" { 22 | description = "A list of tags used for deployed services." 23 | type = map(string) 24 | } 25 | 26 | variable "resource_token" { 27 | description = "A suffix string to centrally mitigate resource name collisions." 28 | type = string 29 | } -------------------------------------------------------------------------------- /infra/core/host/appserviceplan/appserviceplan_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "tags" { 12 | description = "A list of tags used for deployed services." 13 | type = map(string) 14 | } 15 | 16 | variable "resource_token" { 17 | description = "A suffix string to centrally mitigate resource name collisions." 18 | type = string 19 | } 20 | 21 | variable "sku_name" { 22 | description = "The SKU for the plan." 23 | type = string 24 | default = "B1" 25 | } 26 | 27 | variable "os_type" { 28 | description = "The O/S type for the App Services to be hosted in this plan." 29 | type = string 30 | default = "Linux" 31 | } -------------------------------------------------------------------------------- /infra/core/host/appserviceplan/appserviceplan.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy app service plan 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "plan_name" { 17 | name = var.resource_token 18 | resource_type = "azurerm_app_service_plan" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_service_plan" "plan" { 24 | name = azurecaf_name.plan_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | os_type = var.os_type 28 | sku_name = var.sku_name 29 | 30 | tags = var.tags 31 | } 32 | -------------------------------------------------------------------------------- /infra/core/monitor/loganalytics/loganalytics.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy log analytics workspace 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "workspace_name" { 17 | name = var.resource_token 18 | resource_type = "azurerm_log_analytics_workspace" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_log_analytics_workspace" "workspace" { 24 | name = azurecaf_name.workspace_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | sku = "PerGB2018" 28 | retention_in_days = 30 29 | tags = var.tags 30 | } 31 | -------------------------------------------------------------------------------- /infra/core/security/keyvault/keyvault_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "tags" { 12 | description = "A list of tags used for deployed services." 13 | type = map(string) 14 | } 15 | 16 | variable "resource_token" { 17 | description = "A suffix string to centrally mitigate resource name collisions." 18 | type = string 19 | } 20 | 21 | variable "principal_id" { 22 | description = "The Id of the service principal to add to deployed keyvault access policies" 23 | sensitive = true 24 | type = string 25 | } 26 | 27 | variable "access_policy_object_ids" { 28 | description = "A list of object ids to be be added to the keyvault access policies" 29 | type = list(string) 30 | sensitive = true 31 | default = [] 32 | } 33 | 34 | variable "secrets" { 35 | description = "A list of secrets to be added to the keyvault" 36 | type = list(object({ 37 | name = string 38 | value = string 39 | })) 40 | sensitive = true 41 | } -------------------------------------------------------------------------------- /infra/core/gateway/apim-api/apim-api_variables.tf: -------------------------------------------------------------------------------- 1 | variable "name" { 2 | type = string 3 | } 4 | 5 | variable "rg_name" { 6 | description = "The name of the resource group to deploy resources into" 7 | type = string 8 | } 9 | 10 | variable "api_management_logger_id" { 11 | description = "The name of the resource application insights" 12 | type = string 13 | } 14 | 15 | variable "web_front_end_url" { 16 | description = "The url of the web" 17 | type = string 18 | } 19 | 20 | variable "api_backend_url" { 21 | description = "Absolute URL of the backend service implementing this API." 22 | type = string 23 | } 24 | 25 | variable "api_name" { 26 | description = "Resource name to uniquely identify this API within the API Management service instance" 27 | type = string 28 | } 29 | 30 | variable "api_display_name" { 31 | 32 | description = "The Display Name of the API" 33 | type = string 34 | } 35 | 36 | variable "api_path" { 37 | description = "Relative URL uniquely identifying this API and all of its resource paths within the API Management service instance. It is appended to the API endpoint base URL specified during the service instance creation to form a public URL for this API." 38 | type = string 39 | } 40 | -------------------------------------------------------------------------------- /infra/main.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | tags = { azd-env-name : var.environment_name } 3 | sha = base64encode(sha256("${var.environment_name}${var.location}${data.azurerm_client_config.current.subscription_id}")) 4 | resource_token = substr(replace(lower(local.sha), "[^A-Za-z0-9_]", ""), 0, 13) 5 | } 6 | 7 | resource "azurecaf_name" "rg_name" { 8 | name = var.environment_name 9 | resource_type = "azurerm_resource_group" 10 | random_length = 0 11 | clean_input = true 12 | } 13 | 14 | # Deploy resource group 15 | resource "azurerm_resource_group" "rg" { 16 | name = azurecaf_name.rg_name.result 17 | location = var.location 18 | // Tag the resource group with the azd environment name 19 | // This should also be applied to all resources created in this module 20 | tags = { azd-env-name : var.environment_name } 21 | } 22 | 23 | # Add resources to be provisioned below. 24 | # To learn more, https://developer.hashicorp.com/terraform/tutorials/azure-get-started/azure-change 25 | # Note that a tag: 26 | # azd-service-name: "" 27 | # should be applied to targeted service host resources, such as: 28 | # azurerm_linux_web_app, azurerm_windows_web_app for appservice 29 | # azurerm_function_app for function 30 | -------------------------------------------------------------------------------- /infra/core/gateway/apim/apim_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "tags" { 12 | description = "A list of tags used for deployed services." 13 | type = map(string) 14 | } 15 | 16 | variable "sku" { 17 | description = "The pricing tier of this API Management service." 18 | type = string 19 | default = "Consumption" 20 | } 21 | 22 | variable "application_insights_name" { 23 | description = "Azure Application Insights Name." 24 | type = string 25 | } 26 | 27 | variable "skuCount" { 28 | description = "The instance size of this API Management service. @allowed([ 0, 1, 2 ])" 29 | type = string 30 | default = "0" 31 | } 32 | 33 | variable "name" { 34 | type = string 35 | } 36 | 37 | variable "publisher_email" { 38 | description = "The email address of the owner of the service." 39 | type = string 40 | default = "noreply@microsoft.com" 41 | } 42 | 43 | variable "publisher_name" { 44 | description = "The name of the owner of the service" 45 | type = string 46 | default = "n/a" 47 | } 48 | -------------------------------------------------------------------------------- /azure.yaml: -------------------------------------------------------------------------------- 1 | # yaml-language-server: $schema=https://raw.githubusercontent.com/Azure/azure-dev/main/schemas/alpha/azure.yaml.json 2 | 3 | # This is an example starter azure.yaml file containing several example services in comments below. 4 | # Make changes as needed to describe your application setup. 5 | # To learn more about the azure.yaml file, visit https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/azd-schema 6 | 7 | # Name of the application. 8 | name: azd-starter 9 | # services: 10 | # ## An example for a python API service. 11 | # ## The service is named 'python-api'. 12 | # ## The language is 'python'. 13 | # ## The source code is located in the project (azure.yaml) directory. 14 | # ## The service will be hosted on Azure App Service. 15 | # python-api: 16 | # language: python 17 | # project: ./ 18 | # host: appservice 19 | # ## An example for a NodeJS API, located in src/api. 20 | # nodejs-api: 21 | # language: js 22 | # project: ./src/api 23 | # host: appservice 24 | # ## An example for a React front-end app. 25 | # ## The src/react-app/build folder is where the app is built to after `npm run build`. 26 | # react-web: 27 | # language: js 28 | # project: ./src/react-app 29 | # host: appservice 30 | # dist: build 31 | infra: 32 | provider: terraform 33 | -------------------------------------------------------------------------------- /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Azure Developer CLI", 3 | "image": "mcr.microsoft.com/devcontainers/python:3.10-bullseye", 4 | "features": { 5 | // terraform and az (required for auth) are installed by default 6 | // See https://containers.dev/features for list of features 7 | "ghcr.io/devcontainers/features/azure-cli:1": { 8 | }, 9 | "ghcr.io/devcontainers/features/docker-in-docker:2": { 10 | }, 11 | "ghcr.io/devcontainers/features/terraform:1": { 12 | "version": "latest" 13 | }, 14 | "ghcr.io/azure/azure-dev/azd:latest": {} 15 | }, 16 | "customizations": { 17 | "vscode": { 18 | "extensions": [ 19 | "GitHub.vscode-github-actions", 20 | "hashicorp.terraform", 21 | "ms-azuretools.azure-dev", 22 | "ms-azuretools.vscode-azurefunctions", 23 | "ms-azuretools.vscode-docker" 24 | // Include other VSCode extensions if needed 25 | // Right click on an extension inside VSCode to add directly to devcontainer.json, or copy the extension ID 26 | ] 27 | } 28 | }, 29 | "forwardPorts": [ 30 | // Forward ports if needed for local development 31 | ], 32 | "postCreateCommand": "", 33 | "remoteUser": "vscode", 34 | "hostRequirements": { 35 | "memory": "8gb" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicejava/appservicejava_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "appservice_plan_id" { 12 | description = "The id of the appservice plan to use." 13 | type = string 14 | } 15 | 16 | variable "service_name" { 17 | description = "A name to reflect the type of the app service e.g: web, api." 18 | type = string 19 | } 20 | 21 | variable "app_settings" { 22 | description = "A list of app settings pairs to be assigned to the app service" 23 | type = map(string) 24 | } 25 | 26 | variable "identity" { 27 | description = "A list of application identity" 28 | type = list(any) 29 | default = [] 30 | } 31 | 32 | variable "app_command_line" { 33 | description = "The cmd line to configure the app to run." 34 | type = string 35 | } 36 | 37 | variable "tags" { 38 | description = "A list of tags used for deployed services." 39 | type = map(string) 40 | } 41 | 42 | variable "resource_token" { 43 | description = "A suffix string to centrally mitigate resource name collisions." 44 | type = string 45 | } 46 | 47 | variable "java_version" { 48 | description = "the application stack java version to set for the app service." 49 | type = string 50 | default = "17" 51 | } 52 | -------------------------------------------------------------------------------- /infra/core/gateway/apim/apim.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | 14 | data "azurerm_application_insights" "appinsights"{ 15 | name = var.application_insights_name 16 | resource_group_name = var.rg_name 17 | } 18 | # ------------------------------------------------------------------------------------------------------ 19 | # Deploy api management service 20 | # ------------------------------------------------------------------------------------------------------ 21 | 22 | # Create a new APIM instance 23 | resource "azurerm_api_management" "apim" { 24 | name = var.name 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | publisher_name = var.publisher_name 28 | publisher_email = var.publisher_email 29 | tags = var.tags 30 | sku_name = "${var.sku}_${(var.sku == "Consumption") ? 0 : ((var.sku == "Developer") ? 1 : var.skuCount)}" 31 | identity { 32 | type = "SystemAssigned" 33 | } 34 | } 35 | 36 | # Create Logger 37 | resource "azurerm_api_management_logger" "logger" { 38 | name = "app-insights-logger" 39 | api_management_name = azurerm_api_management.apim.name 40 | resource_group_name = var.rg_name 41 | 42 | application_insights { 43 | instrumentation_key = data.azurerm_application_insights.appinsights.instrumentation_key 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicejava/appservicejava.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy app service web app 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "web_name" { 17 | name = "${var.service_name}-${var.resource_token}" 18 | resource_type = "azurerm_app_service" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_linux_web_app" "web" { 24 | name = azurecaf_name.web_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | service_plan_id = var.appservice_plan_id 28 | https_only = true 29 | tags = var.tags 30 | 31 | site_config { 32 | always_on = true 33 | ftps_state = "FtpsOnly" 34 | app_command_line = var.app_command_line 35 | application_stack { 36 | java_version = var.java_version 37 | java_server = "JAVA" 38 | java_server_version = var.java_version 39 | } 40 | } 41 | 42 | app_settings = var.app_settings 43 | 44 | dynamic "identity" { 45 | for_each = { for k, v in var.identity : k => v if var.identity != [] } 46 | content { 47 | type = identity.value["type"] 48 | } 49 | } 50 | 51 | logs { 52 | application_logs { 53 | file_system_level = "Verbose" 54 | } 55 | detailed_error_messages = true 56 | failed_request_tracing = true 57 | http_logs { 58 | file_system { 59 | retention_in_days = 1 60 | retention_in_mb = 35 61 | } 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicenode/appservicenode_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "appservice_plan_id" { 12 | description = "The id of the appservice plan to use." 13 | type = string 14 | } 15 | 16 | variable "service_name" { 17 | description = "A name to reflect the type of the app service e.g: web, api." 18 | type = string 19 | } 20 | 21 | variable "app_settings" { 22 | description = "A list of app settings pairs to be assigned to the app service" 23 | type = map(string) 24 | } 25 | 26 | variable "identity" { 27 | description = "A list of application identity" 28 | type = list(any) 29 | default = [] 30 | } 31 | 32 | variable "app_command_line" { 33 | description = "The cmd line to configure the app to run." 34 | type = string 35 | } 36 | 37 | variable "tags" { 38 | description = "A list of tags used for deployed services." 39 | type = map(string) 40 | } 41 | 42 | variable "resource_token" { 43 | description = "A suffix string to centrally mitigate resource name collisions." 44 | type = string 45 | } 46 | 47 | variable "node_version" { 48 | description = "the application stack node version to set for the app service." 49 | type = string 50 | default = "20-lts" 51 | } 52 | 53 | variable "always_on" { 54 | description = "The always on setting for the app service." 55 | type = bool 56 | default = true 57 | } 58 | 59 | variable "use_32_bit_worker" { 60 | description = "The use 32 bit worker setting for the app service." 61 | type = bool 62 | default = false 63 | } 64 | 65 | variable "health_check_path" { 66 | description = "The path to the health check endpoint" 67 | type = string 68 | default = "" 69 | } 70 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicepython/appservicepython_variables.tf: -------------------------------------------------------------------------------- 1 | variable "location" { 2 | description = "The supported Azure location where the resource deployed" 3 | type = string 4 | } 5 | 6 | variable "rg_name" { 7 | description = "The name of the resource group to deploy resources into" 8 | type = string 9 | } 10 | 11 | variable "appservice_plan_id" { 12 | description = "The id of the appservice plan to use." 13 | type = string 14 | } 15 | 16 | variable "service_name" { 17 | description = "A name to reflect the type of the app service e.g: web, api." 18 | type = string 19 | } 20 | 21 | variable "app_settings" { 22 | description = "A list of app settings pairs to be assigned to the app service" 23 | type = map(string) 24 | } 25 | 26 | variable "identity" { 27 | description = "A list of application identity" 28 | type = list(any) 29 | default = [] 30 | } 31 | 32 | variable "app_command_line" { 33 | description = "The cmd line to configure the app to run." 34 | type = string 35 | } 36 | 37 | variable "tags" { 38 | description = "A list of tags used for deployed services." 39 | type = map(string) 40 | } 41 | 42 | variable "resource_token" { 43 | description = "A suffix string to centrally mitigate resource name collisions." 44 | type = string 45 | } 46 | 47 | variable "python_version" { 48 | description = "the application stack python version to set for the app service." 49 | type = string 50 | default = "3.10" 51 | } 52 | 53 | variable "always_on" { 54 | description = "The always on setting for the app service." 55 | type = bool 56 | default = true 57 | } 58 | 59 | variable "use_32_bit_worker" { 60 | description = "The use 32 bit worker setting for the app service." 61 | type = bool 62 | default = false 63 | } 64 | 65 | variable "health_check_path" { 66 | description = "The path to the health check endpoint" 67 | type = string 68 | default = "" 69 | } 70 | -------------------------------------------------------------------------------- /infra/core/security/keyvault/keyvault.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | 14 | data "azurerm_client_config" "current" {} 15 | # ------------------------------------------------------------------------------------------------------ 16 | # DEPLOY AZURE KEYVAULT 17 | # ------------------------------------------------------------------------------------------------------ 18 | resource "azurecaf_name" "kv_name" { 19 | name = var.resource_token 20 | resource_type = "azurerm_key_vault" 21 | random_length = 0 22 | clean_input = true 23 | } 24 | 25 | resource "azurerm_key_vault" "kv" { 26 | name = azurecaf_name.kv_name.result 27 | location = var.location 28 | resource_group_name = var.rg_name 29 | tenant_id = data.azurerm_client_config.current.tenant_id 30 | purge_protection_enabled = false 31 | sku_name = "standard" 32 | 33 | tags = var.tags 34 | } 35 | 36 | resource "azurerm_key_vault_access_policy" "app" { 37 | count = length(var.access_policy_object_ids) 38 | key_vault_id = azurerm_key_vault.kv.id 39 | tenant_id = data.azurerm_client_config.current.tenant_id 40 | object_id = var.access_policy_object_ids[count.index] 41 | 42 | secret_permissions = [ 43 | "Get", 44 | "Set", 45 | "List", 46 | "Delete", 47 | ] 48 | } 49 | 50 | resource "azurerm_key_vault_access_policy" "user" { 51 | count = var.principal_id == "" ? 0 : 1 52 | key_vault_id = azurerm_key_vault.kv.id 53 | tenant_id = data.azurerm_client_config.current.tenant_id 54 | object_id = var.principal_id 55 | 56 | secret_permissions = [ 57 | "Get", 58 | "Set", 59 | "List", 60 | "Delete", 61 | "Purge" 62 | ] 63 | } 64 | 65 | resource "azurerm_key_vault_secret" "secrets" { 66 | count = length(var.secrets) 67 | name = var.secrets[count.index].name 68 | value = var.secrets[count.index].value 69 | key_vault_id = azurerm_key_vault.kv.id 70 | depends_on = [ 71 | azurerm_key_vault_access_policy.user, 72 | azurerm_key_vault_access_policy.app 73 | ] 74 | } -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicenode/appservicenode.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy app service web app 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "web_name" { 17 | name = "${var.service_name}-${var.resource_token}" 18 | resource_type = "azurerm_app_service" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_linux_web_app" "web" { 24 | name = azurecaf_name.web_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | service_plan_id = var.appservice_plan_id 28 | https_only = true 29 | tags = var.tags 30 | 31 | site_config { 32 | always_on = var.always_on 33 | use_32_bit_worker = var.use_32_bit_worker 34 | ftps_state = "FtpsOnly" 35 | app_command_line = var.app_command_line 36 | application_stack { 37 | node_version = var.node_version 38 | } 39 | health_check_path = var.health_check_path 40 | } 41 | 42 | app_settings = var.app_settings 43 | 44 | dynamic "identity" { 45 | for_each = { for k, v in var.identity : k => v if var.identity != [] } 46 | content { 47 | type = identity.value["type"] 48 | } 49 | } 50 | 51 | logs { 52 | application_logs { 53 | file_system_level = "Verbose" 54 | } 55 | detailed_error_messages = true 56 | failed_request_tracing = true 57 | http_logs { 58 | file_system { 59 | retention_in_days = 1 60 | retention_in_mb = 35 61 | } 62 | } 63 | } 64 | } 65 | 66 | # This is a temporary solution until the azurerm provider supports the basicPublishingCredentialsPolicies resource type 67 | resource "null_resource" "webapp_basic_auth_disable" { 68 | triggers = { 69 | account = azurerm_linux_web_app.web.name 70 | } 71 | 72 | provisioner "local-exec" { 73 | command = "az resource update --resource-group ${var.rg_name} --name ftp --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${azurerm_linux_web_app.web.name} --set properties.allow=false && az resource update --resource-group ${var.rg_name} --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${azurerm_linux_web_app.web.name} --set properties.allow=false" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /infra/core/host/appservice/appservicepython/appservicepython.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy app service web app 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "web_name" { 17 | name = "${var.service_name}-${var.resource_token}" 18 | resource_type = "azurerm_app_service" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_linux_web_app" "web" { 24 | name = azurecaf_name.web_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | service_plan_id = var.appservice_plan_id 28 | https_only = true 29 | tags = var.tags 30 | 31 | site_config { 32 | always_on = var.always_on 33 | use_32_bit_worker = var.use_32_bit_worker 34 | ftps_state = "FtpsOnly" 35 | app_command_line = var.app_command_line 36 | application_stack { 37 | python_version = var.python_version 38 | } 39 | health_check_path = var.health_check_path 40 | } 41 | 42 | app_settings = var.app_settings 43 | 44 | dynamic "identity" { 45 | for_each = { for k, v in var.identity : k => v if var.identity != [] } 46 | content { 47 | type = identity.value["type"] 48 | } 49 | } 50 | 51 | logs { 52 | application_logs { 53 | file_system_level = "Verbose" 54 | } 55 | detailed_error_messages = true 56 | failed_request_tracing = true 57 | http_logs { 58 | file_system { 59 | retention_in_days = 1 60 | retention_in_mb = 35 61 | } 62 | } 63 | } 64 | } 65 | 66 | # This is a temporary solution until the azurerm provider supports the basicPublishingCredentialsPolicies resource type 67 | resource "null_resource" "webapp_basic_auth_disable" { 68 | triggers = { 69 | account = azurerm_linux_web_app.web.name 70 | } 71 | 72 | provisioner "local-exec" { 73 | command = "az resource update --resource-group ${var.rg_name} --name ftp --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${azurerm_linux_web_app.web.name} --set properties.allow=false && az resource update --resource-group ${var.rg_name} --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/${azurerm_linux_web_app.web.name} --set properties.allow=false" 74 | } 75 | } 76 | -------------------------------------------------------------------------------- /infra/core/gateway/apim-api/apim-api.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | 14 | data "azurerm_api_management" "apim" { 15 | name = var.name 16 | resource_group_name = var.rg_name 17 | } 18 | 19 | # ------------------------------------------------------------------------------------------------------ 20 | # Deploy apim-api service 21 | # ------------------------------------------------------------------------------------------------------ 22 | resource "azurerm_api_management_api" "api" { 23 | name = var.api_name 24 | resource_group_name = var.rg_name 25 | api_management_name = data.azurerm_api_management.apim.name 26 | revision = "1" 27 | display_name = var.api_display_name 28 | path = var.api_path 29 | protocols = ["https"] 30 | service_url = var.api_backend_url 31 | subscription_required = false 32 | 33 | import { 34 | content_format = "openapi" 35 | content_value = file("${path.module}/../../../src/api/openapi.yaml") 36 | } 37 | } 38 | 39 | resource "azurerm_api_management_api_policy" "policies" { 40 | api_name = azurerm_api_management_api.api.name 41 | api_management_name = azurerm_api_management_api.api.api_management_name 42 | resource_group_name = var.rg_name 43 | 44 | xml_content = replace(file("${path.module}/apim-api-policy.xml"), "{origin}", var.web_front_end_url) 45 | } 46 | 47 | resource "azurerm_api_management_api_diagnostic" "diagnostics" { 48 | identifier = "applicationinsights" 49 | resource_group_name = var.rg_name 50 | api_management_name = azurerm_api_management_api.api.api_management_name 51 | api_name = azurerm_api_management_api.api.name 52 | api_management_logger_id = var.api_management_logger_id 53 | 54 | sampling_percentage = 100.0 55 | always_log_errors = true 56 | log_client_ip = true 57 | verbosity = "verbose" 58 | http_correlation_protocol = "W3C" 59 | 60 | frontend_request { 61 | body_bytes = 1024 62 | headers_to_log = [ 63 | "content-type", 64 | "accept", 65 | "origin", 66 | ] 67 | } 68 | 69 | frontend_response { 70 | body_bytes = 1024 71 | headers_to_log = [ 72 | "content-type", 73 | "content-length", 74 | "origin", 75 | ] 76 | } 77 | 78 | backend_request { 79 | body_bytes = 1024 80 | headers_to_log = [ 81 | "content-type", 82 | "accept", 83 | "origin", 84 | ] 85 | } 86 | 87 | backend_response { 88 | body_bytes = 1024 89 | headers_to_log = [ 90 | "content-type", 91 | "content-length", 92 | "origin", 93 | ] 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /infra/core/database/cosmos/cosmos.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # Deploy cosmos db account 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "db_acc_name" { 17 | name = var.resource_token 18 | resource_type = "azurerm_cosmosdb_account" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_cosmosdb_account" "db" { 24 | name = azurecaf_name.db_acc_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | offer_type = "Standard" 28 | kind = "MongoDB" 29 | enable_automatic_failover = false 30 | enable_multiple_write_locations = false 31 | mongo_server_version = "4.0" 32 | tags = var.tags 33 | 34 | capabilities { 35 | name = "EnableServerless" 36 | } 37 | 38 | lifecycle { 39 | ignore_changes = [capabilities] 40 | } 41 | consistency_policy { 42 | consistency_level = "Session" 43 | } 44 | 45 | geo_location { 46 | location = var.location 47 | failover_priority = 0 48 | zone_redundant = false 49 | } 50 | } 51 | 52 | # ------------------------------------------------------------------------------------------------------ 53 | # Deploy cosmos mongo db and collections 54 | # ------------------------------------------------------------------------------------------------------ 55 | resource "azurerm_cosmosdb_mongo_database" "mongodb" { 56 | name = "Todo" 57 | resource_group_name = azurerm_cosmosdb_account.db.resource_group_name 58 | account_name = azurerm_cosmosdb_account.db.name 59 | } 60 | 61 | resource "azurerm_cosmosdb_mongo_collection" "list" { 62 | name = "TodoList" 63 | resource_group_name = azurerm_cosmosdb_account.db.resource_group_name 64 | account_name = azurerm_cosmosdb_account.db.name 65 | database_name = azurerm_cosmosdb_mongo_database.mongodb.name 66 | shard_key = "_id" 67 | 68 | 69 | index { 70 | keys = ["_id"] 71 | } 72 | } 73 | 74 | resource "azurerm_cosmosdb_mongo_collection" "item" { 75 | name = "TodoItem" 76 | resource_group_name = azurerm_cosmosdb_account.db.resource_group_name 77 | account_name = azurerm_cosmosdb_account.db.name 78 | database_name = azurerm_cosmosdb_mongo_database.mongodb.name 79 | shard_key = "_id" 80 | 81 | index { 82 | keys = ["_id"] 83 | } 84 | } -------------------------------------------------------------------------------- /infra/core/database/postgresql/postgresql.tf: -------------------------------------------------------------------------------- 1 | locals { 2 | psqlUserName = "psqluser" 3 | } 4 | 5 | terraform { 6 | required_providers { 7 | azurerm = { 8 | version = "~>3.97.1" 9 | source = "hashicorp/azurerm" 10 | } 11 | azurecaf = { 12 | source = "aztfmod/azurecaf" 13 | version = "~>1.2.24" 14 | } 15 | } 16 | } 17 | # ------------------------------------------------------------------------------------------------------ 18 | # Deploy PostgreSQL Server 19 | # ------------------------------------------------------------------------------------------------------ 20 | resource "azurecaf_name" "psql_name" { 21 | name = var.resource_token 22 | resource_type = "azurerm_postgresql_flexible_server" 23 | random_length = 0 24 | clean_input = true 25 | } 26 | 27 | resource "random_password" "password" { 28 | count = 2 29 | length = 32 30 | special = true 31 | override_special = "_%@" 32 | } 33 | 34 | resource "azurerm_postgresql_flexible_server" "psql_server" { 35 | name = azurecaf_name.psql_name.result 36 | location = var.location 37 | resource_group_name = var.rg_name 38 | tags = var.tags 39 | version = "12" 40 | administrator_login = var.administrator_login 41 | administrator_password = random_password.password[0].result 42 | zone = "1" 43 | 44 | storage_mb = 32768 45 | 46 | sku_name = "GP_Standard_D4s_v3" 47 | } 48 | 49 | 50 | resource "azurerm_postgresql_flexible_server_firewall_rule" "firewall_rule" { 51 | name = "AllowAllFireWallRule" 52 | server_id = azurerm_postgresql_flexible_server.psql_server.id 53 | start_ip_address = "0.0.0.0" 54 | end_ip_address = "255.255.255.255" 55 | } 56 | 57 | resource "azurerm_postgresql_flexible_server_database" "database" { 58 | name = var.database_name 59 | server_id = azurerm_postgresql_flexible_server.psql_server.id 60 | collation = "en_US.utf8" 61 | charset = "utf8" 62 | } 63 | 64 | resource "azurerm_resource_deployment_script_azure_cli" "psql-script" { 65 | name = "psql-script-${var.resource_token}" 66 | resource_group_name = var.rg_name 67 | location = var.location 68 | version = "2.40.0" 69 | retention_interval = "PT1H" 70 | cleanup_preference = "OnSuccess" 71 | timeout = "PT5M" 72 | 73 | environment_variable { 74 | name = "PSQLADMINNAME" 75 | value = azurerm_postgresql_flexible_server.psql_server.administrator_login 76 | } 77 | environment_variable { 78 | name = "PSQLADMINPASSWORD" 79 | value = random_password.password[0].result 80 | } 81 | environment_variable { 82 | name = "PSQLUSERNAME" 83 | value = local.psqlUserName 84 | } 85 | environment_variable { 86 | name = "PSQLUSERPASSWORD" 87 | value = random_password.password[1].result 88 | } 89 | environment_variable { 90 | name = "DBNAME" 91 | value = var.database_name 92 | } 93 | environment_variable { 94 | name = "DBSERVER" 95 | value = azurerm_postgresql_flexible_server.psql_server.fqdn 96 | } 97 | 98 | script_content = <<-EOT 99 | 100 | apk add postgresql-client 101 | 102 | cat << EOF > create_user.sql 103 | CREATE ROLE "$PSQLUSERNAME" WITH LOGIN PASSWORD '$PSQLUSERPASSWORD'; 104 | GRANT ALL PRIVILEGES ON DATABASE $DBNAME TO "$PSQLUSERNAME"; 105 | EOF 106 | 107 | psql "host=$DBSERVER user=$PSQLADMINNAME dbname=$DBNAME port=5432 password=$PSQLADMINPASSWORD sslmode=require" < create_user.sql 108 | EOT 109 | 110 | depends_on = [ azurerm_postgresql_flexible_server_database.database ] 111 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Developer CLI (azd) Terraform Starter 2 | 3 | A starter blueprint for getting your application up on Azure using [Azure Developer CLI](https://learn.microsoft.com/en-us/azure/developer/azure-developer-cli/overview) (azd). Add your application code, write Infrastructure as Code assets in Terraform to get your application up and running quickly. 4 | 5 | The following assets have been provided: 6 | 7 | - Infrastructure-as-code (IaC) Terraform modules under the `infra` directory that demonstrate how to provision resources and setup resource tagging for azd. 8 | - A [dev container](https://containers.dev) configuration file under the `.devcontainer` directory that installs infrastructure tooling by default. This can be readily used to create cloud-hosted developer environments such as [GitHub Codespaces](https://aka.ms/codespaces). 9 | - Continuous deployment workflows for CI providers such as GitHub Actions under the `.github` directory, and Azure Pipelines under the `.azdo` directory that work for most use-cases. 10 | 11 | ## Next Steps 12 | 13 | ### Step 1: Add application code 14 | 15 | 1. Initialize the service source code projects anywhere under the current directory. Ensure that all source code projects can be built successfully. 16 | - > Note: For `function` services, it is recommended to initialize the project using the provided [quickstart tools](https://learn.microsoft.com/en-us/azure/azure-functions/functions-get-started). 17 | 2. Once all service source code projects are building correctly, update `azure.yaml` to reference the source code projects. 18 | 3. Run `azd package` to validate that all service source code projects can be built and packaged locally. 19 | 20 | ### Step 2: Provision Azure resources 21 | 22 | Update or add Terraform modules to provision the relevant Azure resources. This can be done incrementally, as the list of [Azure resources](https://learn.microsoft.com/en-us/azure/?product=popular) are explored and added. 23 | 24 | - All Azure resources available in Terraform format can be found [here](https://learn.microsoft.com/en-us/azure/templates/). 25 | 26 | Run `azd provision` whenever you want to ensure that changes made are applied correctly and work as expected. 27 | 28 | ### Step 3: Tie in application and infrastructure 29 | 30 | Certain changes to Terraform modules or deployment manifests are required to tie in application and infrastructure together. For example: 31 | 32 | 1. Set up [application settings](#application-settings) for the code running in Azure to connect to other Azure resources. 33 | 1. If you are accessing sensitive resources in Azure, set up [managed identities](#managed-identities) to allow the code running in Azure to securely access the resources. 34 | 1. If you have secrets, it is recommended to store secrets in [Azure Key Vault](#azure-key-vault) that then can be retrieved by your application, with the use of managed identities. 35 | 1. Configure [host configuration](#host-configuration) on your hosting platform to match your application's needs. This may include networking options, security options, or more advanced configuration that helps you take full advantage of Azure capabilities. 36 | 37 | For more details, see [additional details](#additional-details) below. 38 | 39 | When changes are made, use azd to apply your changes in Azure and validate that they are working as expected: 40 | 41 | - Run `azd up` to validate both infrastructure and application code changes. 42 | - Run `azd deploy` to validate application code changes. 43 | 44 | ### Step 4: Up to Azure 45 | 46 | Finally, run `azd up` to run the end-to-end infrastructure provisioning (`azd provision`) and deployment (`azd deploy`) flow. Visit the service endpoints listed to see your application up-and-running! 47 | 48 | ## Additional Details 49 | 50 | The following section examines different concepts that help tie in application and infrastructure. 51 | 52 | ### Application settings 53 | 54 | It is recommended to have application settings managed in Azure, separating configuration from code. Typically, the service host allows for application settings to be defined. 55 | 56 | - For `appservice` and `function`, application settings should be defined on the Terraform resource for the targeted host. Reference template example [here](https://github.com/Azure-Samples/todo-nodejs-mongo-terraform/tree/main/infra). 57 | - For `aks`, application settings are applied using deployment manifests under the `/manifests` folder. Reference template example [here](https://github.com/Azure-Samples/todo-nodejs-mongo-aks/tree/main/src/api/manifests). 58 | 59 | ### Managed identities 60 | 61 | [Managed identities](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview) allows you to secure communication between services. This is done without having the need for you to manage any credentials. 62 | 63 | ### Azure Key Vault 64 | 65 | [Azure Key Vault](https://learn.microsoft.com/en-us/azure/key-vault/general/overview) allows you to store secrets securely. Your application can access these secrets securely through the use of managed identities. 66 | 67 | ### Host configuration 68 | 69 | For `appservice`, the following host configuration options are often modified: 70 | 71 | - Language runtime version 72 | - Exposed port from the running container (if running a web service) 73 | - Allowed origins for CORS (Cross-Origin Resource Sharing) protection (if running a web service backend with a frontend) 74 | - The run command that starts up your service 75 | -------------------------------------------------------------------------------- /infra/core/monitor/applicationinsights/applicationinsights.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | azurerm = { 4 | version = "~>3.97.1" 5 | source = "hashicorp/azurerm" 6 | } 7 | azurecaf = { 8 | source = "aztfmod/azurecaf" 9 | version = "~>1.2.24" 10 | } 11 | } 12 | } 13 | # ------------------------------------------------------------------------------------------------------ 14 | # DEPLOY APPLICATION INSIGHTS 15 | # ------------------------------------------------------------------------------------------------------ 16 | resource "azurecaf_name" "applicationinsights_name" { 17 | name = var.resource_token 18 | resource_type = "azurerm_application_insights" 19 | random_length = 0 20 | clean_input = true 21 | } 22 | 23 | resource "azurerm_application_insights" "applicationinsights" { 24 | name = azurecaf_name.applicationinsights_name.result 25 | location = var.location 26 | resource_group_name = var.rg_name 27 | application_type = "web" 28 | workspace_id = var.workspace_id 29 | tags = var.tags 30 | } 31 | 32 | data "azurerm_subscription" "current" {} 33 | 34 | resource "azurerm_portal_dashboard" "board" { 35 | name = "dash-${var.resource_token}" 36 | resource_group_name = var.rg_name 37 | location = var.location 38 | tags = var.tags 39 | dashboard_properties = <