From c20442b7bb18ce05826c249a747d63d317d0c865 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 8 May 2026 09:43:32 +0200 Subject: [PATCH 1/7] Add Web App with Custom Docker Image sample --- .gitignore | 11 +- README.md | 2 +- .../aci-blob-storage/python/bicep/README.md | 4 +- .../aci-blob-storage/python/scripts/README.md | 4 +- .../python/terraform/README.md | 4 +- .../python/README.md | 2 +- .../python/bicep/README.md | 4 +- .../python/scripts/README.md | 4 +- .../python/terraform/README.md | 4 +- .../function-app-service-bus/dotnet/README.md | 2 +- .../dotnet/bicep/README.md | 4 +- .../dotnet/scripts/README.md | 4 +- .../dotnet/terraform/README.md | 4 +- .../dotnet/terraform/variables.tf | 6 - .../dotnet/README.md | 4 +- .../dotnet/bicep/README.md | 4 +- .../dotnet/scripts/README.md | 4 +- .../dotnet/terraform/README.md | 4 +- samples/servicebus/java/README.md | 2 +- samples/servicebus/java/bicep/README.md | 4 +- samples/servicebus/java/scripts/README.md | 4 +- samples/servicebus/java/terraform/README.md | 4 +- .../python/README.md | 2 +- .../python/bicep/README.md | 4 +- .../python/bicep/main.bicep | 3 +- .../python/bicep/main.bicepparam | 2 +- .../python/bicep/modules/web-app.bicep | 2 +- .../python/scripts/README.md | 4 +- .../python/scripts/deploy.sh | 149 ++- .../python/scripts/validate.sh | 12 +- .../python/terraform/README.md | 4 +- .../python/terraform/main.tf | 3 +- .../modules/app_service_plan/main.tf | 4 - .../python/terraform/variables.tf | 2 +- .../python/README.md | 2 +- .../python/scripts/README.md | 4 +- samples/web-app-custom-image/python/README.md | 90 +- .../python/bicep/README.md | 286 +++++ .../python/bicep/acr.bicep | 81 ++ .../python/bicep/acr.bicepparam | 8 + .../python/bicep/deploy.sh | 254 +++++ .../python/bicep/main.bicep | 305 ++++++ .../python/bicep/main.bicepparam | 10 + .../bicep/modules/app-service-plan.bicep | 154 +++ .../bicep/modules/container-registry.bicep | 135 +++ .../python/bicep/modules/log-analytics.bicep | 45 + .../bicep/modules/managed-identity.bicep | 54 + .../bicep/modules/private-dns-zone.bicep | 41 + .../bicep/modules/private-endpoint.bicep | 72 ++ .../bicep/modules/virtual-network.bicep | 239 +++++ .../python/bicep/modules/web-app.bicep | 210 ++++ .../python/images/architecture.png | Bin 0 -> 121286 bytes .../python/scripts/README.md | 250 ++++- .../python/scripts/call-web-app.sh | 4 +- .../python/scripts/deploy.sh | 998 +++++++++++++++++- .../python/scripts/validate.sh | 97 +- .../web-app-custom-image/python/src/app.py | 4 +- .../python/terraform/README.md | 280 +++++ .../python/terraform/deploy.sh | 53 + .../python/terraform/main.tf | 225 ++++ .../modules/app_service_plan/main.tf | 25 + .../modules/app_service_plan/outputs.tf | 19 + .../modules/app_service_plan/variables.tf | 42 + .../modules/container_registry/main.tf | 62 ++ .../modules/container_registry/output.tf | 34 + .../modules/container_registry/variables.tf | 60 ++ .../terraform/modules/log_analytics/main.tf | 14 + .../terraform/modules/log_analytics/output.tf | 30 + .../modules/log_analytics/variables.tf | 37 + .../modules/managed_identity/main.tf | 20 + .../modules/managed_identity/output.tf | 25 + .../modules/managed_identity/variables.tf | 26 + .../terraform/modules/nat_gateway/main.tf | 42 + .../terraform/modules/nat_gateway/output.tf | 9 + .../modules/nat_gateway/variables.tf | 55 + .../modules/network_security_group/main.tf | 53 + .../modules/network_security_group/outputs.tf | 9 + .../network_security_group/variables.tf | 51 + .../modules/private_dns_zone/main.tf | 26 + .../modules/private_dns_zone/outputs.tf | 9 + .../modules/private_dns_zone/variables.tf | 20 + .../modules/private_endpoint/main.tf | 26 + .../modules/private_endpoint/outputs.tf | 19 + .../modules/private_endpoint/variables.tf | 61 ++ .../terraform/modules/virtual_network/main.tf | 55 + .../modules/virtual_network/outputs.tf | 19 + .../modules/virtual_network/variables.tf | 40 + .../python/terraform/modules/web_app/main.tf | 85 ++ .../terraform/modules/web_app/outputs.tf | 24 + .../terraform/modules/web_app/variables.tf | 126 +++ .../python/terraform/outputs.tf | 23 + .../python/terraform/providers.tf | 28 + .../python/terraform/push_image.sh | 44 + .../python/terraform/terraform.tfvars | 3 + .../python/terraform/variables.tf | 280 +++++ .../python/visio/web-app-custom-image.vsdx | Bin 0 -> 259502 bytes .../web-app-managed-identity/python/README.md | 2 +- .../python/bicep/README.md | 4 +- .../python/scripts/README.md | 4 +- .../python/terraform/README.md | 4 +- samples/web-app-sql-database/python/README.md | 4 +- .../python/bicep/README.md | 4 +- .../python/scripts/README.md | 4 +- .../python/terraform/README.md | 4 +- 104 files changed, 5461 insertions(+), 251 deletions(-) create mode 100644 samples/web-app-custom-image/python/bicep/README.md create mode 100644 samples/web-app-custom-image/python/bicep/acr.bicep create mode 100644 samples/web-app-custom-image/python/bicep/acr.bicepparam create mode 100755 samples/web-app-custom-image/python/bicep/deploy.sh create mode 100644 samples/web-app-custom-image/python/bicep/main.bicep create mode 100644 samples/web-app-custom-image/python/bicep/main.bicepparam create mode 100644 samples/web-app-custom-image/python/bicep/modules/app-service-plan.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/container-registry.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/log-analytics.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/managed-identity.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/private-dns-zone.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/private-endpoint.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/virtual-network.bicep create mode 100644 samples/web-app-custom-image/python/bicep/modules/web-app.bicep create mode 100644 samples/web-app-custom-image/python/images/architecture.png create mode 100644 samples/web-app-custom-image/python/terraform/README.md create mode 100755 samples/web-app-custom-image/python/terraform/deploy.sh create mode 100644 samples/web-app-custom-image/python/terraform/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/app_service_plan/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/app_service_plan/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/app_service_plan/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/container_registry/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/container_registry/output.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/log_analytics/output.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/log_analytics/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/managed_identity/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/managed_identity/output.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/managed_identity/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/nat_gateway/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/nat_gateway/output.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/network_security_group/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/network_security_group/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/network_security_group/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_dns_zone/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_dns_zone/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_dns_zone/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_endpoint/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/virtual_network/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/virtual_network/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/virtual_network/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/web_app/main.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/web_app/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/modules/web_app/variables.tf create mode 100644 samples/web-app-custom-image/python/terraform/outputs.tf create mode 100644 samples/web-app-custom-image/python/terraform/providers.tf create mode 100755 samples/web-app-custom-image/python/terraform/push_image.sh create mode 100644 samples/web-app-custom-image/python/terraform/terraform.tfvars create mode 100644 samples/web-app-custom-image/python/terraform/variables.tf create mode 100644 samples/web-app-custom-image/python/visio/web-app-custom-image.vsdx diff --git a/.gitignore b/.gitignore index c7d539a..6f73d44 100644 --- a/.gitignore +++ b/.gitignore @@ -217,4 +217,13 @@ cython_debug/ # before adapting. # Usually, these files will be generated by your IDE, so it is # better to have them ignored. -.idea/ \ No newline at end of file +.idea/ +## Terraform +.terraform/ +*.tfstate +*.tfstate.backup +tfplan +override.tf +override.tf.json +*_override.tf +*_override.tf.json diff --git a/README.md b/README.md index e7cf2c1..a25929e 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ Follow the comprehensive setup guide in [LocalStack for Azure Quick Start](./doc ## Documentation -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) - [Azure CLI with LocalStack](https://azure.localstack.cloud/user-guides/sdks/az/) - [Supported Azure Services](https://azure.localstack.cloud/references/coverage/) diff --git a/samples/aci-blob-storage/python/bicep/README.md b/samples/aci-blob-storage/python/bicep/README.md index 680ab0b..7b8b9e8 100644 --- a/samples/aci-blob-storage/python/bicep/README.md +++ b/samples/aci-blob-storage/python/bicep/README.md @@ -4,7 +4,7 @@ This directory contains the Bicep template and a deployment script for provision ## Prerequisites -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support @@ -59,4 +59,4 @@ bash scripts/cleanup.sh - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/aci-blob-storage/python/scripts/README.md b/samples/aci-blob-storage/python/scripts/README.md index 42039bd..1cfdbd7 100644 --- a/samples/aci-blob-storage/python/scripts/README.md +++ b/samples/aci-blob-storage/python/scripts/README.md @@ -4,7 +4,7 @@ This directory includes Bash scripts for deploying and testing the ACI Vacation ## Prerequisites -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper @@ -48,4 +48,4 @@ bash scripts/cleanup.sh ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/aci-blob-storage/python/terraform/README.md b/samples/aci-blob-storage/python/terraform/README.md index 69da3ca..b487e9d 100644 --- a/samples/aci-blob-storage/python/terraform/README.md +++ b/samples/aci-blob-storage/python/terraform/README.md @@ -4,7 +4,7 @@ This directory contains Terraform modules and a deployment script for provisioni ## Prerequisites -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface @@ -66,4 +66,4 @@ rm -rf .terraform terraform.tfstate terraform.tfstate.backup .terraform.lock.hcl ## Related Documentation - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/function-app-managed-identity/python/README.md b/samples/function-app-managed-identity/python/README.md index a81d21f..4c84ad9 100644 --- a/samples/function-app-managed-identity/python/README.md +++ b/samples/function-app-managed-identity/python/README.md @@ -239,4 +239,4 @@ You can use [Azure Storage Explorer](https://learn.microsoft.com/en-us/azure/sto - [What is Azure Blob storage?](https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blobs-overview) - [What is managed identities for Azure resources?](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/overview) - [How managed identities for Azure resources work with Azure virtual machines](https://learn.microsoft.com/en-us/entra/identity/managed-identities-azure-resources/how-managed-identities-work-vm) -- [LocalStack for Azure](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/function-app-managed-identity/python/bicep/README.md b/samples/function-app-managed-identity/python/bicep/README.md index f15afc7..ec822ba 100644 --- a/samples/function-app-managed-identity/python/bicep/README.md +++ b/samples/function-app-managed-identity/python/bicep/README.md @@ -6,7 +6,7 @@ This directory contains the Bicep template and a deployment script for provision Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support and IntelliSense - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -167,4 +167,4 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/function-app-managed-identity/python/scripts/README.md b/samples/function-app-managed-identity/python/scripts/README.md index 132f58e..30aba0d 100644 --- a/samples/function-app-managed-identity/python/scripts/README.md +++ b/samples/function-app-managed-identity/python/scripts/README.md @@ -6,7 +6,7 @@ This directory includes Bash scripts designed for deploying and testing the samp Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface @@ -143,4 +143,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/function-app-managed-identity/python/terraform/README.md b/samples/function-app-managed-identity/python/terraform/README.md index 8bd1e34..a89f929 100644 --- a/samples/function-app-managed-identity/python/terraform/README.md +++ b/samples/function-app-managed-identity/python/terraform/README.md @@ -6,7 +6,7 @@ This directory contains Terraform modules and a deployment script for provisioni Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool for provisioning Azure resources - [Python](https://www.python.org/downloads/): Python runtime (version 3.13 or above) @@ -171,4 +171,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/function-app-service-bus/dotnet/README.md b/samples/function-app-service-bus/dotnet/README.md index a82fd6a..eb17668 100644 --- a/samples/function-app-service-bus/dotnet/README.md +++ b/samples/function-app-service-bus/dotnet/README.md @@ -219,4 +219,4 @@ You can also inspect the function app's runtime behavior by viewing the logs of - [Azure Functions Apps Documentation](https://learn.microsoft.com/en-us/azure/app-service/) - [Azure Service Bus](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview) -- [LocalStack for Azure](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/function-app-service-bus/dotnet/bicep/README.md b/samples/function-app-service-bus/dotnet/bicep/README.md index bca1b9d..cb2df22 100644 --- a/samples/function-app-service-bus/dotnet/bicep/README.md +++ b/samples/function-app-service-bus/dotnet/bicep/README.md @@ -7,7 +7,7 @@ This directory contains the Bicep template and a deployment script for provision Before deploying this solution, ensure you have the following tools installed: - [Azure Subscription](https://azure.microsoft.com/free/) -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper @@ -310,4 +310,4 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/function-app-service-bus/dotnet/scripts/README.md b/samples/function-app-service-bus/dotnet/scripts/README.md index d935c05..0bcb818 100644 --- a/samples/function-app-service-bus/dotnet/scripts/README.md +++ b/samples/function-app-service-bus/dotnet/scripts/README.md @@ -7,7 +7,7 @@ This directory includes Bash scripts designed for deploying and testing the samp Before deploying this solution, ensure you have the following tools installed: - [Azure Subscription](https://azure.microsoft.com/free/) -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper @@ -278,4 +278,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/function-app-service-bus/dotnet/terraform/README.md b/samples/function-app-service-bus/dotnet/terraform/README.md index 0feaede..f278281 100644 --- a/samples/function-app-service-bus/dotnet/terraform/README.md +++ b/samples/function-app-service-bus/dotnet/terraform/README.md @@ -7,7 +7,7 @@ This directory contains Terraform modules and a deployment script for provisioni Before deploying this solution, ensure you have the following tools installed: - [Azure Subscription](https://azure.microsoft.com/free/) -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper @@ -314,4 +314,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/function-app-service-bus/dotnet/terraform/variables.tf b/samples/function-app-service-bus/dotnet/terraform/variables.tf index 3edba4e..300259f 100644 --- a/samples/function-app-service-bus/dotnet/terraform/variables.tf +++ b/samples/function-app-service-bus/dotnet/terraform/variables.tf @@ -321,12 +321,6 @@ variable "nat_gateway_zones" { default = ["1"] } -variable "website_port" { - description = "(Optional) Specifies the port on which the Web App will listen. Defaults to 8000." - type = number - default = 8000 -} - variable "queue_names" { description = "(Optional) Specifies the names of the queues to be created within the Service Bus Namespace." type = set(string) diff --git a/samples/function-app-storage-http/dotnet/README.md b/samples/function-app-storage-http/dotnet/README.md index 0c5132c..3cd8424 100644 --- a/samples/function-app-storage-http/dotnet/README.md +++ b/samples/function-app-storage-http/dotnet/README.md @@ -1,6 +1,6 @@ # Azure Functions Sample with LocalStack for Azure -This sample demonstrates a comprehensive gaming scoreboard system built with [Azure Functions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview) running against [LocalStack for Azure](https://azure.localstack.cloud/). The application showcases how Azure Functions can seamlessly interact with Azure Storage services (Queues, Blobs, and Tables) when both the Azure Function App and storage services are running in emulated fashion locally on your machine using LocalStack for Azure. +This sample demonstrates a comprehensive gaming scoreboard system built with [Azure Functions](https://learn.microsoft.com/en-us/azure/azure-functions/functions-overview) running against [LocalStack for Azure](https://docs.localstack.cloud/azure/). The application showcases how Azure Functions can seamlessly interact with Azure Storage services (Queues, Blobs, and Tables) when both the Azure Function App and storage services are running in emulated fashion locally on your machine using LocalStack for Azure. ## Overview @@ -121,7 +121,7 @@ The sample uses the following configurable settings in `local.settings.json`: ## Prerequisites -- [LocalStack for Azure](https://azure.localstack.cloud/) for Azure services emulation. +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) for Azure services emulation. - [Visual Studio Code](https://code.visualstudio.com/) installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms). - [Azure Functions Core Tools](https://learn.microsoft.com/en-us/azure/azure-functions/functions-run-local) let you develop and test your functions on your local computer. - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep. diff --git a/samples/function-app-storage-http/dotnet/bicep/README.md b/samples/function-app-storage-http/dotnet/bicep/README.md index 8241b6d..9594052 100644 --- a/samples/function-app-storage-http/dotnet/bicep/README.md +++ b/samples/function-app-storage-http/dotnet/bicep/README.md @@ -6,7 +6,7 @@ This directory contains the `main.bicep` Bicep module and `deploy.sh` deployment Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support and IntelliSense - [.NET SDK](https://dotnet.microsoft.com/en-us/download): Required for building and publishing the C# Azure Functions application @@ -155,5 +155,5 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) - [Azure Functions Documentation](https://docs.microsoft.com/en-us/azure/azure-functions/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) - [Azure Functions Methods Documentation](../src/sample/Methods.md) - Detailed documentation of all implemented functions \ No newline at end of file diff --git a/samples/function-app-storage-http/dotnet/scripts/README.md b/samples/function-app-storage-http/dotnet/scripts/README.md index f9b53d1..79312a3 100644 --- a/samples/function-app-storage-http/dotnet/scripts/README.md +++ b/samples/function-app-storage-http/dotnet/scripts/README.md @@ -6,7 +6,7 @@ This folder contains Bash scripts for deploying an Azure Functions application w Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [.NET SDK](https://dotnet.microsoft.com/en-us/download): Required for building and publishing the C# Azure Functions application - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -199,4 +199,4 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) - [Azure Functions CLI Documentation](https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local) - [Azure Functions Methods Documentation](../src/sample/Methods.md) - Detailed documentation of all implemented functions -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/function-app-storage-http/dotnet/terraform/README.md b/samples/function-app-storage-http/dotnet/terraform/README.md index a060dbe..dbcbcb7 100644 --- a/samples/function-app-storage-http/dotnet/terraform/README.md +++ b/samples/function-app-storage-http/dotnet/terraform/README.md @@ -6,7 +6,7 @@ This directory contains Terraform modules and `deploy.sh` deployment script for Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool for provisioning Azure resources - [.NET SDK](https://dotnet.microsoft.com/en-us/download): Required for building and publishing the C# Azure Functions application @@ -179,5 +179,5 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure Functions Documentation](https://docs.microsoft.com/en-us/azure/azure-functions/) - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) - [Azure Functions Methods Documentation](../src/sample/Methods.md) - Detailed documentation of all implemented functions \ No newline at end of file diff --git a/samples/servicebus/java/README.md b/samples/servicebus/java/README.md index ccf882c..36476ee 100644 --- a/samples/servicebus/java/README.md +++ b/samples/servicebus/java/README.md @@ -82,6 +82,6 @@ The application then: - [Spring Cloud Azure Service Bus](https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/configure-spring-cloud-stream-binder-java-app-with-service-bus) - [Azure Service Bus Queues](https://learn.microsoft.com/en-us/azure/service-bus-messaging/service-bus-queues-topics-subscriptions) - [Spring Boot Starter for Azure Service Bus](https://learn.microsoft.com/en-us/azure/developer/java/spring-framework/spring-cloud-azure) -- [LocalStack for Azure](https://azure.localstack.cloud/) +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) diff --git a/samples/servicebus/java/bicep/README.md b/samples/servicebus/java/bicep/README.md index f2ac6c3..3ed3c40 100644 --- a/samples/servicebus/java/bicep/README.md +++ b/samples/servicebus/java/bicep/README.md @@ -6,7 +6,7 @@ This directory contains a Bicep template and a deployment script for provisionin Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support and IntelliSense - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -179,4 +179,4 @@ This will remove all Azure resources created by the Bicep deployment script. - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/servicebus/java/scripts/README.md b/samples/servicebus/java/scripts/README.md index 217c65e..b16ca3f 100644 --- a/samples/servicebus/java/scripts/README.md +++ b/samples/servicebus/java/scripts/README.md @@ -6,7 +6,7 @@ This directory contains Azure CLI scripts and a deployment script for provisioni Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface @@ -161,4 +161,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/servicebus/java/terraform/README.md b/samples/servicebus/java/terraform/README.md index eae6660..e94ce25 100644 --- a/samples/servicebus/java/terraform/README.md +++ b/samples/servicebus/java/terraform/README.md @@ -6,7 +6,7 @@ This directory contains Terraform modules and a deployment script for provisioni Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool for provisioning Azure resources - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -184,4 +184,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/README.md b/samples/web-app-cosmosdb-mongodb-api/python/README.md index b936381..59b4b52 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/README.md +++ b/samples/web-app-cosmosdb-mongodb-api/python/README.md @@ -150,4 +150,4 @@ sampledb> db.activities.find().pretty() - [Quickstart: Python Flask on Azure](https://learn.microsoft.com/en-us/azure/app-service/quickstart-python?tabs=flask%2Cbrowser) - [Quickstart: CosmosDB for MongoDB](https://learn.microsoft.com/en-us/azure/cosmos-db/mongodb/quickstart?tabs=azure-portal) - [Azure Identity Client Library for Python](https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python) -- [LocalStack for Azure](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/bicep/README.md b/samples/web-app-cosmosdb-mongodb-api/python/bicep/README.md index 1d05a9a..39c7048 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/bicep/README.md +++ b/samples/web-app-cosmosdb-mongodb-api/python/bicep/README.md @@ -6,7 +6,7 @@ This directory contains the Bicep template and a deployment script for provision Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support and IntelliSense - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -276,4 +276,4 @@ This will remove all Azure resources created by the CLI deployment script. - [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) - [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicep b/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicep index 9699914..463b07f 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicep +++ b/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicep @@ -269,6 +269,7 @@ param tags object = { var webAppName = '${prefix}-webapp-${suffix}' var appServicePlanName = '${prefix}-app-service-plan-${suffix}' var accountName = '${prefix}-mongodb-${suffix}' +var privateDnsZoneName = 'privatelink.mongo.cosmos.azure.com' //******************************************** // Modules and Resources @@ -332,7 +333,7 @@ module network 'modules/virtual-network.bicep' = { module privateDnsZone 'modules/private-dns-zone.bicep' = { name: 'privateDnsZone' params: { - name: 'privatelink.mongo.cosmos.azure.com' + name: privateDnsZoneName vnetId: network.outputs.virtualNetworkId tags: tags } diff --git a/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicepparam b/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicepparam index 3819eeb..810db4d 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicepparam +++ b/samples/web-app-cosmosdb-mongodb-api/python/bicep/main.bicepparam @@ -1,6 +1,6 @@ using 'main.bicep' -param prefix = 'paolo' +param prefix = 'local' param suffix = 'test' param runtimeName = 'python' param runtimeVersion = '3.13' diff --git a/samples/web-app-cosmosdb-mongodb-api/python/bicep/modules/web-app.bicep b/samples/web-app-cosmosdb-mongodb-api/python/bicep/modules/web-app.bicep index 8af4bec..67ce3d2 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/bicep/modules/web-app.bicep +++ b/samples/web-app-cosmosdb-mongodb-api/python/bicep/modules/web-app.bicep @@ -179,7 +179,7 @@ resource configAppSettings 'Microsoft.Web/sites/config@2024-11-01' = { COSMOSDB_CONNECTION_STRING: account.listConnectionStrings().connectionStrings[0].connectionString COSMOSDB_DATABASE_NAME: databaseName COSMOSDB_COLLECTION_NAME: collectionName - WEBSITE_PORT: '8000' + WEBSITES_PORT: '8000' LOGIN_NAME: username } } diff --git a/samples/web-app-cosmosdb-mongodb-api/python/scripts/README.md b/samples/web-app-cosmosdb-mongodb-api/python/scripts/README.md index 1f6eaeb..0168135 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/scripts/README.md +++ b/samples/web-app-cosmosdb-mongodb-api/python/scripts/README.md @@ -6,7 +6,7 @@ This directory includes Bash scripts designed for deploying and testing the samp Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface @@ -260,4 +260,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/scripts/deploy.sh b/samples/web-app-cosmosdb-mongodb-api/python/scripts/deploy.sh index a28755a..a9b3408 100755 --- a/samples/web-app-cosmosdb-mongodb-api/python/scripts/deploy.sh +++ b/samples/web-app-cosmosdb-mongodb-api/python/scripts/deploy.sh @@ -7,14 +7,14 @@ LOCATION='westeurope' RESOURCE_GROUP_NAME="${PREFIX}-rg" LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" DIAGNOSTIC_SETTINGS_NAME='default' -WEBAPP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" VIRTUAL_NETWORK_ADDRESS_PREFIX="10.0.0.0/8" -WEBAPP_SUBNET_NAME="app-subnet" -WEBAPP_SUBNET_PREFIX="10.0.0.0/24" +WEB_APP_SUBNET_NAME="app-subnet" +WEB_APP_SUBNET_PREFIX="10.0.0.0/24" PE_SUBNET_NAME="pe-subnet" PE_SUBNET_PREFIX="10.0.1.0/24" VIRTUAL_NETWORK_LINK_NAME="link-to-vnet" @@ -24,7 +24,7 @@ PRIVATE_ENDPOINT_GROUP="mongodb" PRIVATE_DNS_ZONE_GROUP_NAME="default" APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" APP_SERVICE_PLAN_SKU="S1" -WEBAPP_NAME="${PREFIX}-webapp-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" COSMOSDB_ACCOUNT_NAME="${PREFIX}-mongodb-${SUFFIX}" MONGODB_API_VERSION="7.0" MONGODB_DATABASE_NAME="sampledb" @@ -37,7 +37,6 @@ RUNTIME_VERSION="3.13" LOGIN_NAME="paolo" CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)" ZIPFILE="planner_website.zip" -SUBSCRIPTION_ID=$(az account show --query id --output tsv) # Change the current directory to the script's directory cd "$CURRENT_DIR" || exit @@ -199,46 +198,46 @@ else fi # Check if the network security group for the web app subnet already exists -echo "Checking if [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +echo "Checking if [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group..." az network nsg show \ - --name "$WEBAPP_SUBNET_NSG_NAME" \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --only-show-errors &>/dev/null if [[ $? != 0 ]]; then - echo "No [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group" - echo "Creating [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet..." + echo "No [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet..." # Create the network security group for the web app subnet az network nsg create \ - --name "$WEBAPP_SUBNET_NSG_NAME" \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --location "$LOCATION" \ --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then - echo "[$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created in the [$RESOURCE_GROUP_NAME] resource group" + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created in the [$RESOURCE_GROUP_NAME] resource group" else - echo "Failed to create [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet in the [$RESOURCE_GROUP_NAME] resource group" + echo "Failed to create [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet in the [$RESOURCE_GROUP_NAME] resource group" exit 1 fi else - echo "[$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet already exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exists in the [$RESOURCE_GROUP_NAME] resource group" fi # Get the resource id of the network security group for the web app subnet -echo "Getting [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group..." -WEBAPP_SUBNET_NSG_ID=$(az network nsg show \ - --name "$WEBAPP_SUBNET_NSG_NAME" \ +echo "Getting [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group..." +WEB_APP_SUBNET_NSG_ID=$(az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query id \ --output tsv \ --only-show-errors) -if [[ -n $WEBAPP_SUBNET_NSG_ID ]]; then - echo "[$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet resource id retrieved successfully: $WEBAPP_SUBNET_NSG_ID" +if [[ -n $WEB_APP_SUBNET_NSG_ID ]]; then + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id retrieved successfully: $WEB_APP_SUBNET_NSG_ID" else - echo "Failed to retrieve [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group" + echo "Failed to retrieve [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group" exit 1 fi @@ -362,8 +361,8 @@ if [[ $? != 0 ]]; then --resource-group "$RESOURCE_GROUP_NAME" \ --location "$LOCATION" \ --address-prefixes "$VIRTUAL_NETWORK_ADDRESS_PREFIX" \ - --subnet-name "$WEBAPP_SUBNET_NAME" \ - --subnet-prefix "$WEBAPP_SUBNET_PREFIX" \ + --subnet-name "$WEB_APP_SUBNET_NAME" \ + --subnet-prefix "$WEB_APP_SUBNET_PREFIX" \ --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then @@ -374,21 +373,21 @@ if [[ $? != 0 ]]; then fi # Update the web app subnet to associate it with the NAT Gateway and the NSG - echo "Associating [$WEBAPP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEBAPP_SUBNET_NSG_NAME] network security group..." + echo "Associating [$WEB_APP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group..." # Update the web app subnet to associate it with the NAT Gateway and the NSG az network vnet subnet update \ - --name "$WEBAPP_SUBNET_NAME" \ + --name "$WEB_APP_SUBNET_NAME" \ --vnet-name "$VIRTUAL_NETWORK_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --nat-gateway "$NAT_GATEWAY_NAME" \ - --network-security-group "$WEBAPP_SUBNET_NSG_NAME" \ + --network-security-group "$WEB_APP_SUBNET_NSG_NAME" \ --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then - echo "[$WEBAPP_SUBNET_NAME] subnet successfully associated with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEBAPP_SUBNET_NSG_NAME] network security group" + echo "[$WEB_APP_SUBNET_NAME] subnet successfully associated with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group" else - echo "Failed to associate [$WEBAPP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEBAPP_SUBNET_NSG_NAME] network security group" + echo "Failed to associate [$WEB_APP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group" exit 1 fi else @@ -604,58 +603,58 @@ else fi # Create the web app -echo "Creating web app [$WEBAPP_NAME]..." +echo "Creating web app [$WEB_APP_NAME]..." az webapp create \ --resource-group "$RESOURCE_GROUP_NAME" \ --plan "$APP_SERVICE_PLAN_NAME" \ - --name "$WEBAPP_NAME" \ + --name "$WEB_APP_NAME" \ --runtime "$RUNTIME:$RUNTIME_VERSION" \ --vnet "$VIRTUAL_NETWORK_NAME" \ - --subnet "$WEBAPP_SUBNET_NAME" \ + --subnet "$WEB_APP_SUBNET_NAME" \ --only-show-errors 1>/dev/null if [ $? -eq 0 ]; then - echo "Web app [$WEBAPP_NAME] created successfully." + echo "Web app [$WEB_APP_NAME] created successfully." else - echo "Failed to create web app [$WEBAPP_NAME]." - exit 1 -fi - -# Enabling -echo "Enabling forced tunneling for web app [$WEBAPP_NAME] to route all outbound traffic through the virtual network..." - -az resource update \ - --ids "/subscriptions/$SUBSCRIPTION_ID/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.Web/sites/$WEBAPP_NAME" \ - --set properties.outboundVnetRouting.allTraffic=true \ - --only-show-errors 1>/dev/null - -if [ $? -eq 0 ]; then - echo "Forced tunneling enabled for web app [$WEBAPP_NAME]." -else - echo "Failed to enable forced tunneling for web app [$WEBAPP_NAME]." + echo "Failed to create web app [$WEB_APP_NAME]." exit 1 fi # Get the web app resource id -echo "Getting [$WEBAPP_NAME] web app resource id in the [$RESOURCE_GROUP_NAME] resource group..." -WEBAPP_ID=$(az webapp show \ - --name "$WEBAPP_NAME" \ +echo "Getting [$WEB_APP_NAME] web app resource id in the [$RESOURCE_GROUP_NAME] resource group..." +WEB_APP_ID=$(az webapp show \ + --name "$WEB_APP_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query id \ --output tsv \ --only-show-errors) -if [[ -n $WEBAPP_ID ]]; then - echo "[$WEBAPP_NAME] web app resource id retrieved successfully: $WEBAPP_ID" +if [[ -n $WEB_APP_ID ]]; then + echo "[$WEB_APP_NAME] web app resource id retrieved successfully: $WEB_APP_ID" +else + echo "Failed to retrieve [$WEB_APP_NAME] web app resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Enabling forced tunneling for web app [$WEB_APP_NAME] to route all outbound traffic through the virtual network... +echo "Enabling forced tunneling for web app [$WEB_APP_NAME] to route all outbound traffic through the virtual network..." + +az resource update \ + --ids "$WEB_APP_ID" \ + --set properties.outboundVnetRouting.allTraffic=true \ + --only-show-errors 1>/dev/null + +if [ $? -eq 0 ]; then + echo "Forced tunneling enabled for web app [$WEB_APP_NAME]." else - echo "Failed to retrieve [$WEBAPP_NAME] web app resource id in the [$RESOURCE_GROUP_NAME] resource group" + echo "Failed to enable forced tunneling for web app [$WEB_APP_NAME]." exit 1 fi # Set web app settings -echo "Setting web app settings for [$WEBAPP_NAME]..." +echo "Setting web app settings for [$WEB_APP_NAME]..." az webapp config appsettings set \ - --name $WEBAPP_NAME \ + --name $WEB_APP_NAME \ --resource-group $RESOURCE_GROUP_NAME \ --settings \ SCM_DO_BUILD_DURING_DEPLOYMENT='true' \ @@ -664,13 +663,13 @@ az webapp config appsettings set \ COSMOSDB_DATABASE_NAME="$MONGODB_DATABASE_NAME" \ COSMOSDB_COLLECTION_NAME="$COLLECTION_NAME" \ LOGIN_NAME="$LOGIN_NAME" \ - WEBSITE_PORT="8000" \ + WEBSITES_PORT="8000" \ --only-show-errors 1>/dev/null if [ $? -eq 0 ]; then - echo "Web app settings for [$WEBAPP_NAME] set successfully." + echo "Web app settings for [$WEB_APP_NAME] set successfully." else - echo "Failed to set web app settings for [$WEBAPP_NAME]." + echo "Failed to set web app settings for [$WEB_APP_NAME]." exit 1 fi @@ -706,20 +705,20 @@ else fi # Check whether the diagnostic settings for the web app already exist -echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app already exist..." +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app already exist..." az monitor diagnostic-settings show \ --name "$DIAGNOSTIC_SETTINGS_NAME" \ - --resource "$WEBAPP_ID" \ + --resource "$WEB_APP_ID" \ --only-show-errors &>/dev/null if [[ $? != 0 ]]; then - echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app actually exist" - echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app..." + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app..." # Create the diagnostic settings for the web app to send logs to the Log Analytics workspace az monitor diagnostic-settings create \ --name "$DIAGNOSTIC_SETTINGS_NAME" \ - --resource "$WEBAPP_ID" \ + --resource "$WEB_APP_ID" \ --workspace "$LOG_ANALYTICS_NAME" \ --logs '[ {"category": "AppServiceHTTPLogs", "enabled": true}, @@ -737,13 +736,13 @@ if [[ $? != 0 ]]; then if [[ $? == 0 ]]; then - echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app successfully created" + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app successfully created" else - echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app" + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app" exit 1 fi else - echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_NAME] web app already exist" + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app already exist" fi # Check whether the diagnostic settings for the app service plan already exist @@ -847,20 +846,20 @@ else fi # Check whether the diagnostic settings for the network security group for the web app subnet already exist -echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet already exist..." +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exist..." az monitor diagnostic-settings show \ --name "$DIAGNOSTIC_SETTINGS_NAME" \ - --resource "$WEBAPP_SUBNET_NSG_ID" \ + --resource "$WEB_APP_SUBNET_NSG_ID" \ --only-show-errors &>/dev/null if [[ $? != 0 ]]; then - echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet actually exist" - echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet..." + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet..." # Create the diagnostic settings for the network security group for the web app subnet to send logs to the Log Analytics workspace az monitor diagnostic-settings create \ --name "$DIAGNOSTIC_SETTINGS_NAME" \ - --resource "$WEBAPP_SUBNET_NSG_ID" \ + --resource "$WEB_APP_SUBNET_NSG_ID" \ --workspace "$LOG_ANALYTICS_NAME" \ --logs '[ {"category": "NetworkSecurityGroupEvent", "enabled": true}, @@ -869,13 +868,13 @@ if [[ $? != 0 ]]; then --only-show-errors 1>/dev/null if [[ $? == 0 ]]; then - echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created" + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created" else - echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet" + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet" exit 1 fi else - echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEBAPP_SUBNET_NSG_NAME] network security group for the web app subnet already exist" + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exist" fi # Check whether the diagnostic settings for the network security group for the private endpoint subnet already exist @@ -927,11 +926,11 @@ echo "Contents of the zip package [$ZIPFILE]:" unzip -l "$ZIPFILE" # Deploy the web app -echo "Deploying web app [$WEBAPP_NAME] with zip file [$ZIPFILE]..." +echo "Deploying web app [$WEB_APP_NAME] with zip file [$ZIPFILE]..." echo "Using standard az webapp deploy command for AzureCloud environment." az webapp deploy \ --resource-group "$RESOURCE_GROUP_NAME" \ - --name "$WEBAPP_NAME" \ + --name "$WEB_APP_NAME" \ --src-path "$ZIPFILE" \ --type zip \ --async true 1>/dev/null diff --git a/samples/web-app-cosmosdb-mongodb-api/python/scripts/validate.sh b/samples/web-app-cosmosdb-mongodb-api/python/scripts/validate.sh index b2f0459..4360e51 100755 --- a/samples/web-app-cosmosdb-mongodb-api/python/scripts/validate.sh +++ b/samples/web-app-cosmosdb-mongodb-api/python/scripts/validate.sh @@ -5,14 +5,14 @@ PREFIX='local' SUFFIX='test' RESOURCE_GROUP_NAME="${PREFIX}-rg" LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" -WEBAPP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" PRIVATE_DNS_ZONE_NAME="privatelink.mongo.cosmos.azure.com" PRIVATE_ENDPOINT_NAME="${PREFIX}-mongodb-pe-${SUFFIX}" APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" -WEBAPP_NAME="${PREFIX}-webapp-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" COSMOSDB_ACCOUNT_NAME="${PREFIX}-mongodb-${SUFFIX}" MONGODB_DATABASE_NAME="sampledb" COLLECTION_NAME="activities" @@ -32,9 +32,9 @@ az appservice plan show \ --only-show-errors # Check Azure Web App -echo -e "\n[$WEBAPP_NAME] web app:\n" +echo -e "\n[$WEB_APP_NAME] web app:\n" az webapp show \ - --name "$WEBAPP_NAME" \ + --name "$WEB_APP_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --output table \ --only-show-errors @@ -111,9 +111,9 @@ az network private-endpoint show \ --only-show-errors # Check Web App Subnet NSG -echo -e "\n[$WEBAPP_SUBNET_NSG_NAME] network security group:\n" +echo -e "\n[$WEB_APP_SUBNET_NSG_NAME] network security group:\n" az network nsg show \ - --name "$WEBAPP_SUBNET_NSG_NAME" \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --output table \ --only-show-errors diff --git a/samples/web-app-cosmosdb-mongodb-api/python/terraform/README.md b/samples/web-app-cosmosdb-mongodb-api/python/terraform/README.md index 564d95b..46f3c53 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/terraform/README.md +++ b/samples/web-app-cosmosdb-mongodb-api/python/terraform/README.md @@ -6,7 +6,7 @@ This directory contains Terraform modules and a deployment script for provisioni Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool for provisioning Azure resources - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack @@ -280,4 +280,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Terraform Azure Provider](https://registry.terraform.io/providers/hashicorp/azurerm/latest) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/terraform/main.tf b/samples/web-app-cosmosdb-mongodb-api/python/terraform/main.tf index 9439ff2..55d3f1c 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/terraform/main.tf +++ b/samples/web-app-cosmosdb-mongodb-api/python/terraform/main.tf @@ -4,7 +4,6 @@ locals { suffix = lower(var.suffix) resource_group_name = "${var.prefix}-rg" log_analytics_name = "${local.prefix}-log-analytics-${local.suffix}" - storage_account_name = "${local.prefix}datastore${local.suffix}" virtual_network_name = "${local.prefix}-vnet-${local.suffix}" nat_gateway_name = "${local.prefix}-nat-gateway-${local.suffix}" private_endpoint_name = "${local.prefix}-mongodb-pe-${local.suffix}" @@ -189,6 +188,6 @@ module "web_app" { COSMOSDB_DATABASE_NAME = module.cosmosdb_mongodb.database_name COSMOSDB_COLLECTION_NAME = var.cosmosdb_collection_name LOGIN_NAME = var.login_name - WEBSITE_PORT = var.website_port + WEBSITES_PORT = var.websites_port } } \ No newline at end of file diff --git a/samples/web-app-cosmosdb-mongodb-api/python/terraform/modules/app_service_plan/main.tf b/samples/web-app-cosmosdb-mongodb-api/python/terraform/modules/app_service_plan/main.tf index 0f67edb..98a3e4d 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/terraform/modules/app_service_plan/main.tf +++ b/samples/web-app-cosmosdb-mongodb-api/python/terraform/modules/app_service_plan/main.tf @@ -19,10 +19,6 @@ resource "azurerm_monitor_diagnostic_setting" "example" { target_resource_id = azurerm_service_plan.example.id log_analytics_workspace_id = var.log_analytics_workspace_id - enabled_log { - category = "VMProtectionAlerts" - } - enabled_metric { category = "AllMetrics" } diff --git a/samples/web-app-cosmosdb-mongodb-api/python/terraform/variables.tf b/samples/web-app-cosmosdb-mongodb-api/python/terraform/variables.tf index 702e90d..d33bed9 100644 --- a/samples/web-app-cosmosdb-mongodb-api/python/terraform/variables.tf +++ b/samples/web-app-cosmosdb-mongodb-api/python/terraform/variables.tf @@ -310,7 +310,7 @@ variable "nat_gateway_zones" { default = ["1"] } -variable "website_port" { +variable "websites_port" { description = "(Optional) Specifies the port on which the Web App will listen. Defaults to 8000." type = number default = 8000 diff --git a/samples/web-app-cosmosdb-nosql-api/python/README.md b/samples/web-app-cosmosdb-nosql-api/python/README.md index a5c11b5..224beb2 100644 --- a/samples/web-app-cosmosdb-nosql-api/python/README.md +++ b/samples/web-app-cosmosdb-nosql-api/python/README.md @@ -75,4 +75,4 @@ You can utilize **CosmosDB Data Explorer** to explore and manage your CosmosDB d - [Azure CosmosDB Documentation](https://learn.microsoft.com/en-us/azure/cosmos-db/) - [Quickstart: Python Flask on Azure](https://learn.microsoft.com/en-us/azure/app-service/quickstart-python?tabs=flask%2Cbrowser) - [Azure Identity Client Library for Python](https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python) -- [LocalStack for Azure](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-cosmosdb-nosql-api/python/scripts/README.md b/samples/web-app-cosmosdb-nosql-api/python/scripts/README.md index dadeb7a..806ae97 100644 --- a/samples/web-app-cosmosdb-nosql-api/python/scripts/README.md +++ b/samples/web-app-cosmosdb-nosql-api/python/scripts/README.md @@ -6,7 +6,7 @@ This directory includes Bash scripts designed for deploying and testing the samp Before deploying this solution, ensure you have the following tools installed: -- [LocalStack for Azure](https://azure.localstack.cloud/): Local Azure cloud emulator for development and testing +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing - [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface @@ -112,4 +112,4 @@ This will remove all Azure resources created by the CLI deployment script. ## Related Documentation - [Azure CLI Documentation](https://docs.microsoft.com/en-us/cli/azure/) -- [LocalStack for Azure Documentation](https://azure.localstack.cloud/) \ No newline at end of file +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-custom-image/python/README.md b/samples/web-app-custom-image/python/README.md index 6662fc6..053c2d1 100644 --- a/samples/web-app-custom-image/python/README.md +++ b/samples/web-app-custom-image/python/README.md @@ -1,59 +1,79 @@ -# Azure Web App With Custom Docker Image +# Azure Web App with Custom Docker Image -This sample demonstrates a Python Flask web application hosted on an Azure Web App using a custom Docker image. The deployment builds the image from the local `src/Dockerfile`, creates an Azure Container Registry resource, and configures a Linux Web App to run the custom image in the LocalStack Azure emulator. +This sample demonstrates a Python Flask web application hosted on an [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview) using a custom Docker image. The app runs on an Azure App Service Plan and uses a container image stored in an [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-intro). For more information on configuring a web app to use a custom container, see [Configure a custom container for Azure App Service](https://learn.microsoft.com/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux). ## Architecture -The sample creates the following Azure resources: +The following diagram illustrates the architecture of the solution: -1. **Azure Resource Group**: Logical container for all resources in the sample. -2. **Azure Container Registry**: Stores the custom Docker image metadata and credentials. -3. **Azure App Service Plan**: Linux plan used by the Web App. -4. **Azure Web App**: Runs the Flask application from the custom image. +![Architecture Diagram](./images/architecture.png) + +The solution is composed of the following Azure resources: + +1. [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-cli): A logical container scoping all resources in this sample. +2. [Azure Virtual Network](https://learn.microsoft.com/azure/virtual-network/virtual-networks-overview): Hosts two subnets: + - *app-subnet*: Dedicated to [regional VNet integration](https://learn.microsoft.com/azure/azure-functions/functions-networking-options?tabs=azure-portal#outbound-networking-features) with the Web App. + - *pe-subnet*: Used for hosting Azure Private Endpoints. +3. [Azure Private DNS Zone](https://learn.microsoft.com/azure/dns/private-dns-privatednszone): Handles DNS resolution for the Azure Container Registry Private Endpoint within the virtual network. +4. [Azure Private Endpoint](https://learn.microsoft.com/azure/private-link/private-endpoint-overview): Secures network access to the Azure Container Registry via a private IP within the VNet. +5. [Azure NAT Gateway](https://learn.microsoft.com/azure/nat-gateway/nat-overview): Provides deterministic outbound connectivity for the Web App. Included for completeness; the sample app does not call any external services. +6. [Azure Network Security Group](https://learn.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview): Enforces inbound and outbound traffic rules across the virtual network's subnets. +7. [Azure Log Analytics Workspace](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-overview): Centralizes diagnostic logs and metrics from all resources in the solution. +8. [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-intro): A fully-managed container registry service based on the open-source [Docker platform](https://docs.docker.com/get-started/docker-overview/) used to hold the container image used by the web app. +9. [User-Assigned Managed Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview): Assigned the [AcrPull](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull) role on the Azure Container Registry, enabling the Web App to pull the container image without storing credentials. +10. [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans): The underlying compute tier that hosts the web application. +11. [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview): Runs the Python Flask application from the custom container image stored in the Azure Container Registry. ## Prerequisites -- Docker -- Azure CLI -- azlocal CLI -- jq -- LocalStack for Azure +- [Azure Subscription](https://azure.microsoft.com/free/) +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) +- [Docker](https://docs.docker.com/get-docker/)udio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep. +- [Terraform](https://developer.hashicorp.com/terraform/downloads), if you plan to install the sample via Terraform. +- [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper +- [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs -## Deploy +## Deployment -Start LocalStack for Azure and configure Azure CLI interception as described in the repository root README. Then run: +Set up the Azure emulator using the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and set it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the image, execute: ```bash -cd samples/web-app-custom-image/python -bash scripts/deploy.sh +docker pull localstack/localstack-azure-alpha ``` -The script builds the Docker image from `src/`, creates the App Service resources, and configures the Web App to use the custom image. - -## Validate +Start the LocalStack Azure emulator by running: ```bash -bash scripts/validate.sh -``` +# Set the authentication token +export LOCALSTACK_AUTH_TOKEN= -## Invoke The App +# Start the LocalStack Azure emulator +IMAGE_NAME=localstack/localstack-azure-alpha localstack start -d +localstack wait -t 60 -```bash -bash scripts/call-web-app.sh +# Route all Azure CLI calls to the LocalStack Azure emulator +azlocal start-interception ``` -The app exposes: +Deploy the application to LocalStack for Azure using one of these methods: -- `/` for the HTML page -- `/api/status` for a JSON health response +- [Azure CLI Deployment](./scripts/README.md) +- [Bicep Deployment](./bicep/README.md) +- [Terraform Deployment](./terraform/README.md) -## Local Docker Run +All deployment methods have been fully tested against Azure and the LocalStack for Azure local emulator. -You can run the same image directly with Docker: +> **Note** +> When you deploy the application to LocalStack for Azure for the first time, the initialization process involves downloading and building Docker images. This is a one-time operation—subsequent deployments will be significantly faster. Depending on your internet connection and system resources, this initial setup may take several minutes. -```bash -cd src -docker build -t vacation-planner-webapp:v1 . -docker run --rm -p 8080:80 vacation-planner-webapp:v1 -curl http://127.0.0.1:8080/api/status -``` +## Test + +You can use the `call-web-app.sh` Bash script below to call the web app. The script calls the web app via the default hostname `.azurewebsites.azure.localhost.localstack.cloud:4566`. + +## References + +- [Azure Web Apps Documentation](https://learn.microsoft.com/en-us/azure/app-service/) +- [Azure Container Registry Documentation](https://learn.microsoft.com/azure/container-registry/container-registry-intro) +- [Configure a custom container for Azure App Service](https://learn.microsoft.com/azure/app-service/configure-custom-container?tabs=debian&pivots=container-linux) +- [Azure Identity Client Library for Python](https://learn.microsoft.com/en-us/python/api/overview/azure/identity-readme?view=azure-python) +- [LocalStack for Azure](https://docs.localstack.cloud/azure/) diff --git a/samples/web-app-custom-image/python/bicep/README.md b/samples/web-app-custom-image/python/bicep/README.md new file mode 100644 index 0000000..4fe9889 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/README.md @@ -0,0 +1,286 @@ +# Bicep Deployment + +This directory contains the Bicep templates and a deployment script for provisioning Azure services in LocalStack for Azure. For further details about the sample application, refer to the [Azure Web App with Custom Docker Image](../README.md). + +## Prerequisites + +Before deploying this solution, ensure you have the following tools installed: + +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing +- [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) +- [Bicep extension](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep): VS Code extension for Bicep language support and IntelliSense +- [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack and building the custom image +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface +- [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper +- [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs + +### Installing azlocal CLI + +The [deploy.sh](deploy.sh) Bash script uses the `azlocal` CLI instead of the standard Azure CLI to work with LocalStack. Install it using: + +```bash +pip install azlocal +``` + +For more information, see [Get started with the az tool on LocalStack](https://azure.localstack.cloud/user-guides/sdks/az/). + +## Architecture Overview + +The [deploy.sh](deploy.sh) script creates the [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-cli) for all the Azure resources. The deployment is split into two Bicep phases with an image push step between them. + +### First Bicep Deployment +In this phase, the [acr.bicep](acr.bicep) template deploys: + +1. [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-intro): A fully-managed container registry service based on the open-source [Docker platform](https://docs.docker.com/get-started/docker-overview/) used to hold the container image used by the web app. +2. [Azure Log Analytics Workspace](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-overview): Centralizes diagnostic logs and metrics from all resources in the solution. + +## Container Image Push +After the first Bicep deployment, the script builds the container image locally from the `src/Dockerfile` and pushes it to the Azure Container Registry. + +### Second Bicep Deployment +The [main.bicep](main.bicep) template deploys the remaining resources: + +1. [Azure Virtual Network](https://learn.microsoft.com/azure/virtual-network/virtual-networks-overview): Hosts two subnets: + - *app-subnet*: Dedicated to [regional VNet integration](https://learn.microsoft.com/azure/azure-functions/functions-networking-options?tabs=azure-portal#outbound-networking-features) with the Web App. + - *pe-subnet*: Used for hosting Azure Private Endpoints. +2. [Azure Private DNS Zone](https://learn.microsoft.com/azure/dns/private-dns-privatednszone): Handles DNS resolution for the Azure Container Registry Private Endpoint within the virtual network. +3. [Azure Private Endpoint](https://learn.microsoft.com/azure/private-link/private-endpoint-overview): Secures network access to the Azure Container Registry via a private IP within the VNet. +4. [Azure NAT Gateway](https://learn.microsoft.com/azure/nat-gateway/nat-overview): Provides deterministic outbound connectivity for the Web App. Included for completeness; the sample app does not call any external services. +5. [Azure Network Security Group](https://learn.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview): Enforces inbound and outbound traffic rules across the virtual network's subnets. +6. [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans): The underlying compute tier that hosts the web application. +7. [User-Assigned Managed Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview): Assigned the [AcrPull](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull) role on the Azure Container Registry, enabling the Web App to pull the container image without storing credentials. +8. [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview): Runs the Python Flask application from the custom container image stored in the Azure Container Registry. + +The provisioning process assigns the user-defined managed identity to the web app and uses its credentials to access the Azure Container Registry to pull the container image. The [AcrPull](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull) role is assigned to the managed identity with the Azure Container Registry as the scope. + +For more information on the sample application, see [Azure Web App with Custom Docker Image](../README.md). + +## Configuration + +Before deploying the `main.bicep` template, update the `main.bicepparam` file with your specific values: + +```bicep +using 'main.bicep' + +param prefix = 'local' +param suffix = 'test' +param imageName = 'custom-image-webapp' +param imageTag = 'v1' +param tags = { + environment: 'test' + project: 'custom-image-webapp' +} +``` + +## Provisioning Scripts + +See [deploy.sh](deploy.sh) for the complete deployment automation. The script performs: + +- Detects environment (LocalStack vs Azure Cloud) and uses appropriate CLI +- Creates resource group if it doesn't exist +- Optionally validates the Bicep template +- Optionally runs what-if deployment for preview +- Deploys [acr.bicep](acr.bicep) to provision the Azure Container Registry and Log Analytics Workspace +- Extracts deployment outputs (ACR name, ACR login server) +- Builds the container image locally and pushes it to the Azure Container Registry +- Deploys [main.bicep](main.bicep) with parameters from [main.bicepparam](main.bicepparam) to provision the remaining resources +- Extracts deployment outputs (Web App name, App Service Plan name, Managed Identity name) + +## Deployment + +You can set up the Azure emulator by utilizing the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and specify it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the Azure Docker image, execute the following command: + +```bash +docker pull localstack/localstack-azure-alpha +``` + +Start the LocalStack Azure emulator using the localstack CLI, execute the following command: + +```bash +# Set the authentication token +export LOCALSTACK_AUTH_TOKEN= + +# Start the LocalStack Azure emulator +IMAGE_NAME=localstack/localstack-azure-alpha localstack start -d +localstack wait -t 60 + +# Route all Azure CLI calls to the LocalStack Azure emulator +azlocal start-interception +``` + +Navigate to the `bicep` folder: + +```bash +cd samples/web-app-custom-image/python/bicep +``` + +Make the script executable: + +```bash +chmod +x deploy.sh +``` + +Run the deployment script: + +```bash +./deploy.sh +``` + +## Validation + +Once the deployment completes, run the [validate.sh](../scripts/validate.sh) script to confirm that all resources were provisioned and configured as expected: + +```bash +#!/bin/bash +set -euo pipefail + +PREFIX='local' +SUFFIX='test' +RESOURCE_GROUP_NAME="${PREFIX}-rg" +ACR_NAME="${PREFIX}acr${SUFFIX}" +MANAGED_IDENTITY_NAME="${PREFIX}-identity-${SUFFIX}" +APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" +VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" +PRIVATE_DNS_ZONE_NAME="privatelink.azurecr.io" +PRIVATE_ENDPOINT_NAME="${PREFIX}-acr-pe-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" +NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" +PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" +LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" + +# Check resource group +echo -e "[$RESOURCE_GROUP_NAME] resource group:\n" +az group show \ + --name "$RESOURCE_GROUP_NAME" \ + --output table + +# Check managed identity +echo -e "[$MANAGED_IDENTITY_NAME] managed identity:\n" +az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check App Service Plan +echo -e "\n[$APP_SERVICE_PLAN_NAME] App Service Plan:\n" +az appservice plan show \ + --name "$APP_SERVICE_PLAN_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Container Registry +echo -e "\n[$ACR_NAME] Azure Container Registry:\n" +az acr show \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Web App +echo -e "\n[$WEB_APP_NAME] Web App:\n" +az webapp show \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "{name:name, state:state, defaultHostName:defaultHostName, kind:kind}" \ + --output table + +# Check App Settings +echo -e "\n[$WEB_APP_NAME] app settings:\n" +az webapp config appsettings list \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[?name=='IMAGE_NAME' || name=='APP_NAME' || name=='WEBSITES_PORT']" \ + --output table + +# Check Virtual Network +echo -e "\n[$VIRTUAL_NETWORK_NAME] virtual network:\n" +az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private DNS Zone +echo -e "\n[$PRIVATE_DNS_ZONE_NAME] private dns zone:\n" +az network private-dns zone show \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query '{Name:name,ResourceGroup:resourceGroup,RecordSets:recordSets,VirtualNetworkLinks:virtualNetworkLinks}' \ + --output table \ + --only-show-errors + +# Check Private Endpoint +echo -e "\n[$PRIVATE_ENDPOINT_NAME] private endpoint:\n" +az network private-endpoint show \ + --name "$PRIVATE_ENDPOINT_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Web App Subnet NSG +echo -e "\n[$WEB_APP_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private Endpoint Subnet NSG +echo -e "\n[$PE_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check NAT Gateway +echo -e "\n[$NAT_GATEWAY_NAME] nat gateway:\n" +az network nat gateway show \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Public IP Prefix +echo -e "\n[$PIP_PREFIX_NAME] public ip prefix:\n" +az network public-ip prefix show \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Log Analytics Workspace +echo -e "\n[$LOG_ANALYTICS_NAME] log analytics workspace:\n" +az monitor log-analytics workspace show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --workspace-name "$LOG_ANALYTICS_NAME" \ + --query '{Name:name,Location:location,ResourceGroup:resourceGroup}' \ + --output table \ + --only-show-errors + +echo -e "\nResources in [$RESOURCE_GROUP_NAME]:\n" +az resource list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table +``` + +## Cleanup + +To destroy all created resources: + +```bash +# Delete resource group and all contained resources +az group delete --name local-rg --yes --no-wait + +# Verify deletion +az group list --output table +``` + +This will remove all Azure resources created by the Bicep deployment script. + +## Related Documentation + +- [Azure Bicep Documentation](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/) +- [Bicep Language Reference](https://docs.microsoft.com/en-us/azure/azure-resource-manager/bicep/bicep-functions) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) \ No newline at end of file diff --git a/samples/web-app-custom-image/python/bicep/acr.bicep b/samples/web-app-custom-image/python/bicep/acr.bicep new file mode 100644 index 0000000..01a4e6b --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/acr.bicep @@ -0,0 +1,81 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the prefix for the name of the Azure resources.') +@minLength(2) +param prefix string = take(uniqueString(resourceGroup().id), 4) + +@description('Specifies the suffix for the name of the Azure resources.') +@minLength(2) +param suffix string = take(uniqueString(resourceGroup().id), 4) + +@description('Specifies the location for all resources.') +param location string = resourceGroup().location + +@description('Specifies the name of the Azure Log Analytics resource.') +param logAnalyticsName string = '' + +@description('Specifies the service tier of the workspace: Free, Standalone, PerNode, Per-GB.') +@allowed([ + 'Free' + 'Standalone' + 'PerNode' + 'PerGB2018' +]) +param logAnalyticsSku string = 'PerNode' + +@description('Specifies the workspace data retention in days. -1 means Unlimited retention for the Unlimited Sku. 730 days is the maximum allowed for all other Skus.') +param logAnalyticsRetentionInDays int = 60 + +@description('Tier of your Azure Container Registry.') +@allowed([ + 'Basic' + 'Standard' + 'Premium' +]) +param acrSku string = 'Premium' + +@description('Specifies the tags to be applied to the resources.') +param tags object = { + environment: 'test' + iac: 'bicep' +} + +//******************************************** +// Variables +//******************************************** +var acrName = '${prefix}acr${suffix}' + +//******************************************** +// Modules and Resources +//******************************************** +module workspace 'modules/log-analytics.bicep' = { + name: 'workspace' + params: { + // properties + name: empty(logAnalyticsName) ? toLower('${prefix}-log-analytics-${suffix}') : logAnalyticsName + location: location + tags: tags + sku: logAnalyticsSku + retentionInDays: logAnalyticsRetentionInDays + } +} + +module containerRegistry './modules/container-registry.bicep' = { + name: 'containerRegistry' + params: { + name: acrName + sku: acrSku + adminUserEnabled: true + workspaceId: workspace.outputs.id + location: location + tags: tags + } +} + +//******************************************** +// Outputs +//******************************************** +output acrName string = containerRegistry.outputs.name +output acrLoginServer string = containerRegistry.outputs.loginServer +output logAnalyticsWorkspaceName string = workspace.outputs.name diff --git a/samples/web-app-custom-image/python/bicep/acr.bicepparam b/samples/web-app-custom-image/python/bicep/acr.bicepparam new file mode 100644 index 0000000..f58b20d --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/acr.bicepparam @@ -0,0 +1,8 @@ +using 'acr.bicep' + +param prefix = 'local' +param suffix = 'test' +param tags = { + environment: 'test' + project: 'custom-image-webapp' +} diff --git a/samples/web-app-custom-image/python/bicep/deploy.sh b/samples/web-app-custom-image/python/bicep/deploy.sh new file mode 100755 index 0000000..9c16125 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/deploy.sh @@ -0,0 +1,254 @@ +#!/bin/bash + +# Variables +PREFIX='local' +SUFFIX='test' +ACR_TEMPLATE="acr.bicep" +ACR_PARAMETERS="acr.bicepparam" +MAIN_TEMPLATE="main.bicep" +MAIN_PARAMETERS="main.bicepparam" +RESOURCE_GROUP_NAME="${PREFIX}-rg" +LOCATION="westeurope" +IMAGE_NAME="custom-image-webapp" +IMAGE_TAG="v1" +LOCAL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +VALIDATE_TEMPLATE=1 +USE_WHAT_IF=0 +SUBSCRIPTION_NAME=$(az account show --query name --output tsv) +CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)" + +# Change the current directory to the script's directory +cd "$CURRENT_DIR" || exit + +# Validates if the resource group exists in the subscription, if not creates it +echo "Checking if resource group [$RESOURCE_GROUP_NAME] exists in the subscription [$SUBSCRIPTION_NAME]..." +az group show --name $RESOURCE_GROUP_NAME &>/dev/null + +if [[ $? != 0 ]]; then + echo "No resource group [$RESOURCE_GROUP_NAME] exists in the subscription [$SUBSCRIPTION_NAME]" + echo "Creating resource group [$RESOURCE_GROUP_NAME] in the subscription [$SUBSCRIPTION_NAME]..." + + # Create the resource group + az group create \ + --name $RESOURCE_GROUP_NAME \ + --location $LOCATION \ + --only-show-errors 1> /dev/null + + if [[ $? == 0 ]]; then + echo "Resource group [$RESOURCE_GROUP_NAME] successfully created in the subscription [$SUBSCRIPTION_NAME]" + else + echo "Failed to create resource group [$RESOURCE_GROUP_NAME] in the subscription [$SUBSCRIPTION_NAME]" + exit + fi +else + echo "Resource group [$RESOURCE_GROUP_NAME] already exists in the subscription [$SUBSCRIPTION_NAME]" +fi + +echo "Deploying Azure Container Registry and Log Analytics Workspace Bicep..." + +# Validates the Bicep template +if [[ $VALIDATE_TEMPLATE == 1 ]]; then + if [[ $USE_WHAT_IF == 1 ]]; then + # Execute a deployment What-If operation at resource group scope. + echo "Previewing changes deployed by Bicep template [$ACR_TEMPLATE]..." + az deployment group what-if \ + --resource-group $RESOURCE_GROUP_NAME \ + --template-file $ACR_TEMPLATE \ + --parameters $ACR_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + --only-show-errors + + if [[ $? == 0 ]]; then + echo "Bicep template [$ACR_TEMPLATE] validation succeeded" + else + echo "Failed to validate Bicep template [$ACR_TEMPLATE]" + exit + fi + else + # Validate the Bicep template + echo "Validating Bicep template [$ACR_TEMPLATE]..." + output=$(az deployment group validate \ + --resource-group $RESOURCE_GROUP_NAME \ + --template-file $ACR_TEMPLATE \ + --parameters $ACR_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + --only-show-errors) + + if [[ $? == 0 ]]; then + echo "Bicep template [$ACR_TEMPLATE] validation succeeded" + else + echo "Failed to validate Bicep template [$ACR_TEMPLATE]" + echo "$output" + exit + fi + fi +fi + +# Deploy the Bicep template +echo "Deploying Bicep template [$ACR_TEMPLATE]..." +if DEPLOYMENT_OUTPUTS=$(az deployment group create \ + --resource-group $RESOURCE_GROUP_NAME \ + --only-show-errors \ + --template-file $ACR_TEMPLATE \ + --parameters $ACR_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + --query 'properties.outputs' -o json); then + # Extract only the JSON portion (everything from first { to the end) + DEPLOYMENT_JSON=$(echo "$DEPLOYMENT_OUTPUTS" | sed -n '/{/,$ p') + echo "Bicep template [$ACR_TEMPLATE] deployed successfully. Outputs:" + echo "$DEPLOYMENT_JSON" | jq . + ACR_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.acrName.value') + ACR_LOGIN_SERVER=$(echo "$DEPLOYMENT_JSON" | jq -r '.acrLoginServer.value') + LOG_ANALYTICS_WORKSPACE_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.logAnalyticsWorkspaceName.value') + echo "Deployment complete." + echo "Resource Group: $RESOURCE_GROUP_NAME" + echo "Azure Container Registry: $ACR_NAME ($ACR_LOGIN_SERVER)" +else + echo "Failed to deploy Bicep template [$ACR_TEMPLATE]" + exit 1 +fi + +if [[ -z "$ACR_NAME" || -z "$ACR_LOGIN_SERVER" || -z "$LOG_ANALYTICS_WORKSPACE_NAME" ]]; then + echo "ACR Name, ACR Login Server, or Log Analytics Workspace Name is empty. Exiting." + exit 1 +fi + +echo "Logging into Azure Container Registry [$ACR_NAME]..." +az acr login --name "$ACR_NAME" --only-show-errors + +if [ $? -eq 0 ]; then + echo "Logged into Azure Container Registry [$ACR_NAME] successfully." +else + echo "Failed to log into Azure Container Registry [$ACR_NAME]." + exit 1 +fi + +# Create full image name with login server, image name, and tag +FULL_IMAGE="${ACR_LOGIN_SERVER}/${IMAGE_NAME}:${IMAGE_TAG}" + +echo "Building custom Docker image [$LOCAL_IMAGE]..." +docker build -t "$LOCAL_IMAGE" ../src/ + +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] built successfully." +else + echo "Failed to build Docker image [$LOCAL_IMAGE]." + exit 1 +fi + +echo "Tagging Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]..." +docker tag "$LOCAL_IMAGE" "$FULL_IMAGE" + +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] tagged as [$FULL_IMAGE] successfully." +else + echo "Failed to tag Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]." + exit 1 +fi + +echo "Pushing image [$FULL_IMAGE] to ACR..." +docker push "$FULL_IMAGE" + +if [ $? -eq 0 ]; then + echo "Docker image [$FULL_IMAGE] pushed to ACR successfully." +else + echo "Failed to push Docker image [$FULL_IMAGE] to ACR." + exit 1 +fi + +echo "Deploying the remaining Azure resources..." + +# Validates the Bicep template +if [[ $VALIDATE_TEMPLATE == 1 ]]; then + if [[ $USE_WHAT_IF == 1 ]]; then + # Execute a deployment What-If operation at resource group scope. + echo "Previewing changes deployed by Bicep template [$MAIN_TEMPLATE]..." + az deployment group what-if \ + --resource-group $RESOURCE_GROUP_NAME \ + --template-file $MAIN_TEMPLATE \ + --parameters $MAIN_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + imageName=$IMAGE_NAME \ + imageTag=$IMAGE_TAG \ + acrName="$ACR_NAME" \ + logAnalyticsWorkspaceName="$LOG_ANALYTICS_WORKSPACE_NAME" \ + --only-show-errors + + if [[ $? == 0 ]]; then + echo "Bicep template [$MAIN_TEMPLATE] validation succeeded" + else + echo "Failed to validate Bicep template [$MAIN_TEMPLATE]" + exit + fi + else + # Validate the Bicep template + echo "Validating Bicep template [$MAIN_TEMPLATE]..." + output=$(az deployment group validate \ + --resource-group $RESOURCE_GROUP_NAME \ + --template-file $MAIN_TEMPLATE \ + --parameters $MAIN_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + imageName=$IMAGE_NAME \ + imageTag=$IMAGE_TAG \ + acrName="$ACR_NAME" \ + logAnalyticsWorkspaceName="$LOG_ANALYTICS_WORKSPACE_NAME" \ + --only-show-errors) + + if [[ $? == 0 ]]; then + echo "Bicep template [$MAIN_TEMPLATE] validation succeeded" + else + echo "Failed to validate Bicep template [$MAIN_TEMPLATE]" + echo "$output" + exit + fi + fi +fi + +# Deploy the Bicep template +echo "Deploying Bicep template [$MAIN_TEMPLATE]..." +if DEPLOYMENT_OUTPUTS=$(az deployment group create \ + --resource-group $RESOURCE_GROUP_NAME \ + --only-show-errors \ + --template-file $MAIN_TEMPLATE \ + --parameters $MAIN_PARAMETERS \ + --parameters location=$LOCATION \ + prefix=$PREFIX \ + suffix=$SUFFIX \ + imageName=$IMAGE_NAME \ + imageTag=$IMAGE_TAG \ + acrName="$ACR_NAME" \ + logAnalyticsWorkspaceName="$LOG_ANALYTICS_WORKSPACE_NAME" \ + --query 'properties.outputs' -o json); then + # Extract only the JSON portion (everything from first { to the end) + DEPLOYMENT_JSON=$(echo "$DEPLOYMENT_OUTPUTS" | sed -n '/{/,$ p') + echo "Bicep template [$MAIN_TEMPLATE] deployed successfully. Outputs:" + echo "$DEPLOYMENT_JSON" | jq . + APP_SERVICE_PLAN_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.appServicePlanName.value') + WEB_APP_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.webAppName.value') + ACR_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.acrName.value') + ACR_LOGIN_SERVER=$(echo "$DEPLOYMENT_JSON" | jq -r '.acrLoginServer.value') + MANAGED_IDENTITY_NAME=$(echo "$DEPLOYMENT_JSON" | jq -r '.managedIdentityName.value') + echo "Deployment complete." + echo "Resource Group: $RESOURCE_GROUP_NAME" + echo "App Service Plan: $APP_SERVICE_PLAN_NAME" + echo "Web App: $WEB_APP_NAME" + echo "Azure Container Registry: $ACR_NAME ($ACR_LOGIN_SERVER)" + echo "Managed Identity: $MANAGED_IDENTITY_NAME" +else + echo "Failed to deploy Bicep template [$MAIN_TEMPLATE]" + exit 1 +fi + +# Print the list of resources in the resource group +echo "Listing resources in resource group [$RESOURCE_GROUP_NAME]..." +az resource list --resource-group "$RESOURCE_GROUP_NAME" --output table \ No newline at end of file diff --git a/samples/web-app-custom-image/python/bicep/main.bicep b/samples/web-app-custom-image/python/bicep/main.bicep new file mode 100644 index 0000000..802b75c --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/main.bicep @@ -0,0 +1,305 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the prefix for the name of the Azure resources.') +@minLength(2) +param prefix string = take(uniqueString(resourceGroup().id), 4) + +@description('Specifies the suffix for the name of the Azure resources.') +@minLength(2) +param suffix string = take(uniqueString(resourceGroup().id), 4) + +@description('Specifies the location for all resources.') +param location string = resourceGroup().location + +@description('Specifies the name of the image to be used for the Web App.') +param imageName string + +@description('Specifies the tag of the image to be used for the Web App.') +param imageTag string + +@description('Specifies the tier name for the hosting plan.') +@allowed([ + 'Basic' + 'Standard' + 'ElasticPremium' + 'Premium' + 'PremiumV2' + 'Premium0V3' + 'PremiumV3' + 'PremiumMV3' + 'Isolated' + 'IsolatedV2' + 'WorkflowStandard' + 'FlexConsumption' +]) +param skuTier string = 'Standard' + +@description('Specifies the SKU name for the hosting plan.') +@allowed([ + 'B1' + 'B2' + 'B3' + 'S1' + 'S2' + 'S3' + 'EP1' + 'EP2' + 'EP3' + 'P1' + 'P2' + 'P3' + 'P1V2' + 'P2V2' + 'P3V2' + 'P0V3' + 'P1V3' + 'P2V3' + 'P3V3' + 'P1MV3' + 'P2MV3' + 'P3MV3' + 'P4MV3' + 'P5MV3' + 'I1' + 'I2' + 'I3' + 'I1V2' + 'I2V2' + 'I3V2' + 'I4V2' + 'I5V2' + 'I6V2' + 'WS1' + 'WS2' + 'WS3' + 'FC1' +]) +param skuName string = 'S1' + +@description('Specifies the kind of the hosting plan.') +@allowed([ + 'app' + 'elastic' + 'functionapp' + 'windows' + 'linux' +]) +param appServicePlanKind string = 'linux' + +@description('Specifies whether the hosting plan is reserved.') +param reserved bool = true + +@description('Specifies whether the hosting plan is zone redundant.') +param zoneRedundant bool = false + +@description('Specifies the kind of the hosting plan.') +@allowed([ + 'app' // Windows Web app + 'app,linux' // Linux Web app + 'app,linux,container' // Linux Container Web app + 'hyperV' // Windows Container Web App + 'app,container,windows' // Windows Container Web App + 'app,linux,kubernetes' // Linux Web App on ARC + 'app,linux,container,kubernetes' // Linux Container Web App on ARC + 'functionapp' // Function Code App + 'functionapp,linux' // Linux Consumption Function app + 'functionapp,linux,container,kubernetes' // Function Container App on ARC + 'functionapp,linux,kubernetes' // Function Code App on ARC +]) +param webAppKind string = 'app,linux' + +@description('Specifies whether HTTPS is enforced for the Azure Web App.') +param httpsOnly bool = false + +@description('Specifies the minimum TLS version for the Azure Web App.') +@allowed([ + '1.2' + '1.3' +]) +param minTlsVersion string = '1.2' + +@description('Specifies whether the public network access is enabled or disabled') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Specifies the optional Git Repo URL.') +param repoUrl string = ' ' + +@description('Specifies the name of the virtual network.') +param virtualNetworkName string = '' + +@description('Specifies the address prefixes of the virtual network.') +param virtualNetworkAddressPrefixes string = '10.0.0.0/8' + +@description('Specifies the name of the subnet used by the Web App for the regional virtual network integration.') +param webAppSubnetName string = 'app-subnet' + +@description('Specifies the address prefix of the subnet used by the Web App for the regional virtual network integration.') +param webAppSubnetAddressPrefix string = '10.0.0.0/24' + +@description('Specifies the name of the network security group associated to the subnet hosting the Web App.') +param webAppSubnetNsgName string = '' + +@description('Specifies the name of the subnet which contains the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetName string = 'pe-subnet' + +@description('Specifies the address prefix of the subnet which contains the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetAddressPrefix string = '10.0.1.0/24' + +@description('Specifies the name of the network security group associated to the subnet hosting the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetNsgName string = '' + +@description('Specifies the length of the Public IP Prefix.') +@minValue(28) +@maxValue(32) +param natGatewayPublicIpPrefixLength int = 31 + +@description('Specifies the name of the Azure NAT Gateway.') +param natGatewayName string = '' + +@description('Specifies a list of availability zones denoting the zone in which Nat Gateway should be deployed.') +param natGatewayZones array = [] + +@description('Specifies the idle timeout in minutes for the Azure NAT Gateway.') +param natGatewayIdleTimeoutMins int = 30 + +@description('Specifies the name of the Azure Container Registry resource.') +param acrName string = '' + +@description('Specifies the name of the Azure Log Analytics resource.') +param logAnalyticsWorkspaceName string = '' + +@description('Specifies the tags to be applied to the resources.') +param tags object = { + environment: 'test' + iac: 'bicep' +} + +//******************************************** +// Variables +//******************************************** +var webAppName = '${prefix}-webapp-${suffix}' +var appServicePlanName = '${prefix}-app-service-plan-${suffix}' +var managedIdentityName = '${prefix}-identity-${suffix}' +var privateDnsZoneName = 'privatelink.azurecr.io' +var privateEndpointName = '${prefix}-acr-pe-${suffix}' + +//******************************************** +// Modules and Resources +//******************************************** +resource workspace 'Microsoft.OperationalInsights/workspaces@2025-07-01' existing = { + name: logAnalyticsWorkspaceName == '' ? toLower('${prefix}-log-analytics-${suffix}') : logAnalyticsWorkspaceName +} +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2024-11-01-preview' existing = { + name: acrName == '' ? toLower('${prefix}acr${suffix}') : acrName +} + +module managedIdentity 'modules/managed-identity.bicep' = { + name: 'managedIdentity' + params: { + // properties + name: managedIdentityName + containerRegistryName: containerRegistry.name + location: location + tags: tags + } +} + +module network 'modules/virtual-network.bicep' = { + name: 'network' + params: { + virtualNetworkName: empty(virtualNetworkName) ? toLower('${prefix}-vnet-${suffix}') : virtualNetworkName + virtualNetworkAddressPrefixes: virtualNetworkAddressPrefixes + webAppSubnetName: webAppSubnetName + webAppSubnetAddressPrefix: webAppSubnetAddressPrefix + webAppSubnetNsgName: empty(webAppSubnetNsgName) ? toLower('${prefix}-webapp-subnet-nsg-${suffix}') : webAppSubnetNsgName + peSubnetName: peSubnetName + peSubnetAddressPrefix: peSubnetAddressPrefix + peSubnetNsgName: empty(peSubnetNsgName) ? toLower('${prefix}-pe-subnet-nsg-${suffix}') : peSubnetNsgName + natGatewayName: empty(natGatewayName) ? toLower('${prefix}-nat-gateway-${suffix}') : natGatewayName + natGatewayZones: natGatewayZones + natGatewayPublicIpPrefixName: toLower('${prefix}-nat-gateway-pip-prefix-${suffix}') + natGatewayPublicIpPrefixLength: natGatewayPublicIpPrefixLength + natGatewayIdleTimeoutMins: natGatewayIdleTimeoutMins + delegationServiceName: skuTier == 'FlexConsumption' ? 'Microsoft.App/environments' : 'Microsoft.Web/serverfarms' + workspaceId: workspace.id + location: location + tags: tags + } +} + +module privateDnsZone 'modules/private-dns-zone.bicep' = { + name: 'privateDnsZone' + params: { + name: privateDnsZoneName + vnetId: network.outputs.virtualNetworkId + tags: tags + } +} + +module privateEndpoints 'modules/private-endpoint.bicep' = { + name: 'privateEndpoints' + params: { + name: privateEndpointName + privateLinkServiceId: containerRegistry.id + privateDnsZoneId: privateDnsZone.outputs.id + vnetId: network.outputs.virtualNetworkId + subnetId: network.outputs.peSubnetId + groupIds: [ + 'registry' + ] + location: location + tags: tags + } +} + +module appServicePlan 'modules/app-service-plan.bicep' = { + name: 'appServicePlan' + params: { + name: appServicePlanName + location: location + skuName: skuName + skuTier: skuTier + kind: appServicePlanKind + reserved: reserved + zoneRedundant: zoneRedundant + workspaceId: workspace.id + tags: tags + } +} + +module webApp 'modules/web-app.bicep' = { + name: webAppName + params: { + name: webAppName + location: location + kind: webAppKind + httpsOnly: httpsOnly + minTlsVersion: minTlsVersion + publicNetworkAccess: publicNetworkAccess + repoUrl: repoUrl + virtualNetworkName: network.outputs.virtualNetworkName + subnetName: network.outputs.webAppSubnetName + hostingPlanName: appServicePlan.outputs.name + loginServer: containerRegistry.properties.loginServer + imageName: imageName + imageTag: imageTag + managedIdentityName: managedIdentity.outputs.name + managedIdentityType: 'UserAssigned' + workspaceId: workspace.id + tags: tags + } +} + +//******************************************** +// Outputs +//******************************************** +output appServicePlanName string = appServicePlan.outputs.name +output webAppName string = webApp.outputs.name +output acrName string = containerRegistry.name +output acrLoginServer string = containerRegistry.properties.loginServer +output managedIdentityName string = managedIdentity.outputs.name diff --git a/samples/web-app-custom-image/python/bicep/main.bicepparam b/samples/web-app-custom-image/python/bicep/main.bicepparam new file mode 100644 index 0000000..0bfd022 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/main.bicepparam @@ -0,0 +1,10 @@ +using 'main.bicep' + +param prefix = 'local' +param suffix = 'test' +param imageName = 'custom-image-webapp' +param imageTag = 'v1' +param tags = { + environment: 'test' + project: 'custom-image-webapp' +} diff --git a/samples/web-app-custom-image/python/bicep/modules/app-service-plan.bicep b/samples/web-app-custom-image/python/bicep/modules/app-service-plan.bicep new file mode 100644 index 0000000..4b5cfb3 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/app-service-plan.bicep @@ -0,0 +1,154 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the name of the App Service Plan.') +param name string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the tier name for the hosting plan.') +@allowed([ + 'Basic' + 'Standard' + 'ElasticPremium' + 'Premium' + 'PremiumV2' + 'Premium0V3' + 'PremiumV3' + 'PremiumMV3' + 'Isolated' + 'IsolatedV2' + 'WorkflowStandard' + 'FlexConsumption' +]) +param skuTier string = 'Standard' + +@description('Specifies the SKU name for the hosting plan.') +@allowed([ + 'B1' + 'B2' + 'B3' + 'S1' + 'S2' + 'S3' + 'EP1' + 'EP2' + 'EP3' + 'P1' + 'P2' + 'P3' + 'P1V2' + 'P2V2' + 'P3V2' + 'P0V3' + 'P1V3' + 'P2V3' + 'P3V3' + 'P1MV3' + 'P2MV3' + 'P3MV3' + 'P4MV3' + 'P5MV3' + 'I1' + 'I2' + 'I3' + 'I1V2' + 'I2V2' + 'I3V2' + 'I4V2' + 'I5V2' + 'I6V2' + 'WS1' + 'WS2' + 'WS3' + 'FC1' +]) +param skuName string = 'S1' + +@description('Specifies the kind of the hosting plan.') +@allowed([ + 'app' + 'elastic' + 'functionapp' + 'windows' + 'linux' +]) +param kind string = 'linux' + +@description('Specifies whether the hosting plan is reserved.') +param reserved bool = true + +@description('Specifies whether the hosting plan is zone redundant.') +param zoneRedundant bool = false + +@description('Specifies the resource id of the Log Analytics workspace.') +param workspaceId string + +@description('Specifies the tags to be applied to the resources.') +param tags object = {} + +//******************************************** +// Variables +//******************************************** + +var diagnosticSettingsName = 'default' +var logCategories = [] +var metricCategories = [ + 'AllMetrics' +] +var logs = [ + for category in logCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] +var metrics = [ + for category in metricCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] + +//******************************************** +// Resources +//******************************************** +resource appServicePlan 'Microsoft.Web/serverfarms@2024-11-01' = { + name: name + location: location + tags: tags + kind: kind + sku: { + tier: skuTier + name: skuName + } + properties: { + reserved: reserved + zoneRedundant: zoneRedundant + maximumElasticWorkerCount: skuTier == 'FlexConsumption' ? 1 : 20 + } +} + +resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if(!empty(workspaceId)) { + name: diagnosticSettingsName + scope: appServicePlan + properties: { + workspaceId: workspaceId + logs: logs + metrics: metrics + } +} + +//******************************************** +// Outputs +//******************************************** +output id string = appServicePlan.id +output name string = appServicePlan.name diff --git a/samples/web-app-custom-image/python/bicep/modules/container-registry.bicep b/samples/web-app-custom-image/python/bicep/modules/container-registry.bicep new file mode 100644 index 0000000..e830e39 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/container-registry.bicep @@ -0,0 +1,135 @@ + +//******************************************** +// Parameters +//******************************************** + +@description('Name of your Azure Container Registry') +@minLength(5) +@maxLength(50) +param name string = 'acr${uniqueString(resourceGroup().id)}' + +@description('Enable admin user that have push / pull permission to the registry.') +param adminUserEnabled bool = true + +@description('Specifies whether to allow public network access for the container registry.') +@allowed([ + 'Disabled' + 'Enabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Tier of your Azure Container Registry.') +@allowed([ + 'Basic' + 'Standard' + 'Premium' +]) +param sku string = 'Premium' + +@description('Specifies whether or not registry-wide pull is enabled from unauthenticated clients.') +param anonymousPullEnabled bool = true + +@description('Specifies whether or not a single data endpoint is enabled per region for serving data.') +param dataEndpointEnabled bool = true + +@description('Specifies the network rule set for the container registry.') +param networkRuleSet object = { + defaultAction: 'Allow' +} + +@description('Specifies ehether to allow trusted Azure services to access a network restricted registry.') +@allowed([ + 'AzureServices' + 'None' +]) +param networkRuleBypassOptions string = 'AzureServices' + +@description('Specifies whether or not zone redundancy is enabled for this container registry.') +@allowed([ + 'Disabled' + 'Enabled' +]) +param zoneRedundancy string = 'Disabled' + +@description('Specifies the resource id of the Log Analytics workspace.') +param workspaceId string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Variables +//******************************************** + +var diagnosticSettingsName = 'diagnosticSettings' +var logCategories = [ + 'ContainerRegistryRepositoryEvents' + 'ContainerRegistryLoginEvents' +] +var metricCategories = [ + 'AllMetrics' +] +var logs = [ + for category in logCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] +var metrics = [ + for category in metricCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] + +//******************************************** +// Resources +//******************************************** + +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2024-11-01-preview' = { + name: name + location: location + tags: tags + sku: { + name: sku + } + properties: { + adminUserEnabled: adminUserEnabled + anonymousPullEnabled: anonymousPullEnabled + dataEndpointEnabled: dataEndpointEnabled + networkRuleBypassOptions: networkRuleBypassOptions + networkRuleSet: networkRuleSet + publicNetworkAccess: publicNetworkAccess + zoneRedundancy: zoneRedundancy + } +} + +resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = { + name: diagnosticSettingsName + scope: containerRegistry + properties: { + workspaceId: workspaceId + logs: logs + metrics: metrics + } +} + +//******************************************** +// Outputs +//******************************************** + +output id string = containerRegistry.id +output name string = containerRegistry.name +output sku string = containerRegistry.sku.name +output loginServer string = containerRegistry.properties.loginServer diff --git a/samples/web-app-custom-image/python/bicep/modules/log-analytics.bicep b/samples/web-app-custom-image/python/bicep/modules/log-analytics.bicep new file mode 100644 index 0000000..2618829 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/log-analytics.bicep @@ -0,0 +1,45 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the name of the Log Analytics workspace.') +param name string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the service tier of the workspace: Free, Standalone, PerNode, Per-GB.') +@allowed([ + 'Free' + 'Standalone' + 'PerNode' + 'PerGB2018' +]) +param sku string = 'PerNode' + +@description('Specifies the workspace data retention in days. -1 means Unlimited retention for the Unlimited Sku. 730 days is the maximum allowed for all other Skus.') +param retentionInDays int = 60 + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Resources +//******************************************** +resource workspace 'Microsoft.OperationalInsights/workspaces@2025-07-01' = { + name: name + tags: tags + location: location + properties: { + sku: { + name: sku + } + retentionInDays: retentionInDays + } +} + +//******************************************** +// Outputs +//******************************************** +output id string = workspace.id +output name string = workspace.name +output customerId string = workspace.properties.customerId diff --git a/samples/web-app-custom-image/python/bicep/modules/managed-identity.bicep b/samples/web-app-custom-image/python/bicep/modules/managed-identity.bicep new file mode 100644 index 0000000..656f1a4 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/managed-identity.bicep @@ -0,0 +1,54 @@ +//******************************************** +// Parameters +//******************************************** + +@description('Specifies the name of the user-defined managed identity.') +param name string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the name of the Azure Container Registry.') +param containerRegistryName string + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Resources +//******************************************** + + +resource containerRegistry 'Microsoft.ContainerRegistry/registries@2025-06-01-preview' existing = { + name: containerRegistryName +} + +resource acrPullRoleDefinition 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = { + name: '7f951dda-4ed3-4680-a7ca-43fe172d538d' + scope: subscription() +} + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' = { + name: name + location: location + tags: tags +} + +resource acrPullRoleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = { + name: guid(containerRegistry.id, managedIdentity.id, acrPullRoleDefinition.id) + scope: containerRegistry + properties: { + roleDefinitionId: acrPullRoleDefinition.id + principalId: managedIdentity.properties.principalId + principalType: 'ServicePrincipal' + } +} + +//******************************************** +// Outputs +//******************************************** + +output id string = managedIdentity.id +output name string = managedIdentity.name +output clientId string = managedIdentity.properties.clientId +output principalId string = managedIdentity.properties.principalId diff --git a/samples/web-app-custom-image/python/bicep/modules/private-dns-zone.bicep b/samples/web-app-custom-image/python/bicep/modules/private-dns-zone.bicep new file mode 100644 index 0000000..d849259 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/private-dns-zone.bicep @@ -0,0 +1,41 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the name of the private DNS zone.') +param name string + +@description('Specifies the resource ID of the virtual network where private endpoints will be created.') +param vnetId string + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Resources +//******************************************** + +// Private DNS Zones +resource privateDnsZone 'Microsoft.Network/privateDnsZones@2024-06-01' = { + name: name + location: 'global' + tags: tags +} + +// Virtual Network Links +resource privateDnsZoneVirtualNetworkLink 'Microsoft.Network/privateDnsZones/virtualNetworkLinks@2024-06-01' = { + parent: privateDnsZone + name: 'link-to-vnet' + location: 'global' + properties: { + registrationEnabled: false + virtualNetwork: { + id: vnetId + } + } +} + +//******************************************** +// Outputs +//******************************************** +output id string = privateDnsZone.id +output name string = privateDnsZone.name diff --git a/samples/web-app-custom-image/python/bicep/modules/private-endpoint.bicep b/samples/web-app-custom-image/python/bicep/modules/private-endpoint.bicep new file mode 100644 index 0000000..8fd35b8 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/private-endpoint.bicep @@ -0,0 +1,72 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the name of the private endpoint.') +param name string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the resource ID of the virtual network where private endpoints will be created.') +param vnetId string + +@description('Specifies the resource ID of the subnet where private endpoints will be created.') +param subnetId string + +@description('Specifies the group IDs for the private link service connection.') +param groupIds array + +@description('Specifies the resource ID of the target resource.') +param privateLinkServiceId string + +@description('Specifies the resource ID of the private DNS zone.') +param privateDnsZoneId string + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Resources +//******************************************** + +// Private Endpoints +resource privateEndpoint 'Microsoft.Network/privateEndpoints@2025-05-01' = { + name: name + location: location + tags: tags + properties: { + privateLinkServiceConnections: [ + { + name: '${name}-pls-connection' + properties: { + privateLinkServiceId: privateLinkServiceId + groupIds: groupIds + } + } + ] + subnet: { + id: subnetId + } + } +} + +resource privateDnsZoneGroupName 'Microsoft.Network/privateEndpoints/privateDnsZoneGroups@2025-05-01' = { + parent: privateEndpoint + name: 'private-dns-zone-group' + properties: { + privateDnsZoneConfigs: [ + { + name: 'dnsConfig' + properties: { + privateDnsZoneId: privateDnsZoneId + } + } + ] + } +} + +//******************************************** +// Outputs +//******************************************** +output id string = privateEndpoint.id +output name string = privateEndpoint.name diff --git a/samples/web-app-custom-image/python/bicep/modules/virtual-network.bicep b/samples/web-app-custom-image/python/bicep/modules/virtual-network.bicep new file mode 100644 index 0000000..1c7a088 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/virtual-network.bicep @@ -0,0 +1,239 @@ +//******************************************** +// Parameters +//******************************************** +@description('Specifies the name of the virtual network.') +param virtualNetworkName string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the address prefixes of the virtual network.') +param virtualNetworkAddressPrefixes string = '10.0.0.0/8' + +@description('Specifies the name of the subnet used by the Web App for the regional virtual network integration.') +param webAppSubnetName string = 'functionAppSubnet' + +@description('Specifies the address prefix of the subnet used by the Web App for the regional virtual network integration.') +param webAppSubnetAddressPrefix string = '10.0.0.0/24' + +@description('Specifies the name of the network security group associated to the subnet hosting the Web App.') +param webAppSubnetNsgName string = '' + +@description('Specifies the name of the subnet which contains the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetName string = 'pe-subnet' + +@description('Specifies the address prefix of the subnet which contains the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetAddressPrefix string = '10.0.1.0/24' + +@description('Specifies the name of the network security group associated to the subnet hosting the private endpoint to the Azure CosmosDB for MongoDB API account.') +param peSubnetNsgName string = '' + +@description('Specifies the name of the Azure NAT Gateway.') +param natGatewayName string + +@description('Specifies a list of availability zones denoting the zone in which Nat Gateway should be deployed.') +param natGatewayZones array = [] + +@description('Specifies the name of the public IP prefix for the Azure NAT Gateway.') +param natGatewayPublicIpPrefixName string + +@description('Specifies the length of the Public IP Prefix.') +@minValue(28) +@maxValue(32) +param natGatewayPublicIpPrefixLength int = 31 + +@description('Specifies the idle timeout in minutes for the Azure NAT Gateway.') +param natGatewayIdleTimeoutMins int = 30 + +@description('Specifies the delegation service name.') +param delegationServiceName string + +@description('Specifies the resource id of the Log Analytics workspace.') +param workspaceId string + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Variables +//******************************************** +var diagnosticSettingsName = 'default' +var nsgLogCategories = [ + 'NetworkSecurityGroupEvent' + 'NetworkSecurityGroupRuleCounter' +] +var nsgLogs = [for category in nsgLogCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } +}] +var vnetLogCategories = [ + 'VMProtectionAlerts' +] +var vnetMetricCategories = [ + 'AllMetrics' +] +var vnetLogs = [for category in vnetLogCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } +}] +var vnetMetrics = [for category in vnetMetricCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } +}] + +//******************************************** +// Resources +//******************************************** + +// Virtual Network +resource vnet 'Microsoft.Network/virtualNetworks@2024-03-01' = { + name: virtualNetworkName + location: location + tags: tags + properties: { + addressSpace: { + addressPrefixes: [ + virtualNetworkAddressPrefixes + ] + } + subnets: [ + { + name: webAppSubnetName + properties: { + addressPrefix: webAppSubnetAddressPrefix + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Disabled' + networkSecurityGroup: { + id: webAppSubnetNsg.id + } + natGateway: { + id: natGateway.id + } + delegations: [ + { + name: 'delegation' + properties: { + serviceName: delegationServiceName + } + } + ] + } + } + { + name: peSubnetName + properties: { + addressPrefix: peSubnetAddressPrefix + networkSecurityGroup: { + id: peSubnetNsg.id + } + privateEndpointNetworkPolicies: 'Disabled' + privateLinkServiceNetworkPolicies: 'Disabled' + natGateway: { + id: natGateway.id + } + } + } + ] + } +} + +resource webAppSubnetNsg 'Microsoft.Network/networkSecurityGroups@2025-05-01' = { + name: webAppSubnetNsgName + location: location + tags: tags + properties: { + securityRules: [ + ] + } +} + +resource peSubnetNsg 'Microsoft.Network/networkSecurityGroups@2025-05-01' = { + name: peSubnetNsgName + location: location + tags: tags + properties: { + securityRules: [ + ] + } +} + +// NAT Gateway +resource natGatewayPublicIpPrefix 'Microsoft.Network/publicIPPrefixes@2025-05-01' = { + name: natGatewayPublicIpPrefixName + location: location + sku: { + name: 'Standard' + } + zones: !empty(natGatewayZones) ? natGatewayZones : [] + properties: { + publicIPAddressVersion: 'IPv4' + prefixLength: natGatewayPublicIpPrefixLength + } +} + +resource natGateway 'Microsoft.Network/natGateways@2025-05-01' = { + name: natGatewayName + location: location + sku: { + name: 'Standard' + } + zones: !empty(natGatewayZones) ? natGatewayZones : [] + properties: { + publicIpPrefixes: [ + { + id: natGatewayPublicIpPrefix.id + } + ] + idleTimeoutInMinutes: natGatewayIdleTimeoutMins + } +} + +resource peSubnetNsgDiagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { + name: diagnosticSettingsName + scope: peSubnetNsg + properties: { + workspaceId: workspaceId + logs: nsgLogs + } +} + +resource webAppSubnetNsgDiagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { + name: diagnosticSettingsName + scope: webAppSubnetNsg + properties: { + workspaceId: workspaceId + logs: nsgLogs + } +} + +resource vnetDiagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if (!empty(workspaceId)) { + name: diagnosticSettingsName + scope: vnet + properties: { + workspaceId: workspaceId + logs: vnetLogs + metrics: vnetMetrics + } +} + +//******************************************** +// Outputs +//******************************************** +output virtualNetworkId string = vnet.id +output virtualNetworkName string = vnet.name +output webAppSubnetId string = resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, webAppSubnetName) +output webAppSubnetName string = webAppSubnetName +output peSubnetId string = resourceId('Microsoft.Network/virtualNetworks/subnets', vnet.name, peSubnetName) +output peSubnetName string = peSubnetName diff --git a/samples/web-app-custom-image/python/bicep/modules/web-app.bicep b/samples/web-app-custom-image/python/bicep/modules/web-app.bicep new file mode 100644 index 0000000..a51c307 --- /dev/null +++ b/samples/web-app-custom-image/python/bicep/modules/web-app.bicep @@ -0,0 +1,210 @@ +//******************************************** +// Parameters +//******************************************** + +@description('Specifies a globally unique name the Azure Web App.') +param name string + +@description('Specifies the location.') +param location string = resourceGroup().location + +@description('Specifies the kind of the hosting plan.') +@allowed([ + 'app' // Windows Web app + 'app,linux' // Linux Web app + 'app,linux,container' // Linux Container Web app + 'hyperV' // Windows Container Web App + 'app,container,windows' // Windows Container Web App + 'app,linux,kubernetes' // Linux Web App on ARC + 'app,linux,container,kubernetes' // Linux Container Web App on ARC + 'functionapp' // Function Code App + 'functionapp,linux' // Linux Consumption Function app + 'functionapp,linux,container,kubernetes' // Function Container App on ARC + 'functionapp,linux,kubernetes' // Function Code App on ARC +]) +param kind string = 'app,linux' + +@description('Specifies the minimum TLS version for the Azure Web App.') +@allowed([ + '1.2' + '1.3' +]) +param minTlsVersion string = '1.2' + +@description('Specifies whether the public network access is enabled or disabled') +@allowed([ + 'Enabled' + 'Disabled' +]) +param publicNetworkAccess string = 'Enabled' + +@description('Specifies whether HTTPS is enforced for the Azure Web App.') +param httpsOnly bool = true + +@description('Specifies the name of the hosting plan.') +param hostingPlanName string + +@description('Specifies the name of the virtual network.') +param virtualNetworkName string + +@description('Specifies the name of the subnet used by Azure Functions for the regional virtual network integration.') +param subnetName string + +@description('Specifies the resource id of the Log Analytics workspace.') +param workspaceId string + +@description('Specifies the login server of the Azure Container Registry.') +param loginServer string + +@description('Specifies the name of the image to be used for the Web App.') +param imageName string + +@description('Specifies the tag of the image to be used for the Web App.') +param imageTag string + +@description('Specifies the type of the managed identity to be used by the Web App.') +@allowed([ + 'SystemAssigned' + 'UserAssigned' +]) +param managedIdentityType string = 'SystemAssigned' + +@description('Specifies the name of the managed identity to be used by the Web App if user assigned identity is selected.') +param managedIdentityName string = '' + +@description('Specifies the optional Git Repo URL.') +param repoUrl string = ' ' + +@description('Specifies the resource tags.') +param tags object + +//******************************************** +// Variables +//******************************************** + +// Generates a unique container name for deployments. +var diagnosticSettingsName = 'default' +var logCategories = [ + 'AppServiceHTTPLogs' + 'AppServiceConsoleLogs' + 'AppServiceAppLogs' + 'AppServiceAuditLogs' + 'AppServiceIPSecAuditLogs' + 'AppServicePlatformLogs' + 'AppServiceAuthenticationLogs' +] +var metricCategories = [ + 'AllMetrics' +] +var logs = [ + for category in logCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] +var metrics = [ + for category in metricCategories: { + category: category + enabled: true + retentionPolicy: { + enabled: true + days: 0 + } + } +] + +//******************************************** +// Resources +//******************************************** + +resource managedIdentity 'Microsoft.ManagedIdentity/userAssignedIdentities@2025-01-31-preview' existing = { + name: managedIdentityName +} + +resource virtualNetwork 'Microsoft.Network/virtualNetworks@2024-05-01' existing = { + name: virtualNetworkName +} + +resource subnet 'Microsoft.Network/virtualNetworks/subnets@2024-05-01' existing = { + parent: virtualNetwork + name: subnetName +} + +resource hostingPlan 'Microsoft.Web/serverfarms@2024-04-01' existing = { + name: hostingPlanName +} + +resource webApp 'Microsoft.Web/sites@2025-03-01' = { + name: name + location: location + tags: tags + kind: kind + properties: { + httpsOnly: httpsOnly + serverFarmId: hostingPlan.id + virtualNetworkSubnetId: subnet.id + outboundVnetRouting: { + allTraffic: true + applicationTraffic: true + contentShareTraffic: true + imagePullTraffic: true + backupRestoreTraffic: true + } + siteConfig: { + acrUseManagedIdentityCreds: true + acrUserManagedIdentityID: managedIdentity.properties.clientId + linuxFxVersion: 'DOCKER|${loginServer}/${imageName}:${imageTag}' + minTlsVersion: minTlsVersion + publicNetworkAccess: publicNetworkAccess + } + } + identity: { + type: managedIdentityType + userAssignedIdentities : managedIdentityType == 'SystemAssigned' ? null : { + '${managedIdentity.id}': {} + } + } +} + +resource configAppSettings 'Microsoft.Web/sites/config@2024-11-01' = { + parent: webApp + name: 'appsettings' + properties: { + SCM_DO_BUILD_DURING_DEPLOYMENT: 'true' + ENABLE_ORYX_BUILD: 'true' + WEBSITES_PORT: '80' + APP_NAME: 'Custom Image' + IMAGE_NAME: '${loginServer}/${imageName}:${imageTag}' + } +} + +resource webAppSourceControl 'Microsoft.Web/sites/sourcecontrols@2024-11-01' = if (contains(repoUrl,'http')){ + name: 'web' + parent: webApp + properties: { + repoUrl: repoUrl + branch: 'master' + isManualIntegration: true + } +} + +resource diagnosticSettings 'Microsoft.Insights/diagnosticSettings@2021-05-01-preview' = if(!empty(workspaceId)) { + name: diagnosticSettingsName + scope: webApp + properties: { + workspaceId: workspaceId + logs: logs + metrics: metrics + } +} + +//******************************************** +// Outputs +//******************************************** +output id string = webApp.id +output name string = webApp.name +output defaultHostName string = webApp.properties.defaultHostName diff --git a/samples/web-app-custom-image/python/images/architecture.png b/samples/web-app-custom-image/python/images/architecture.png new file mode 100644 index 0000000000000000000000000000000000000000..6ca0fe32580f44339177476ddbf38928c422703f GIT binary patch literal 121286 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

1y+&vpVeUx!!%3ch3OaM#4RN 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 literal 0 HcmV?d00001 diff --git a/samples/web-app-custom-image/python/scripts/README.md b/samples/web-app-custom-image/python/scripts/README.md index ca16963..7120446 100644 --- a/samples/web-app-custom-image/python/scripts/README.md +++ b/samples/web-app-custom-image/python/scripts/README.md @@ -1,33 +1,251 @@ -# Web App Custom Image Scripts +# Azure CLI Deployment -These scripts deploy and validate a Python Flask application running on Azure Web App for Containers. +This directory contains the Azure CLI scripts for provisioning Azure services in LocalStack for Azure. For further details about the sample application, refer to the [Azure Web App with Custom Docker Image](../README.md). -## Deploy +## Prerequisites + +Before deploying this solution, ensure you have the following tools installed: + +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing +- [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack and building the custom image +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface +- [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper +- [Python](https://www.python.org/downloads/): Python runtime (version 3.12 or above) +- [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs + +### Installing azlocal CLI + +The [deploy.sh](deploy.sh) Bash script uses the `azlocal` CLI instead of the standard Azure CLI to work with LocalStack. Install it using: + +```bash +pip install azlocal +``` + +For more information, see [Get started with the az tool on LocalStack](https://azure.localstack.cloud/user-guides/sdks/az/). + +## Architecture Overview + +The [deploy.sh](deploy.sh) script creates all Azure resources from scratch using the Azure CLI: + +1. [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-cli): A logical container scoping all resources in this sample. +2. [Azure Virtual Network](https://learn.microsoft.com/azure/virtual-network/virtual-networks-overview): Hosts two subnets: + - *app-subnet*: Dedicated to [regional VNet integration](https://learn.microsoft.com/azure/azure-functions/functions-networking-options?tabs=azure-portal#outbound-networking-features) with the Web App. + - *pe-subnet*: Used for hosting Azure Private Endpoints. +3. [Azure Private DNS Zone](https://learn.microsoft.com/azure/dns/private-dns-privatednszone): Handles DNS resolution for the Azure Container Registry Private Endpoint within the virtual network. +4. [Azure Private Endpoint](https://learn.microsoft.com/azure/private-link/private-endpoint-overview): Secures network access to the Azure Container Registry via a private IP within the VNet. +5. [Azure NAT Gateway](https://learn.microsoft.com/azure/nat-gateway/nat-overview): Provides deterministic outbound connectivity for the Web App. Included for completeness; the sample app does not call any external services. +6. [Azure Network Security Group](https://learn.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview): Enforces inbound and outbound traffic rules across the virtual network's subnets. +7. [Azure Log Analytics Workspace](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-overview): Centralizes diagnostic logs and metrics from all resources in the solution. +8. [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-intro): A fully-managed container registry service based on the open-source [Docker platform](https://docs.docker.com/get-started/docker-overview/) used to hold the container image used by the web app. +9. [User-Assigned Managed Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview): Assigned the [AcrPull](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull) role on the Azure Container Registry, enabling the Web App to pull the container image without storing credentials. +10. [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans): The underlying compute tier that hosts the web application. +11. [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview): Runs the Python Flask application from the custom container image stored in the Azure Container Registry. + +## Provisioning Scripts + +See [deploy.sh](deploy.sh) for the complete deployment automation. The script performs: + +- Creates resource group +- Deploys Azure Container Registry +- Builds container image locally and pushes it to ACR +- Deploys remaining Azure resources (VNet, NSG, NAT Gateway, DNS, Private Endpoint, App Service Plan, managed identity, Web App) +- Configures Web App to use the container image from ACR +- Assigns [AcrPull](https://learn.microsoft.com/en-us/azure/role-based-access-control/built-in-roles/containers#acrpull) role to the user-assigned managed identity + +## Deployment + +You can set up the Azure emulator by utilizing the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and specify it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the Azure Docker image, execute the following command: + +```bash +docker pull localstack/localstack-azure-alpha +``` + +Start the LocalStack Azure emulator using the localstack CLI, execute the following command: + +```bash +# Set the authentication token +export LOCALSTACK_AUTH_TOKEN= + +# Start the LocalStack Azure emulator +IMAGE_NAME=localstack/localstack-azure-alpha localstack start -d +localstack wait -t 60 + +# Route all Azure CLI calls to the LocalStack Azure emulator +azlocal start-interception +``` + +Navigate to the `scripts` folder: ```bash -bash scripts/deploy.sh +cd samples/web-app-custom-image/python/scripts ``` -The deployment script creates: +Make the script executable: -- Resource group -- Azure Container Registry with admin credentials enabled -- Custom Docker image built from `src/Dockerfile` -- Linux App Service Plan -- Web App configured to use the custom image +```bash +chmod +x deploy.sh +``` -If pushing to the emulated registry is unavailable in the current LocalStack environment, the script falls back to the local Docker image tag. +Run the deployment script: -## Validate +```bash +./deploy.sh +``` + +## Validation + +Once the deployment completes, run the [validate.sh](validate.sh) script to confirm that all resources were provisioned and configured as expected: ```bash -bash scripts/validate.sh +#!/bin/bash +set -euo pipefail + +PREFIX='local' +SUFFIX='test' +RESOURCE_GROUP_NAME="${PREFIX}-rg" +ACR_NAME="${PREFIX}acr${SUFFIX}" +MANAGED_IDENTITY_NAME="${PREFIX}-identity-${SUFFIX}" +APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" +VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" +PRIVATE_DNS_ZONE_NAME="privatelink.azurecr.io" +PRIVATE_ENDPOINT_NAME="${PREFIX}-acr-pe-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" +NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" +PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" +LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" + +# Check resource group +echo -e "[$RESOURCE_GROUP_NAME] resource group:\n" +az group show \ + --name "$RESOURCE_GROUP_NAME" \ + --output table + +# Check managed identity +echo -e "[$MANAGED_IDENTITY_NAME] managed identity:\n" +az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check App Service Plan +echo -e "\n[$APP_SERVICE_PLAN_NAME] App Service Plan:\n" +az appservice plan show \ + --name "$APP_SERVICE_PLAN_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Container Registry +echo -e "\n[$ACR_NAME] Azure Container Registry:\n" +az acr show \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Web App +echo -e "\n[$WEB_APP_NAME] Web App:\n" +az webapp show \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "{name:name, state:state, defaultHostName:defaultHostName, kind:kind}" \ + --output table + +# Check App Settings +echo -e "\n[$WEB_APP_NAME] app settings:\n" +az webapp config appsettings list \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[?name=='IMAGE_NAME' || name=='APP_NAME' || name=='WEBSITES_PORT']" \ + --output table + +# Check Virtual Network +echo -e "\n[$VIRTUAL_NETWORK_NAME] virtual network:\n" +az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private DNS Zone +echo -e "\n[$PRIVATE_DNS_ZONE_NAME] private dns zone:\n" +az network private-dns zone show \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query '{Name:name,ResourceGroup:resourceGroup,RecordSets:recordSets,VirtualNetworkLinks:virtualNetworkLinks}' \ + --output table \ + --only-show-errors + +# Check Private Endpoint +echo -e "\n[$PRIVATE_ENDPOINT_NAME] private endpoint:\n" +az network private-endpoint show \ + --name "$PRIVATE_ENDPOINT_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Web App Subnet NSG +echo -e "\n[$WEB_APP_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private Endpoint Subnet NSG +echo -e "\n[$PE_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check NAT Gateway +echo -e "\n[$NAT_GATEWAY_NAME] nat gateway:\n" +az network nat gateway show \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Public IP Prefix +echo -e "\n[$PIP_PREFIX_NAME] public ip prefix:\n" +az network public-ip prefix show \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Log Analytics Workspace +echo -e "\n[$LOG_ANALYTICS_NAME] log analytics workspace:\n" +az monitor log-analytics workspace show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --workspace-name "$LOG_ANALYTICS_NAME" \ + --query '{Name:name,Location:location,ResourceGroup:resourceGroup}' \ + --output table \ + --only-show-errors + +echo -e "\nResources in [$RESOURCE_GROUP_NAME]:\n" +az resource list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table ``` -## Call The Web App +## Cleanup + +To destroy all created resources: ```bash -bash scripts/call-web-app.sh +# Delete resource group and all contained resources +az group delete --name local-rg --yes --no-wait + +# Verify deletion +az group list --output table ``` -The call script first uses the LocalStack proxy endpoint and then, when available, calls the Docker host port mapped to the emulated Web App container. +This will remove all Azure resources created by the Azure CLI deployment script. + +## Related Documentation + +- [Azure CLI Documentation](https://learn.microsoft.com/en-us/cli/azure/) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) diff --git a/samples/web-app-custom-image/python/scripts/call-web-app.sh b/samples/web-app-custom-image/python/scripts/call-web-app.sh index 7747690..bff883f 100755 --- a/samples/web-app-custom-image/python/scripts/call-web-app.sh +++ b/samples/web-app-custom-image/python/scripts/call-web-app.sh @@ -3,8 +3,8 @@ set -euo pipefail PREFIX='local' SUFFIX='test' -RESOURCE_GROUP_NAME="${PREFIX}-custom-image-rg" -WEB_APP_NAME="${PREFIX}-custom-image-webapp-${SUFFIX}" +RESOURCE_GROUP_NAME="${PREFIX}-rg" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" get_docker_container_name_by_prefix() { local app_prefix="$1" diff --git a/samples/web-app-custom-image/python/scripts/deploy.sh b/samples/web-app-custom-image/python/scripts/deploy.sh index 9e16746..4ba852d 100755 --- a/samples/web-app-custom-image/python/scripts/deploy.sh +++ b/samples/web-app-custom-image/python/scripts/deploy.sh @@ -1,80 +1,1013 @@ #!/bin/bash -set -euo pipefail # Variables PREFIX='local' SUFFIX='test' LOCATION='westeurope' -RESOURCE_GROUP_NAME="${PREFIX}-custom-image-rg" -ACR_NAME="${PREFIX}customimageacr" -APP_SERVICE_PLAN_NAME="${PREFIX}-custom-image-plan-${SUFFIX}" -APP_SERVICE_PLAN_SKU="B1" -WEB_APP_NAME="${PREFIX}-custom-image-webapp-${SUFFIX}" +RESOURCE_GROUP_NAME="${PREFIX}-rg" +ACR_NAME="${PREFIX}acr${SUFFIX}" +ACR_SKU='Premium' +MANAGED_IDENTITY_NAME="${PREFIX}-identity-${SUFFIX}" +APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" +APP_SERVICE_PLAN_SKU="S1" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" IMAGE_NAME="custom-image-webapp" IMAGE_TAG="v1" +LOCAL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" +VIRTUAL_NETWORK_ADDRESS_PREFIX="10.0.0.0/8" +WEB_APP_SUBNET_NAME="app-subnet" +WEB_APP_SUBNET_PREFIX="10.0.0.0/24" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +PE_SUBNET_NAME="pe-subnet" +PE_SUBNET_PREFIX="10.0.1.0/24" +PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" +VIRTUAL_NETWORK_LINK_NAME="link-to-vnet" +PRIVATE_DNS_ZONE_NAME="privatelink.azurecr.io" +PRIVATE_ENDPOINT_NAME="${PREFIX}-acr-pe-${SUFFIX}" +PRIVATE_ENDPOINT_GROUP="registry" +PRIVATE_DNS_ZONE_GROUP_NAME="default" +NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" +PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" +LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" +DIAGNOSTIC_SETTINGS_NAME='default' CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)" +RETRY_COUNT=3 +SLEEP=5 cd "$CURRENT_DIR" || exit +# Create a resource group echo "Creating resource group [$RESOURCE_GROUP_NAME]..." az group create \ --name "$RESOURCE_GROUP_NAME" \ - --location "$LOCATION" + --location "$LOCATION" \ + --only-show-errors 1>/dev/null + +if [ $? -eq 0 ]; then + echo "Resource group [$RESOURCE_GROUP_NAME] created successfully." +else + echo "Failed to create resource group [$RESOURCE_GROUP_NAME]." + exit 1 +fi -echo "Creating Azure Container Registry [$ACR_NAME]..." -az acr create \ +# Check if the Azure Container Registry already exists +echo "Checking if [$ACR_NAME] Azure Container Registry already exists in the [$RESOURCE_GROUP_NAME] resource group..." +az acr show \ --name "$ACR_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ - --location "$LOCATION" \ - --sku Basic \ - --admin-enabled true + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$ACR_NAME] Azure Container Registry exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating Azure Container Registry [$ACR_NAME]..." + az acr create \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --sku "$ACR_SKU" \ + --admin-enabled true \ + --only-show-errors 1>/dev/null + + if [ $? -eq 0 ]; then + echo "Azure Container Registry [$ACR_NAME] created successfully." + else + echo "Failed to create Azure Container Registry [$ACR_NAME]." + exit 1 + fi +else + echo "[$ACR_NAME] Azure Container Registry already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Get the Azure Container Registry resource id +echo "Getting [$ACR_NAME] Azure Container Registry resource id in the [$RESOURCE_GROUP_NAME] resource group..." +ACR_ID=$(az acr show \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $ACR_ID ]]; then + echo "[$ACR_NAME] Azure Container Registry resource id retrieved successfully: $ACR_ID" +else + echo "Failed to retrieve [$ACR_NAME] Azure Container Registry resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +echo "Logging into Azure Container Registry [$ACR_NAME]..." +az acr login --name "$ACR_NAME" --only-show-errors -az acr login --name $ACR_NAME +if [ $? -eq 0 ]; then + echo "Logged into Azure Container Registry [$ACR_NAME] successfully." +else + echo "Failed to log into Azure Container Registry [$ACR_NAME]." + exit 1 +fi -LOGIN_SERVER=$(az acr show \ +echo "Getting login server for Azure Container Registry [$ACR_NAME]..." +ACR_LOGIN_SERVER=$(az acr show \ --name "$ACR_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query "loginServer" \ --output tsv \ --only-show-errors) -FULL_IMAGE="${LOGIN_SERVER}/${IMAGE_NAME}:${IMAGE_TAG}" -LOCAL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +if [ -n "$ACR_LOGIN_SERVER" ]; then + echo "Login server retrieved successfully: $ACR_LOGIN_SERVER" +else + echo "Failed to retrieve login server for Azure Container Registry [$ACR_NAME]." + exit 1 +fi + +# Create full image name with login server, image name, and tag +FULL_IMAGE="${ACR_LOGIN_SERVER}/${IMAGE_NAME}:${IMAGE_TAG}" echo "Building custom Docker image [$LOCAL_IMAGE]..." docker build -t "$LOCAL_IMAGE" ../src/ + +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] built successfully." +else + echo "Failed to build Docker image [$LOCAL_IMAGE]." + exit 1 +fi + +echo "Tagging Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]..." docker tag "$LOCAL_IMAGE" "$FULL_IMAGE" +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] tagged as [$FULL_IMAGE] successfully." +else + echo "Failed to tag Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]." + exit 1 +fi + echo "Pushing image [$FULL_IMAGE] to ACR..." docker push "$FULL_IMAGE" -WEBAPP_IMAGE="$FULL_IMAGE" +if [ $? -eq 0 ]; then + echo "Docker image [$FULL_IMAGE] pushed to ACR successfully." +else + echo "Failed to push Docker image [$FULL_IMAGE] to ACR." + exit 1 +fi + +# Check if the user-assigned managed identity already exists +echo "Checking if [$MANAGED_IDENTITY_NAME] user-assigned managed identity actually exists in the [$RESOURCE_GROUP_NAME] resource group..." + +az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$MANAGED_IDENTITY_NAME] user-assigned managed identity actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$MANAGED_IDENTITY_NAME] user-assigned managed identity in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the user-assigned managed identity + az identity create \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --subscription "$SUBSCRIPTION_ID" 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$MANAGED_IDENTITY_NAME] user-assigned managed identity successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$MANAGED_IDENTITY_NAME] user-assigned managed identity in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$MANAGED_IDENTITY_NAME] user-assigned managed identity already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Retrieve the principalId of the user-assigned managed identity +echo "Retrieving principalId for [$MANAGED_IDENTITY_NAME] managed identity..." +PRINCIPAL_ID=$(az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query principalId \ + --output tsv) + +if [[ -n $PRINCIPAL_ID ]]; then + echo "[$PRINCIPAL_ID] principalId for the [$MANAGED_IDENTITY_NAME] managed identity successfully retrieved" +else + echo "Failed to retrieve principalId for the [$MANAGED_IDENTITY_NAME] managed identity" + exit 1 +fi + +# Retrieve the clientId of the user-assigned managed identity +echo "Retrieving clientId for [$MANAGED_IDENTITY_NAME] managed identity..." +CLIENT_ID=$(az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query clientId \ + --output tsv) + +if [[ -n $CLIENT_ID ]]; then + echo "[$CLIENT_ID] clientId for the [$MANAGED_IDENTITY_NAME] managed identity successfully retrieved" +else + echo "Failed to retrieve clientId for the [$MANAGED_IDENTITY_NAME] managed identity" + exit 1 +fi + +# Retrieve the resource id of the user-assigned managed identity +echo "Retrieving resource id for the [$MANAGED_IDENTITY_NAME] managed identity..." +IDENTITY_ID=$(az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv) + +if [[ -n $IDENTITY_ID ]]; then + echo "Resource id for the [$MANAGED_IDENTITY_NAME] managed identity successfully retrieved" +else + echo "Failed to retrieve the resource id for the [$MANAGED_IDENTITY_NAME] managed identity" + exit 1 +fi + +# Assign the AcrPull role to the managed identity with the Azure Container Registry as scope +ROLE="AcrPull" +echo "Checking if the [$MANAGED_IDENTITY_NAME] managed identity has the [$ROLE] role assignment on Azure Container Registry [$ACR_NAME]..." +current=$(az role assignment list \ + --assignee "$PRINCIPAL_ID" \ + --scope "$ACR_ID" \ + --query "[?roleDefinitionName=='$ROLE'].roleDefinitionName" \ + --output tsv 2>/dev/null) + +if [[ $current == "$ROLE" ]]; then + echo "Managed identity [$MANAGED_IDENTITY_NAME] already has the [$ROLE] role assignment on Azure Container Registry [$ACR_NAME]" +else + echo "Managed identity [$MANAGED_IDENTITY_NAME] does not have the [$ROLE] role assignment on Azure Container Registry [$ACR_NAME]" + echo "Creating role assignment: assigning [$ROLE] role to managed identity [$MANAGED_IDENTITY_NAME] on Azure Container Registry [$ACR_NAME]..." + ATTEMPT=1 + while [ $ATTEMPT -le $RETRY_COUNT ]; do + echo "Attempt $ATTEMPT of $RETRY_COUNT to assign role..." + az role assignment create \ + --assignee "$PRINCIPAL_ID" \ + --role "$ROLE" \ + --scope "$ACR_ID" 1>/dev/null + + if [[ $? == 0 ]]; then + break + else + if [ $ATTEMPT -lt $RETRY_COUNT ]; then + echo "Role assignment failed. Waiting [$SLEEP] seconds before retry..." + sleep $SLEEP + fi + ATTEMPT=$((ATTEMPT + 1)) + fi + done + + if [[ $? == 0 ]]; then + echo "Successfully assigned [$ROLE] role to managed identity [$MANAGED_IDENTITY_NAME] on Azure Container Registry [$ACR_NAME]" + else + echo "Failed to assign [$ROLE] role to managed identity [$MANAGED_IDENTITY_NAME] on Azure Container Registry [$ACR_NAME]" + exit 1 + fi +fi + +# Check if the network security group for the web app subnet already exists +echo "Checking if [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet..." + + # Create the network security group for the web app subnet + az network nsg create \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --only-show-errors 1>/dev/null -echo "Creating Linux App Service Plan [$APP_SERVICE_PLAN_NAME]..." -az appservice plan create \ + if [[ $? == 0 ]]; then + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Get the resource id of the network security group for the web app subnet +echo "Getting [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group..." +WEB_APP_SUBNET_NSG_ID=$(az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $WEB_APP_SUBNET_NSG_ID ]]; then + echo "[$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id retrieved successfully: $WEB_APP_SUBNET_NSG_ID" +else + echo "Failed to retrieve [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Check if the network security group for the private endpoint subnet already exists +echo "Checking if [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet..." + + # Create the network security group for the private endpoint subnet + az network nsg create \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Get the resource id of the network security group for the private endpoint subnet +echo "Getting [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet resource id in the [$RESOURCE_GROUP_NAME] resource group..." +PE_SUBNET_NSG_ID=$(az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $PE_SUBNET_NSG_ID ]]; then + echo "[$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet resource id retrieved successfully: $PE_SUBNET_NSG_ID" +else + echo "Failed to retrieve [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Check if the public IP prefix for the NAT Gateway already exists +echo "Checking if [$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network public-ip prefix show \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the public IP prefix for the NAT Gateway + az network public-ip prefix create \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --length 31 \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$PIP_PREFIX_NAME] public IP prefix for the NAT Gateway already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check if the NAT Gateway already exists +echo "Checking if [$NAT_GATEWAY_NAME] NAT Gateway actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network nat gateway show \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$NAT_GATEWAY_NAME] NAT Gateway actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$NAT_GATEWAY_NAME] NAT Gateway in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the NAT Gateway + az network nat gateway create \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --public-ip-prefixes "$PIP_PREFIX_NAME" \ + --idle-timeout 4 \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$NAT_GATEWAY_NAME] NAT Gateway successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$NAT_GATEWAY_NAME] NAT Gateway in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$NAT_GATEWAY_NAME] NAT Gateway already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check if the virtual network already exists +echo "Checking if [$VIRTUAL_NETWORK_NAME] virtual network actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$VIRTUAL_NETWORK_NAME] virtual network actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$VIRTUAL_NETWORK_NAME] virtual network in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the virtual network + az network vnet create \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --address-prefixes "$VIRTUAL_NETWORK_ADDRESS_PREFIX" \ + --subnet-name "$WEB_APP_SUBNET_NAME" \ + --subnet-prefix "$WEB_APP_SUBNET_PREFIX" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$VIRTUAL_NETWORK_NAME] virtual network successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$VIRTUAL_NETWORK_NAME] virtual network in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi + + # Update the web app subnet to associate it with the NAT Gateway and the NSG + echo "Associating [$WEB_APP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group..." + az network vnet subnet update \ + --name "$WEB_APP_SUBNET_NAME" \ + --vnet-name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --nat-gateway "$NAT_GATEWAY_NAME" \ + --network-security-group "$WEB_APP_SUBNET_NSG_NAME" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$WEB_APP_SUBNET_NAME] subnet successfully associated with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group" + else + echo "Failed to associate [$WEB_APP_SUBNET_NAME] subnet with the [$NAT_GATEWAY_NAME] NAT Gateway and the [$WEB_APP_SUBNET_NSG_NAME] network security group" + exit 1 + fi +else + echo "[$VIRTUAL_NETWORK_NAME] virtual network already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check if the subnet already exists +echo "Checking if [$PE_SUBNET_NAME] subnet actually exists in the [$VIRTUAL_NETWORK_NAME] virtual network..." +az network vnet subnet show \ + --name "$PE_SUBNET_NAME" \ + --vnet-name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$PE_SUBNET_NAME] subnet actually exists in the [$VIRTUAL_NETWORK_NAME] virtual network" + echo "Creating [$PE_SUBNET_NAME] subnet in the [$VIRTUAL_NETWORK_NAME] virtual network..." + + # Create the subnet + az network vnet subnet create \ + --name "$PE_SUBNET_NAME" \ + --vnet-name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --address-prefix "$PE_SUBNET_PREFIX" \ + --network-security-group "$PE_SUBNET_NSG_NAME" \ + --private-endpoint-network-policies "Disabled" \ + --private-link-service-network-policies "Disabled" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$PE_SUBNET_NAME] subnet successfully created in the [$VIRTUAL_NETWORK_NAME] virtual network" + else + echo "Failed to create [$PE_SUBNET_NAME] subnet in the [$VIRTUAL_NETWORK_NAME] virtual network" + exit + fi +else + echo "[$PE_SUBNET_NAME] subnet already exists in the [$VIRTUAL_NETWORK_NAME] virtual network" +fi + +# Retrieve the virtual network resource id +echo "Getting [$VIRTUAL_NETWORK_NAME] virtual network resource id in the [$RESOURCE_GROUP_NAME] resource group..." +VIRTUAL_NETWORK_ID=$(az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $VIRTUAL_NETWORK_ID ]]; then + echo "[$VIRTUAL_NETWORK_NAME] virtual network resource id retrieved successfully: $VIRTUAL_NETWORK_ID" +else + echo "Failed to retrieve [$VIRTUAL_NETWORK_NAME] virtual network resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Check if the private DNS Zone already exists +echo "Checking if [$PRIVATE_DNS_ZONE_NAME] private DNS zone actually exists in the [$RESOURCE_GROUP_NAME] resource group..." +az network private-dns zone show \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$PRIVATE_DNS_ZONE_NAME] private DNS zone actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$PRIVATE_DNS_ZONE_NAME] private DNS zone in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the private DNS Zone + az network private-dns zone create \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$PRIVATE_DNS_ZONE_NAME] private DNS zone successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$PRIVATE_DNS_ZONE_NAME] private DNS zone in the [$RESOURCE_GROUP_NAME] resource group" + exit + fi +else + echo "[$PRIVATE_DNS_ZONE_NAME] private DNS zone already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check if the virtual network link between the private DNS zone and the virtual network already exists +echo "Checking if [$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network actually exists..." +az network private-dns link vnet show \ + --name "$VIRTUAL_NETWORK_LINK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --zone-name "$PRIVATE_DNS_ZONE_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network actually exists" + + echo "Creating [$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network..." + + # Create the virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network + az network private-dns link vnet create \ + --name "$VIRTUAL_NETWORK_LINK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --zone-name "$PRIVATE_DNS_ZONE_NAME" \ + --virtual-network "$VIRTUAL_NETWORK_ID" \ + --registration-enabled false \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network successfully created" + else + echo "Failed to create [$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network" + exit + fi +else + echo "[$VIRTUAL_NETWORK_LINK_NAME] virtual network link between [$PRIVATE_DNS_ZONE_NAME] private DNS zone and [$VIRTUAL_NETWORK_NAME] virtual network already exists" +fi + +# Check if the private endpoint already exists +echo "Checking if private endpoint [$PRIVATE_ENDPOINT_NAME] exists in the [$RESOURCE_GROUP_NAME] resource group..." +privateEndpointId=$(az network private-endpoint list \ + --resource-group $RESOURCE_GROUP_NAME \ + --only-show-errors \ + --query "[?name=='$PRIVATE_ENDPOINT_NAME'].id" \ + --output tsv) + +if [[ -z $privateEndpointId ]]; then + echo "Private endpoint [$PRIVATE_ENDPOINT_NAME] does not exist in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$PRIVATE_ENDPOINT_NAME] private endpoint for the [$ACR_NAME] Azure Container Registry in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create a private endpoint for the Azure Container Registry + az network private-endpoint create \ + --name "$PRIVATE_ENDPOINT_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --vnet-name "$VIRTUAL_NETWORK_NAME" \ + --subnet "$PE_SUBNET_NAME" \ + --private-connection-resource-id "$ACR_ID" \ + --group-id "$PRIVATE_ENDPOINT_GROUP" \ + --connection-name "acr-connection" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "Private endpoint [$PRIVATE_ENDPOINT_NAME] successfully created for the [$ACR_NAME] Azure Container Registry in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create a private endpoint for the [$ACR_NAME] Azure Container Registry in the [$RESOURCE_GROUP_NAME] resource group" + exit + fi +else + echo "Private endpoint [$PRIVATE_ENDPOINT_NAME] already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check if the private DNS zone group is already created for the Azure Container Registry private endpoint +echo "Checking if the private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint already exists..." +NAME=$(az network private-endpoint dns-zone-group show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --endpoint-name "$PRIVATE_ENDPOINT_NAME" \ + --name "$PRIVATE_DNS_ZONE_GROUP_NAME" \ + --query name \ + --output tsv \ + --only-show-errors) + +if [[ -z $NAME ]]; then + echo "No private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint actually exists" + echo "Creating private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint..." + + # Create the private DNS zone group for the Azure Container Registry private endpoint + az network private-endpoint dns-zone-group create \ + --name "$PRIVATE_DNS_ZONE_GROUP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --endpoint-name "$PRIVATE_ENDPOINT_NAME" \ + --private-dns-zone "$PRIVATE_DNS_ZONE_NAME" \ + --zone-name "$PRIVATE_DNS_ZONE_NAME" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "Private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint successfully created" + else + echo "Failed to create private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint" + exit + fi +else + echo "Private DNS zone group [$PRIVATE_DNS_ZONE_GROUP_NAME] for the [$PRIVATE_ENDPOINT_NAME] private endpoint already exists" +fi + +# Check if the App Service Plan already exists +echo "Checking if [$APP_SERVICE_PLAN_NAME] App Service Plan already exists in the [$RESOURCE_GROUP_NAME] resource group..." +az appservice plan show \ --name "$APP_SERVICE_PLAN_NAME" \ - --location "$LOCATION" \ - --sku "$APP_SERVICE_PLAN_SKU" \ - --is-linux + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$APP_SERVICE_PLAN_NAME] App Service Plan exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating Linux App Service Plan [$APP_SERVICE_PLAN_NAME]..." + az appservice plan create \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --name "$APP_SERVICE_PLAN_NAME" \ + --location "$LOCATION" \ + --sku "$APP_SERVICE_PLAN_SKU" \ + --is-linux \ + --only-show-errors 1>/dev/null + + if [ $? -eq 0 ]; then + echo "App Service Plan [$APP_SERVICE_PLAN_NAME] created successfully." + else + echo "Failed to create App Service Plan [$APP_SERVICE_PLAN_NAME]." + exit 1 + fi +else + echo "[$APP_SERVICE_PLAN_NAME] App Service Plan already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Get the App Service Plan resource id +echo "Getting [$APP_SERVICE_PLAN_NAME] App Service Plan resource id in the [$RESOURCE_GROUP_NAME] resource group..." +APP_SERVICE_PLAN_ID=$(az appservice plan show \ + --name "$APP_SERVICE_PLAN_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $APP_SERVICE_PLAN_ID ]]; then + echo "[$APP_SERVICE_PLAN_NAME] App Service Plan resource id retrieved successfully: $APP_SERVICE_PLAN_ID" +else + echo "Failed to retrieve [$APP_SERVICE_PLAN_NAME] App Service Plan resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Check if the Web App already exists +echo "Checking if [$WEB_APP_NAME] Web App already exists in the [$RESOURCE_GROUP_NAME] resource group..." +az webapp show \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$WEB_APP_NAME] Web App exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating Web App [$WEB_APP_NAME] from custom image [$FULL_IMAGE]..." + az webapp create \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --plan "$APP_SERVICE_PLAN_NAME" \ + --name "$WEB_APP_NAME" \ + --assign-identity "${IDENTITY_ID}" \ + --container-image-name "$FULL_IMAGE" \ + --vnet "$VIRTUAL_NETWORK_NAME" \ + --subnet "$WEB_APP_SUBNET_NAME" \ + --only-show-errors 1>/dev/null -echo "Creating Web App [$WEB_APP_NAME] from custom image [$WEBAPP_IMAGE]..." + if [ $? -eq 0 ]; then + echo "Web App [$WEB_APP_NAME] created successfully." + else + echo "Failed to create Web App [$WEB_APP_NAME]." + exit 1 + fi +else + echo "[$WEB_APP_NAME] Web App already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi -az webapp create \ - --resource-group "$RESOURCE_GROUP_NAME" \ - --plan "$APP_SERVICE_PLAN_NAME" \ +# Configure the App Service to use managed identity for ACR authentication +echo "Configuring Web App [$WEB_APP_NAME] to use managed identity [$MANAGED_IDENTITY_NAME] to access Azure Container Registry [$ACR_NAME]..." +az webapp config set \ --name "$WEB_APP_NAME" \ - --container-image-name "$WEBAPP_IMAGE" + --resource-group "$RESOURCE_GROUP_NAME" \ + --generic-configurations "{\"acrUseManagedIdentityCreds\": true, \"acrUserManagedIdentityID\": \"$CLIENT_ID\"}" 1>/dev/null + +if [ $? -eq 0 ]; then + echo "Web App [$WEB_APP_NAME] configured to use managed identity [$MANAGED_IDENTITY_NAME] to access Azure Container Registry [$ACR_NAME] successfully." +else + echo "Failed to configure Web App [$WEB_APP_NAME] to use managed identity [$MANAGED_IDENTITY_NAME] to access Azure Container Registry [$ACR_NAME]." + exit 1 +fi -echo "Setting Web App container settings..." +# Get the Web App resource id +echo "Getting [$WEB_APP_NAME] Web App resource id in the [$RESOURCE_GROUP_NAME] resource group..." +WEB_APP_ID=$(az webapp show \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query id \ + --output tsv \ + --only-show-errors) + +if [[ -n $WEB_APP_ID ]]; then + echo "[$WEB_APP_NAME] Web App resource id retrieved successfully: $WEB_APP_ID" +else + echo "Failed to retrieve [$WEB_APP_NAME] Web App resource id in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 +fi + +# Enabling forced tunneling for the web app to route all outbound traffic through the virtual network +echo "Enabling forced tunneling for web app [$WEB_APP_NAME] to route all outbound traffic through the virtual network..." + +az resource update \ + --ids "$WEB_APP_ID" \ + --set properties.outboundVnetRouting.allTraffic=true \ + --only-show-errors 1>/dev/null + +if [ $? -eq 0 ]; then + echo "Forced tunneling enabled for web app [$WEB_APP_NAME]." +else + echo "Failed to enable forced tunneling for web app [$WEB_APP_NAME]." + exit 1 +fi + +# Set web app settings +echo "Setting Web App container settings for [$WEB_APP_NAME]..." az webapp config appsettings set \ --name "$WEB_APP_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --settings \ - WEBSITE_PORT="80" \ WEBSITES_PORT="80" \ APP_NAME="Custom Image" \ - IMAGE_NAME="$WEBAPP_IMAGE" + IMAGE_NAME="$FULL_IMAGE" \ + --only-show-errors 1>/dev/null + +if [ $? -eq 0 ]; then + echo "Web App settings for [$WEB_APP_NAME] set successfully." +else + echo "Failed to set Web App settings for [$WEB_APP_NAME]." + exit 1 +fi + +# Check if the Log Analytics workspace already exists +echo "Checking if [$LOG_ANALYTICS_NAME] Log Analytics workspace already exists in the [$RESOURCE_GROUP_NAME] resource group..." +az monitor log-analytics workspace show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --workspace-name "$LOG_ANALYTICS_NAME" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$LOG_ANALYTICS_NAME] Log Analytics workspace actually exists in the [$RESOURCE_GROUP_NAME] resource group" + echo "Creating [$LOG_ANALYTICS_NAME] Log Analytics workspace in the [$RESOURCE_GROUP_NAME] resource group..." + + # Create the Log Analytics workspace + az monitor log-analytics workspace create \ + --name "$LOG_ANALYTICS_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --location "$LOCATION" \ + --query-access "Enabled" \ + --retention-time 30 \ + --sku "PerNode" \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$LOG_ANALYTICS_NAME] Log Analytics workspace successfully created in the [$RESOURCE_GROUP_NAME] resource group" + else + echo "Failed to create [$LOG_ANALYTICS_NAME] Log Analytics workspace in the [$RESOURCE_GROUP_NAME] resource group" + exit 1 + fi +else + echo "[$LOG_ANALYTICS_NAME] Log Analytics workspace already exists in the [$RESOURCE_GROUP_NAME] resource group" +fi + +# Check whether the diagnostic settings for the container registry already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$ACR_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry..." + + # Create the diagnostic settings for the container registry to send logs to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$ACR_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --logs '[ + {"category": "ContainerRegistryRepositoryEvents", "enabled": true}, + {"category": "ContainerRegistryLoginEvents", "enabled": true} + ]' \ + --metrics '[ + {"category": "AllMetrics", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$ACR_NAME] container registry already exist" +fi + +# Check whether the diagnostic settings for the web app already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$WEB_APP_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app..." + + # Create the diagnostic settings for the web app to send logs to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$WEB_APP_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --logs '[ + {"category": "AppServiceHTTPLogs", "enabled": true}, + {"category": "AppServiceConsoleLogs", "enabled": true}, + {"category": "AppServiceAppLogs", "enabled": true}, + {"category": "AppServiceAuditLogs", "enabled": true}, + {"category": "AppServiceIPSecAuditLogs", "enabled": true}, + {"category": "AppServicePlatformLogs", "enabled": true}, + {"category": "AppServiceAuthenticationLogs", "enabled": true} + ]' \ + --metrics '[ + {"category": "AllMetrics", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_NAME] web app already exist" +fi + +# Check whether the diagnostic settings for the App Service Plan already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$APP_SERVICE_PLAN_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan..." + + # Create the diagnostic settings for the App Service Plan to send metrics to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$APP_SERVICE_PLAN_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --metrics '[ + {"category": "AllMetrics", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$APP_SERVICE_PLAN_NAME] App Service Plan already exist" +fi + +# Check whether the diagnostic settings for the virtual network already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$VIRTUAL_NETWORK_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network..." + + # Create the diagnostic settings for the virtual network to send logs to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$VIRTUAL_NETWORK_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --logs '[ + {"category": "VMProtectionAlerts", "enabled": true} + ]' \ + --metrics '[ + {"category": "AllMetrics", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$VIRTUAL_NETWORK_NAME] virtual network already exist" +fi + +# Check whether the diagnostic settings for the network security group for the web app subnet already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$WEB_APP_SUBNET_NSG_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet..." + + # Create the diagnostic settings for the network security group for the web app subnet to send logs to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$WEB_APP_SUBNET_NSG_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --logs '[ + {"category": "NetworkSecurityGroupEvent", "enabled": true}, + {"category": "NetworkSecurityGroupRuleCounter", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$WEB_APP_SUBNET_NSG_NAME] network security group for the web app subnet already exist" +fi + +# Check whether the diagnostic settings for the network security group for the private endpoint subnet already exist +echo "Checking if [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet already exist..." +az monitor diagnostic-settings show \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$PE_SUBNET_NSG_ID" \ + --only-show-errors &>/dev/null + +if [[ $? != 0 ]]; then + echo "No [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet actually exist" + echo "Creating [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet..." + + # Create the diagnostic settings for the network security group for the private endpoint subnet to send logs to the Log Analytics workspace + az monitor diagnostic-settings create \ + --name "$DIAGNOSTIC_SETTINGS_NAME" \ + --resource "$PE_SUBNET_NSG_ID" \ + --workspace "$LOG_ANALYTICS_NAME" \ + --logs '[ + {"category": "NetworkSecurityGroupEvent", "enabled": true}, + {"category": "NetworkSecurityGroupRuleCounter", "enabled": true} + ]' \ + --only-show-errors 1>/dev/null + + if [[ $? == 0 ]]; then + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet successfully created" + else + echo "Failed to create [$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet" + exit 1 + fi +else + echo "[$DIAGNOSTIC_SETTINGS_NAME] diagnostic settings for the [$PE_SUBNET_NSG_NAME] network security group for the private endpoint subnet already exist" +fi echo "Listing resources in resource group [$RESOURCE_GROUP_NAME]..." az resource list --resource-group "$RESOURCE_GROUP_NAME" --output table @@ -84,7 +1017,8 @@ echo "Deployment complete." echo "Resource Group: $RESOURCE_GROUP_NAME" echo "App Service Plan: $APP_SERVICE_PLAN_NAME" echo "Web App: $WEB_APP_NAME" -echo "ACR: $ACR_NAME ($LOGIN_SERVER)" -echo "Image: $WEBAPP_IMAGE" +echo "Azure Container Registry: $ACR_NAME ($ACR_LOGIN_SERVER)" +echo "Image: $FULL_IMAGE" +echo "Managed Identity: $MANAGED_IDENTITY_NAME" echo "" echo "Run 'bash scripts/validate.sh' to verify the deployment." diff --git a/samples/web-app-custom-image/python/scripts/validate.sh b/samples/web-app-custom-image/python/scripts/validate.sh index 8d89b8c..b58fb61 100755 --- a/samples/web-app-custom-image/python/scripts/validate.sh +++ b/samples/web-app-custom-image/python/scripts/validate.sh @@ -3,28 +3,48 @@ set -euo pipefail PREFIX='local' SUFFIX='test' -RESOURCE_GROUP_NAME="${PREFIX}-custom-image-rg" -ACR_NAME="${PREFIX}customimageacr" -APP_SERVICE_PLAN_NAME="${PREFIX}-custom-image-plan-${SUFFIX}" -WEB_APP_NAME="${PREFIX}-custom-image-webapp-${SUFFIX}" +RESOURCE_GROUP_NAME="${PREFIX}-rg" +ACR_NAME="${PREFIX}acr${SUFFIX}" +MANAGED_IDENTITY_NAME="${PREFIX}-identity-${SUFFIX}" +APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" +VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" +PRIVATE_DNS_ZONE_NAME="privatelink.azurecr.io" +PRIVATE_ENDPOINT_NAME="${PREFIX}-acr-pe-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" +NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" +PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" +LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" +# Check resource group echo -e "[$RESOURCE_GROUP_NAME] resource group:\n" az group show \ --name "$RESOURCE_GROUP_NAME" \ --output table +# Check managed identity +echo -e "[$MANAGED_IDENTITY_NAME] managed identity:\n" +az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check App Service Plan echo -e "\n[$APP_SERVICE_PLAN_NAME] App Service Plan:\n" az appservice plan show \ --name "$APP_SERVICE_PLAN_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --output table +# Check Azure Container Registry echo -e "\n[$ACR_NAME] Azure Container Registry:\n" az acr show \ --name "$ACR_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --output table +# Check Azure Web App echo -e "\n[$WEB_APP_NAME] Web App:\n" az webapp show \ --name "$WEB_APP_NAME" \ @@ -32,13 +52,80 @@ az webapp show \ --query "{name:name, state:state, defaultHostName:defaultHostName, kind:kind}" \ --output table +# Check App Settings echo -e "\n[$WEB_APP_NAME] app settings:\n" az webapp config appsettings list \ --name "$WEB_APP_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ - --query "[?name=='IMAGE_NAME' || name=='WEBSITE_PORT' || name=='WEBSITES_PORT'].[name,value]" \ + --query "[?name=='IMAGE_NAME' || name=='APP_NAME' || name=='WEBSITES_PORT']" \ --output table +# Check Virtual Network +echo -e "\n[$VIRTUAL_NETWORK_NAME] virtual network:\n" +az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private DNS Zone +echo -e "\n[$PRIVATE_DNS_ZONE_NAME] private dns zone:\n" +az network private-dns zone show \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query '{Name:name,ResourceGroup:resourceGroup,RecordSets:recordSets,VirtualNetworkLinks:virtualNetworkLinks}' \ + --output table \ + --only-show-errors + +# Check Private Endpoint +echo -e "\n[$PRIVATE_ENDPOINT_NAME] private endpoint:\n" +az network private-endpoint show \ + --name "$PRIVATE_ENDPOINT_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Web App Subnet NSG +echo -e "\n[$WEB_APP_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private Endpoint Subnet NSG +echo -e "\n[$PE_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check NAT Gateway +echo -e "\n[$NAT_GATEWAY_NAME] nat gateway:\n" +az network nat gateway show \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Public IP Prefix +echo -e "\n[$PIP_PREFIX_NAME] public ip prefix:\n" +az network public-ip prefix show \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Log Analytics Workspace +echo -e "\n[$LOG_ANALYTICS_NAME] log analytics workspace:\n" +az monitor log-analytics workspace show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --workspace-name "$LOG_ANALYTICS_NAME" \ + --query '{Name:name,Location:location,ResourceGroup:resourceGroup}' \ + --output table \ + --only-show-errors + echo -e "\nResources in [$RESOURCE_GROUP_NAME]:\n" az resource list \ --resource-group "$RESOURCE_GROUP_NAME" \ diff --git a/samples/web-app-custom-image/python/src/app.py b/samples/web-app-custom-image/python/src/app.py index 7a4b31c..faccd67 100644 --- a/samples/web-app-custom-image/python/src/app.py +++ b/samples/web-app-custom-image/python/src/app.py @@ -12,7 +12,7 @@ def index(): return render_template( "index.html", app_name=os.environ.get("APP_NAME", "Custom Image Web App"), - image_name=os.environ.get("IMAGE_NAME", "vacation-planner-webapp:v1"), + image_name=os.environ.get("IMAGE_NAME", "custom-image-webapp:v1"), hostname=socket.gethostname(), ) @@ -23,7 +23,7 @@ def status(): { "status": "ok", "app": os.environ.get("APP_NAME", "Custom Image Web App"), - "image": os.environ.get("IMAGE_NAME", "vacation-planner-webapp:v1"), + "image": os.environ.get("IMAGE_NAME", "custom-image-webapp:v1"), "hostname": socket.gethostname(), } ) diff --git a/samples/web-app-custom-image/python/terraform/README.md b/samples/web-app-custom-image/python/terraform/README.md new file mode 100644 index 0000000..8f87db4 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/README.md @@ -0,0 +1,280 @@ +# Terraform Deployment + +This directory contains Terraform modules and a deployment script for provisioning Azure services in LocalStack for Azure. For further details about the sample application, refer to the [Azure Web App with Custom Docker Image](../README.md). + +## Prerequisites + +Before deploying this solution, ensure you have the following tools installed: + +- [LocalStack for Azure](https://docs.localstack.cloud/azure/): Local Azure cloud emulator for development and testing +- [Visual Studio Code](https://code.visualstudio.com/): Code editor installed on one of the [supported platforms](https://code.visualstudio.com/docs/supporting/requirements#_platforms) +- [Terraform](https://developer.hashicorp.com/terraform/downloads): Infrastructure as Code tool for provisioning Azure resources +- [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack and building the custom image +- [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface +- [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper +- [Python](https://www.python.org/downloads/): Python runtime (version 3.12 or above) +- [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs + +### Installing azlocal CLI + +The [deploy.sh](deploy.sh) Bash script uses the `azlocal` CLI instead of the standard Azure CLI to work with LocalStack. Install it using: + +```bash +pip install azlocal +``` + +For more information, see [Get started with the az tool on LocalStack](https://azure.localstack.cloud/user-guides/sdks/az/). + +## Architecture Overview + +The Terraform modules create the following Azure resources: + +1. [Azure Resource Group](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/manage-resource-groups-cli): A logical container scoping all resources in this sample. +2. [Azure Virtual Network](https://learn.microsoft.com/azure/virtual-network/virtual-networks-overview): Hosts two subnets: + - *app-subnet*: Dedicated to [regional VNet integration](https://learn.microsoft.com/azure/azure-functions/functions-networking-options?tabs=azure-portal#outbound-networking-features) with the Web App. + - *pe-subnet*: Used for hosting Azure Private Endpoints. +3. [Azure Private DNS Zone](https://learn.microsoft.com/azure/dns/private-dns-privatednszone): Handles DNS resolution for the Azure Container Registry Private Endpoint within the virtual network. +4. [Azure Private Endpoint](https://learn.microsoft.com/azure/private-link/private-endpoint-overview): Secures network access to the Azure Container Registry via a private IP within the VNet. +5. [Azure NAT Gateway](https://learn.microsoft.com/azure/nat-gateway/nat-overview): Provides deterministic outbound connectivity for the Web App. Included for completeness; the sample app does not call any external services. +6. [Azure Network Security Group](https://learn.microsoft.com/en-us/azure/virtual-network/network-security-groups-overview): Enforces inbound and outbound traffic rules across the virtual network's subnets. +7. [Azure Log Analytics Workspace](https://learn.microsoft.com/azure/azure-monitor/logs/log-analytics-overview): Centralizes diagnostic logs and metrics from all resources in the solution. +8. [Azure Container Registry](https://learn.microsoft.com/azure/container-registry/container-registry-intro): A fully-managed container registry service based on the open-source [Docker platform](https://docs.docker.com/get-started/docker-overview/) used to hold the container image used by the web app. +9. [User-Assigned Managed Identity](https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/overview): Created and associated with the Web App. +10. [Azure App Service Plan](https://learn.microsoft.com/en-us/azure/app-service/overview-hosting-plans): The underlying compute tier that hosts the web application. +11. [Azure Web App](https://learn.microsoft.com/en-us/azure/app-service/overview): Runs the Python Flask application from the custom container image stored in the Azure Container Registry. + +> **Note** +> The Terraform [azurerm_linux_web_app](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs/resources/linux_web_app) resource does not support using a managed identity for container image pull from Azure Container Registry. The Terraform deployment uses ACR admin username and password instead of a managed identity. + +## Provisioning Scripts + +You can use the [deploy.sh](deploy.sh) script to automate the deployment of all Azure resources in a single step, streamlining setup and reducing manual configuration. The script executes the following steps: + +- Cleans up any previous Terraform state and plan files to ensure a fresh deployment. +- Initializes the Terraform working directory and downloads required plugins. +- Creates and validates a Terraform execution plan for the Azure infrastructure. +- Applies the Terraform plan to provision all necessary Azure resources. +- Uses a [`local-exec` provisioner](https://developer.hashicorp.com/terraform/language/resources/provisioners/local-exec) on a `null_resource` to build and push the container image to the Azure Container Registry locally before deploying the Web App. +- Deploys the Web App configured to pull the container image using ACR admin credentials. + +## Configuration + +When using LocalStack for Azure, configure the `metadata_host` and `subscription_id` settings in the [Azure Provider for Terraform](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) to ensure proper connectivity: + +```hcl +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } + + # Set the hostname of the Azure Metadata Service (for example management.azure.com) + # used to obtain the Cloud Environment when using LocalStack's Azure emulator. + # This allows the provider to correctly identify the environment and avoid making calls to the real Azure endpoints. + metadata_host = "localhost.localstack.cloud:4566" + + # Set the subscription ID to a dummy value when using LocalStack's Azure emulator. + subscription_id = "00000000-0000-0000-0000-000000000000" +} +``` + +## Deployment + +You can set up the Azure emulator by utilizing the LocalStack for Azure Docker image. Before starting, ensure you have a valid `LOCALSTACK_AUTH_TOKEN` to access the Azure emulator. Refer to the [Auth Token guide](https://docs.localstack.cloud/getting-started/auth-token/?__hstc=108988063.8aad2b1a7229945859f4d9b9bb71e05d.1743148429561.1758793541854.1758810151462.32&__hssc=108988063.3.1758810151462&__hsfp=3945774529) to obtain your Auth Token and specify it in the `LOCALSTACK_AUTH_TOKEN` environment variable. The Azure Docker image is available on the [LocalStack Docker Hub](https://hub.docker.com/r/localstack/localstack-azure-alpha). To pull the Azure Docker image, execute the following command: + +```bash +docker pull localstack/localstack-azure-alpha +``` + +Start the LocalStack Azure emulator using the localstack CLI, execute the following command: + +```bash +# Set the authentication token +export LOCALSTACK_AUTH_TOKEN= + +# Start the LocalStack Azure emulator +IMAGE_NAME=localstack/localstack-azure-alpha localstack start -d +localstack wait -t 60 + +# Route all Azure CLI calls to the LocalStack Azure emulator +azlocal start-interception +``` + +Navigate to the `terraform` folder: + +```bash +cd samples/web-app-custom-image/python/terraform +``` + +Make the script executable: + +```bash +chmod +x deploy.sh +``` + +Run the deployment script: + +```bash +./deploy.sh +``` + +## Validation + +Once the deployment completes, run the [validate.sh](../scripts/validate.sh) script to confirm that all resources were provisioned and configured as expected: + +```bash +#!/bin/bash +set -euo pipefail + +PREFIX='local' +SUFFIX='test' +RESOURCE_GROUP_NAME="${PREFIX}-rg" +ACR_NAME="${PREFIX}acr${SUFFIX}" +MANAGED_IDENTITY_NAME="${PREFIX}-identity-${SUFFIX}" +APP_SERVICE_PLAN_NAME="${PREFIX}-app-service-plan-${SUFFIX}" +WEB_APP_NAME="${PREFIX}-webapp-${SUFFIX}" +VIRTUAL_NETWORK_NAME="${PREFIX}-vnet-${SUFFIX}" +PRIVATE_DNS_ZONE_NAME="privatelink.azurecr.io" +PRIVATE_ENDPOINT_NAME="${PREFIX}-acr-pe-${SUFFIX}" +WEB_APP_SUBNET_NSG_NAME="${PREFIX}-webapp-subnet-nsg-${SUFFIX}" +PE_SUBNET_NSG_NAME="${PREFIX}-pe-subnet-nsg-${SUFFIX}" +NAT_GATEWAY_NAME="${PREFIX}-nat-gateway-${SUFFIX}" +PIP_PREFIX_NAME="${PREFIX}-nat-gateway-pip-prefix-${SUFFIX}" +LOG_ANALYTICS_NAME="${PREFIX}-log-analytics-${SUFFIX}" + +# Check resource group +echo -e "[$RESOURCE_GROUP_NAME] resource group:\n" +az group show \ + --name "$RESOURCE_GROUP_NAME" \ + --output table + +# Check managed identity +echo -e "[$MANAGED_IDENTITY_NAME] managed identity:\n" +az identity show \ + --name "$MANAGED_IDENTITY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check App Service Plan +echo -e "\n[$APP_SERVICE_PLAN_NAME] App Service Plan:\n" +az appservice plan show \ + --name "$APP_SERVICE_PLAN_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Container Registry +echo -e "\n[$ACR_NAME] Azure Container Registry:\n" +az acr show \ + --name "$ACR_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table + +# Check Azure Web App +echo -e "\n[$WEB_APP_NAME] Web App:\n" +az webapp show \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "{name:name, state:state, defaultHostName:defaultHostName, kind:kind}" \ + --output table + +# Check App Settings +echo -e "\n[$WEB_APP_NAME] app settings:\n" +az webapp config appsettings list \ + --name "$WEB_APP_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query "[?name=='IMAGE_NAME' || name=='APP_NAME' || name=='WEBSITES_PORT']" \ + --output table + +# Check Virtual Network +echo -e "\n[$VIRTUAL_NETWORK_NAME] virtual network:\n" +az network vnet show \ + --name "$VIRTUAL_NETWORK_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private DNS Zone +echo -e "\n[$PRIVATE_DNS_ZONE_NAME] private dns zone:\n" +az network private-dns zone show \ + --name "$PRIVATE_DNS_ZONE_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --query '{Name:name,ResourceGroup:resourceGroup,RecordSets:recordSets,VirtualNetworkLinks:virtualNetworkLinks}' \ + --output table \ + --only-show-errors + +# Check Private Endpoint +echo -e "\n[$PRIVATE_ENDPOINT_NAME] private endpoint:\n" +az network private-endpoint show \ + --name "$PRIVATE_ENDPOINT_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Web App Subnet NSG +echo -e "\n[$WEB_APP_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$WEB_APP_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Private Endpoint Subnet NSG +echo -e "\n[$PE_SUBNET_NSG_NAME] network security group:\n" +az network nsg show \ + --name "$PE_SUBNET_NSG_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check NAT Gateway +echo -e "\n[$NAT_GATEWAY_NAME] nat gateway:\n" +az network nat gateway show \ + --name "$NAT_GATEWAY_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Public IP Prefix +echo -e "\n[$PIP_PREFIX_NAME] public ip prefix:\n" +az network public-ip prefix show \ + --name "$PIP_PREFIX_NAME" \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table \ + --only-show-errors + +# Check Log Analytics Workspace +echo -e "\n[$LOG_ANALYTICS_NAME] log analytics workspace:\n" +az monitor log-analytics workspace show \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --workspace-name "$LOG_ANALYTICS_NAME" \ + --query '{Name:name,Location:location,ResourceGroup:resourceGroup}' \ + --output table \ + --only-show-errors + +echo -e "\nResources in [$RESOURCE_GROUP_NAME]:\n" +az resource list \ + --resource-group "$RESOURCE_GROUP_NAME" \ + --output table +``` + +## Cleanup + +To destroy all created resources: + +```bash +# Delete resource group and all contained resources +az group delete --name local-rg --yes --no-wait + +# Verify deletion +az group list --output table +``` + +This will remove all Azure resources created by the Terraform deployment. + +## Related Documentation + +- [Terraform Azure Provider Documentation](https://registry.terraform.io/providers/hashicorp/azurerm/latest/docs) +- [Terraform local-exec Provisioner](https://developer.hashicorp.com/terraform/language/resources/provisioners/local-exec) +- [LocalStack for Azure Documentation](https://docs.localstack.cloud/azure/) + diff --git a/samples/web-app-custom-image/python/terraform/deploy.sh b/samples/web-app-custom-image/python/terraform/deploy.sh new file mode 100755 index 0000000..63e42fb --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/deploy.sh @@ -0,0 +1,53 @@ +#!/bin/bash + +# Variables +PREFIX='local' +SUFFIX='test' +LOCATION='westeurope' +CURRENT_DIR="$(cd "$(dirname "$0")" && pwd)" +IMAGE_NAME="custom-image-webapp" +IMAGE_TAG="v1" + +# Change the current directory to the script's directory +cd "$CURRENT_DIR" || exit + +# Intialize Terraform +echo "Initializing Terraform..." +terraform init -upgrade + +# Run terraform plan and check for errors +echo "Planning Terraform deployment..." +terraform plan -out=tfplan \ + -var "prefix=$PREFIX" \ + -var "suffix=$SUFFIX" \ + -var "location=$LOCATION" \ + -var "image_name=$IMAGE_NAME" \ + -var "image_tag=$IMAGE_TAG" + +if [[ $? != 0 ]]; then + echo "Terraform plan failed. Exiting." + exit 1 +fi + +# Apply the Terraform configuration +echo "Applying Terraform configuration..." +terraform apply -auto-approve tfplan + +if [[ $? != 0 ]]; then + echo "Terraform apply failed. Exiting." + exit 1 +fi + +# Get the output values +RESOURCE_GROUP_NAME=$(terraform output -raw resource_group_name) +WEB_APP_NAME=$(terraform output -raw web_app_name) +ACR_NAME=$(terraform output -raw container_registry_name) + +if [[ -z "$RESOURCE_GROUP_NAME" || -z "$WEB_APP_NAME" || -z "$ACR_NAME" ]]; then + echo "Resource Group Name, Web App Name, or ACR Name is empty. Exiting." + exit 1 +fi + +# Print the list of resources in the resource group +echo "Listing resources in resource group [$RESOURCE_GROUP_NAME]..." +az resource list --resource-group "$RESOURCE_GROUP_NAME" --output table \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/main.tf b/samples/web-app-custom-image/python/terraform/main.tf new file mode 100644 index 0000000..5af101e --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/main.tf @@ -0,0 +1,225 @@ +# Local Variables +locals { + prefix = lower(var.prefix) + suffix = lower(var.suffix) + resource_group_name = "${var.prefix}-rg" + log_analytics_name = "${local.prefix}-log-analytics-${local.suffix}" + virtual_network_name = "${local.prefix}-vnet-${local.suffix}" + nat_gateway_name = "${local.prefix}-nat-gateway-${local.suffix}" + nat_gateway_ip_prefix_name = "${local.prefix}-nat-gateway-pip-prefix-${local.suffix}" + private_endpoint_name = "${local.prefix}-acr-pe-${local.suffix}" + webapp_subnet_nsg_name = "${local.prefix}-webapp-subnet-nsg-${local.suffix}" + pe_subnet_nsg_name = "${local.prefix}-pe-subnet-nsg-${local.suffix}" + acr_name = "${local.prefix}acr${local.suffix}" + managed_identity_name = "${local.prefix}-identity-${local.suffix}" + app_service_plan_name = "${local.prefix}-app-service-plan-${local.suffix}" + web_app_name = "${local.prefix}-webapp-${local.suffix}" +} + +# Data Sources +data "azurerm_client_config" "current" { +} + +# Create a resource group +resource "azurerm_resource_group" "example" { + name = local.resource_group_name + location = var.location + tags = var.tags +} + +# Create a log analytics workspace +module "log_analytics_workspace" { + source = "./modules/log_analytics" + name = local.log_analytics_name + location = var.location + resource_group_name = azurerm_resource_group.example.name + tags = var.tags +} + +# Create a container registry +module "container_registry" { + source = "./modules/container_registry" + name = local.acr_name + resource_group_name = azurerm_resource_group.example.name + location = var.location + sku = var.acr_sku + admin_enabled = var.acr_admin_enabled + georeplication_locations = var.acr_georeplication_locations + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags +} + +# Create a virtual network with subnets +module "virtual_network" { + source = "./modules/virtual_network" + resource_group_name = azurerm_resource_group.example.name + location = var.location + vnet_name = local.virtual_network_name + address_space = var.vnet_address_space + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags + + subnets = [ + { + name : var.webapp_subnet_name + address_prefixes : var.webapp_subnet_address_prefix + private_endpoint_network_policies : "Enabled" + private_link_service_network_policies_enabled : false + delegation : "Microsoft.Web/serverFarms" + }, + { + name : var.pe_subnet_name + address_prefixes : var.pe_subnet_address_prefix + private_endpoint_network_policies : "Enabled" + private_link_service_network_policies_enabled : false + delegation : null + } + ] +} + +# Create a network security group and associate it with the webapp subnet +module "webapp_subnet_network_security_group" { + source = "./modules/network_security_group" + name = local.webapp_subnet_nsg_name + resource_group_name = azurerm_resource_group.example.name + location = var.location + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags + subnet_ids = { + (var.webapp_subnet_name) = module.virtual_network.subnet_ids[var.webapp_subnet_name] + } +} + +# Create a network security group and associate it with the private endpoint subnet +module "pe_subnet_network_security_group" { + source = "./modules/network_security_group" + name = local.pe_subnet_nsg_name + resource_group_name = azurerm_resource_group.example.name + location = var.location + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags + subnet_ids = { + (var.pe_subnet_name) = module.virtual_network.subnet_ids[var.pe_subnet_name] + } +} + +# Create a NAT gateway and associate it with the webapp subnet +module "nat_gateway" { + source = "./modules/nat_gateway" + name = local.nat_gateway_name + resource_group_name = azurerm_resource_group.example.name + location = var.location + sku_name = var.nat_gateway_sku_name + public_ip_prefix_name = local.nat_gateway_ip_prefix_name + public_ip_prefix_length = 31 + idle_timeout_in_minutes = var.nat_gateway_idle_timeout_in_minutes + zones = var.nat_gateway_zones + subnet_ids = { + (var.webapp_subnet_name) = module.virtual_network.subnet_ids[var.webapp_subnet_name] + } + tags = var.tags +} + +# Create a private DNS zone for the CosmosDB MongoDB account and link it to the virtual network +module "private_dns_zone" { + source = "./modules/private_dns_zone" + name = "privatelink.azurecr.io" + resource_group_name = azurerm_resource_group.example.name + tags = var.tags + virtual_networks_to_link = { + (module.virtual_network.name) = { + subscription_id = data.azurerm_client_config.current.subscription_id + resource_group_name = azurerm_resource_group.example.name + } + } +} + +# Create a private endpoint for the CosmosDB MongoDB account in the pe_subnet subnet +module "private_endpoint" { + source = "./modules/private_endpoint" + name = local.private_endpoint_name + location = var.location + resource_group_name = azurerm_resource_group.example.name + subnet_id = module.virtual_network.subnet_ids[var.pe_subnet_name] + tags = var.tags + private_connection_resource_id = module.container_registry.id + is_manual_connection = false + subresource_name = "registry" + private_dns_zone_group_name = "private-dns-zone-group" + private_dns_zone_group_ids = [module.private_dns_zone.id] +} + +# Create App Service Plan using module +module "app_service_plan" { + source = "./modules/app_service_plan" + name = local.app_service_plan_name + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + sku_name = var.sku_name + os_type = var.os_type + zone_balancing_enabled = var.zone_balancing_enabled + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags +} + +# Create a user-assigned managed identity +module "managed_identity" { + source = "./modules/managed_identity" + name = local.managed_identity_name + resource_group_name = azurerm_resource_group.example.name + location = var.location + acr_id = module.container_registry.id + tags = var.tags +} + +# Push container image to the registry +resource "null_resource" "push_image" { + count = (var.image_name != null && var.image_name != "" && var.image_tag != null && var.image_tag != "") ? 1 : 0 + + provisioner "local-exec" { + command = "${path.root}/push_image.sh" + environment = { + ACR_NAME = local.acr_name + ACR_LOGIN_SERVER = module.container_registry.login_server + IMAGE_NAME = var.image_name + IMAGE_TAG = var.image_tag + } + } + + depends_on = [module.container_registry] +} + +# Create Web App using module +module "web_app" { + source = "./modules/web_app" + name = local.web_app_name + resource_group_name = azurerm_resource_group.example.name + location = azurerm_resource_group.example.location + managed_identity_id = module.managed_identity.id + service_plan_id = module.app_service_plan.id + https_only = var.https_only + virtual_network_subnet_id = module.virtual_network.subnet_ids[var.webapp_subnet_name] + vnet_route_all_enabled = true + public_network_access_enabled = var.public_network_access_enabled + always_on = var.always_on + http2_enabled = var.http2_enabled + minimum_tls_version = var.minimum_tls_version + image_name = var.image_name + image_tag = var.image_tag + docker_registry_url = module.container_registry.login_server_url + docker_registry_username = module.container_registry.admin_username + docker_registry_password = module.container_registry.admin_password + repo_url = var.repo_url + log_analytics_workspace_id = module.log_analytics_workspace.id + tags = var.tags + + app_settings = { + SCM_DO_BUILD_DURING_DEPLOYMENT = "true" + ENABLE_ORYX_BUILD = "true" + WEBSITES_PORT = var.websites_port + APP_NAME = "Custom Image" + IMAGE_NAME = "${module.container_registry.login_server}/${var.image_name}:${var.image_tag}" + } + + depends_on = [null_resource.push_image] +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/app_service_plan/main.tf b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/main.tf new file mode 100644 index 0000000..98a3e4d --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/main.tf @@ -0,0 +1,25 @@ +resource "azurerm_service_plan" "example" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + sku_name = var.sku_name + os_type = var.os_type + zone_balancing_enabled = var.zone_balancing_enabled + tags = var.tags + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_monitor_diagnostic_setting" "example" { + name = "DiagnosticsSettings" + target_resource_id = azurerm_service_plan.example.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + enabled_metric { + category = "AllMetrics" + } +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/app_service_plan/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/outputs.tf new file mode 100644 index 0000000..f1455ea --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/outputs.tf @@ -0,0 +1,19 @@ +output "id" { + value = azurerm_service_plan.example.id + description = "Specifies the resource id of the App Service Plan" +} + +output "name" { + value = azurerm_service_plan.example.name + description = "Specifies the name of the App Service Plan" +} + +output "location" { + value = azurerm_service_plan.example.location + description = "Specifies the location of the App Service Plan" +} + +output "resource_group_name" { + value = azurerm_service_plan.example.resource_group_name + description = "Specifies the resource group name of the App Service Plan" +} diff --git a/samples/web-app-custom-image/python/terraform/modules/app_service_plan/variables.tf b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/variables.tf new file mode 100644 index 0000000..e543066 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/app_service_plan/variables.tf @@ -0,0 +1,42 @@ +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group." + type = string +} + +variable "location" { + description = "(Required) Specifies the location for the App Service Plan." + type = string +} + +variable "name" { + description = "(Required) Specifies the name of the App Service Plan." + type = string +} + +variable "sku_name" { + description = "(Required) Specifies the SKU name for the App Service Plan." + type = string +} + +variable "os_type" { + description = "(Required) Specifies the O/S type for the App Services to be hosted in this plan." + type = string + default = "Linux" +} + +variable "zone_balancing_enabled" { + description = "(Optional) Should the Service Plan balance across Availability Zones in the region." + type = bool + default = false +} + +variable "tags" { + description = "(Optional) Specifies the tags to be applied to the resources." + type = map(any) + default = {} +} + +variable "log_analytics_workspace_id" { + description = "Specifies the resource id of the Azure Log Analytics workspace." + type = string +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/container_registry/main.tf b/samples/web-app-custom-image/python/terraform/modules/container_registry/main.tf new file mode 100644 index 0000000..8bbc17d --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/container_registry/main.tf @@ -0,0 +1,62 @@ +resource "azurerm_container_registry" "example" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + sku = var.sku + admin_enabled = var.admin_enabled + tags = var.tags + + identity { + type = "UserAssigned" + identity_ids = [ + azurerm_user_assigned_identity.identity.id + ] + } + + dynamic "georeplications" { + for_each = var.georeplication_locations + + content { + location = georeplications.value + tags = var.tags + } + } + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_user_assigned_identity" "identity" { + resource_group_name = var.resource_group_name + location = var.location + tags = var.tags + + name = "${var.name}Identity" + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_monitor_diagnostic_setting" "example" { + name = "DiagnosticsSettings" + target_resource_id = azurerm_container_registry.example.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + enabled_log { + category = "ContainerRegistryRepositoryEvents" + } + + enabled_log { + category = "ContainerRegistryLoginEvents" + } + + enabled_metric { + category = "AllMetrics" + } +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/container_registry/output.tf b/samples/web-app-custom-image/python/terraform/modules/container_registry/output.tf new file mode 100644 index 0000000..5e6fcd1 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/container_registry/output.tf @@ -0,0 +1,34 @@ +output "name" { + description = "Specifies the name of the container registry." + value = azurerm_container_registry.example.name +} + +output "id" { + description = "Specifies the resource id of the container registry." + value = azurerm_container_registry.example.id +} + +output "resource_group_name" { + description = "Specifies the name of the resource group." + value = var.resource_group_name +} + +output "login_server" { + description = "Specifies the login server of the container registry." + value = azurerm_container_registry.example.login_server +} + +output "login_server_url" { + description = "Specifies the login server url of the container registry." + value = "https://${azurerm_container_registry.example.login_server}" +} + +output "admin_username" { + description = "Specifies the admin username of the container registry." + value = azurerm_container_registry.example.admin_username +} + +output "admin_password" { + description = "Specifies the admin password of the container registry." + value = azurerm_container_registry.example.admin_password +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf b/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf new file mode 100644 index 0000000..50429a5 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf @@ -0,0 +1,60 @@ +variable "name" { + description = "(Required) Specifies the name of the Container Registry. Changing this forces a new resource to be created." + type = string +} + +variable "resource_group_name" { + description = "(Required) The name of the resource group in which to create the Container Registry. Changing this forces a new resource to be created." + type = string +} + +variable "location" { + description = "(Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created." + type = string +} + +variable "admin_enabled" { + description = "(Optional) Specifies whether the admin user is enabled. Defaults to false." + type = string + default = false +} + +variable "sku" { + description = "(Optional) The SKU name of the container registry. Possible values are Basic, Standard and Premium. Defaults to Basic" + type = string + default = "Basic" + + validation { + condition = contains(["Basic", "Standard", "Premium"], var.sku) + error_message = "The container registry sku is invalid." + } +} + +variable "tags" { + description = "(Optional) A mapping of tags to assign to the resource." + type = map(any) + default = {} +} + +variable "georeplication_locations" { + description = "(Optional) A list of Azure locations where the container registry should be geo-replicated." + type = list(string) + default = [] +} + +variable "log_analytics_workspace_id" { + description = "Specifies the resource id of the Azure Log Analytics workspace." + type = string +} + +variable "image_name" { + description = "(Required) Specifies the name of the container image to deploy to the Web App." + type = string + default = "custom-image-webapp" +} + +variable "image_tag" { + description = "(Required) Specifies the tag of the container image to deploy to the Web App." + type = string + default = "v1" +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf b/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf new file mode 100644 index 0000000..2f88414 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf @@ -0,0 +1,14 @@ +resource "azurerm_log_analytics_workspace" "example" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + sku = var.sku + tags = var.tags + retention_in_days = var.retention_in_days != "" ? var.retention_in_days : null + + lifecycle { + ignore_changes = [ + tags + ] + } +} diff --git a/samples/web-app-custom-image/python/terraform/modules/log_analytics/output.tf b/samples/web-app-custom-image/python/terraform/modules/log_analytics/output.tf new file mode 100644 index 0000000..fe2c398 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/log_analytics/output.tf @@ -0,0 +1,30 @@ +output "id" { + value = azurerm_log_analytics_workspace.example.id + description = "Specifies the resource id of the log analytics workspace" +} + +output "location" { + value = azurerm_log_analytics_workspace.example.location + description = "Specifies the location of the log analytics workspace" +} + +output "name" { + value = azurerm_log_analytics_workspace.example.name + description = "Specifies the name of the log analytics workspace" +} + +output "resource_group_name" { + value = azurerm_log_analytics_workspace.example.resource_group_name + description = "Specifies the name of the resource group that contains the log analytics workspace" +} + +output "workspace_id" { + value = azurerm_log_analytics_workspace.example.workspace_id + description = "Specifies the workspace id of the log analytics workspace" +} + +output "primary_shared_key" { + value = azurerm_log_analytics_workspace.example.primary_shared_key + description = "Specifies the workspace key of the log analytics workspace" + sensitive = true +} diff --git a/samples/web-app-custom-image/python/terraform/modules/log_analytics/variables.tf b/samples/web-app-custom-image/python/terraform/modules/log_analytics/variables.tf new file mode 100644 index 0000000..2db6a01 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/log_analytics/variables.tf @@ -0,0 +1,37 @@ +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group." + type = string +} + +variable "location" { + description = "(Required) Specifies the location of the Azure Log Analytics workspace" + type = string +} + +variable "name" { + description = "(Required) Specifies the name of the Azure Log Analytics workspace" + type = string +} + +variable "sku" { + description = "(Optional) Specifies the sku of the Azure Log Analytics workspace" + type = string + default = "PerGB2018" + + validation { + condition = contains(["Free", "Standalone", "PerNode", "PerGB2018"], var.sku) + error_message = "The log analytics sku is incorrect." + } +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure Log Analytics workspace." + type = map(any) + default = {} +} + +variable "retention_in_days" { + description = " (Optional) Specifies the workspace data retention in days. Possible values are either 7 (Free Tier only) or range between 30 and 730." + type = number + default = 30 +} diff --git a/samples/web-app-custom-image/python/terraform/modules/managed_identity/main.tf b/samples/web-app-custom-image/python/terraform/modules/managed_identity/main.tf new file mode 100644 index 0000000..95f89a8 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/managed_identity/main.tf @@ -0,0 +1,20 @@ + +resource "azurerm_user_assigned_identity" "example" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + tags = var.tags + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_role_assignment" "example" { + scope = var.acr_id + role_definition_name = "AcrPull" + principal_id = azurerm_user_assigned_identity.example.principal_id + skip_service_principal_aad_check = true +} diff --git a/samples/web-app-custom-image/python/terraform/modules/managed_identity/output.tf b/samples/web-app-custom-image/python/terraform/modules/managed_identity/output.tf new file mode 100644 index 0000000..a22e571 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/managed_identity/output.tf @@ -0,0 +1,25 @@ + +output "id" { + value = azurerm_user_assigned_identity.example.id + description = "Specifies the resource id of the workload user-defined managed identity" +} + +output "location" { + value = azurerm_user_assigned_identity.example.location + description = "Specifies the location of the workload user-defined managed identity" +} + +output "name" { + value = azurerm_user_assigned_identity.example.name + description = "Specifies the name of the workload user-defined managed identity" +} + +output "client_id" { + value = azurerm_user_assigned_identity.example.client_id + description = "Specifies the client id of the workload user-defined managed identity" +} + +output "principal_id" { + value = azurerm_user_assigned_identity.example.principal_id + description = "Specifies the principal id of the workload user-defined managed identity" +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/managed_identity/variables.tf b/samples/web-app-custom-image/python/terraform/modules/managed_identity/variables.tf new file mode 100644 index 0000000..5da194a --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/managed_identity/variables.tf @@ -0,0 +1,26 @@ +variable "name" { + description = "(Required) Specifies the name of the log analytics workspace" + type = string +} + +variable "resource_group_name" { + description = "(Required) Specifies the resource group name" + type = string +} + +variable "location" { + description = "(Required) Specifies the location of the log analytics workspace" + type = string +} + +variable "tags" { + description = "(Optional) Specifies the tags of the log analytics workspace" + type = map(any) + default = {} +} + +variable "acr_id" { + description = "(Required) Specifies resource id of the Azure Container Registry resource" + type = string +} + diff --git a/samples/web-app-custom-image/python/terraform/modules/nat_gateway/main.tf b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/main.tf new file mode 100644 index 0000000..0dea868 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/main.tf @@ -0,0 +1,42 @@ +resource "azurerm_public_ip_prefix" "example" { + name = var.public_ip_prefix_name + location = var.location + resource_group_name = var.resource_group_name + sku = var.sku_name + zones = var.zones + tags = var.tags + prefix_length = var.public_ip_prefix_length + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_nat_gateway" "example" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + sku_name = var.sku_name + idle_timeout_in_minutes = var.idle_timeout_in_minutes + zones = var.zones + tags = var.tags + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_nat_gateway_public_ip_prefix_association" "example" { + nat_gateway_id = azurerm_nat_gateway.example.id + public_ip_prefix_id = azurerm_public_ip_prefix.example.id +} + +resource "azurerm_subnet_nat_gateway_association" "example" { + for_each = var.subnet_ids + subnet_id = each.value + nat_gateway_id = azurerm_nat_gateway.example.id +} diff --git a/samples/web-app-custom-image/python/terraform/modules/nat_gateway/output.tf b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/output.tf new file mode 100644 index 0000000..3f5d284 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/output.tf @@ -0,0 +1,9 @@ +output "name" { + value = azurerm_nat_gateway.example.name + description = "Specifies the name of the Azure NAT Gateway" +} + +output "id" { + value = azurerm_nat_gateway.example.id + description = "Specifies the resource id of the Azure NAT Gateway" +} diff --git a/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf new file mode 100644 index 0000000..b66d7ef --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf @@ -0,0 +1,55 @@ +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group." + type = string +} + +variable "location" { + description = "(Required) Specifies the location of the Azure NAT Gateway" + type = string +} + +variable "name" { + description = "(Required) Specifies the name of the Azure NAT Gateway" + type = string +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure NAT Gateway" + type = map(any) + default = {} +} + +variable "sku_name" { + description = "(Optional) The SKU which should be used. At this time the only supported value is Standard. Defaults to Standard" + type = string + default = "Standard" +} + +variable "idle_timeout_in_minutes" { + description = "(Optional) The idle timeout which should be used in minutes. Defaults to 4." + type = number + default = 4 +} + +variable "zones" { + description = " (Optional) A list of Availability Zones in which this NAT Gateway should be located. Changing this forces a new NAT Gateway to be created." + type = list(string) + default = [] +} + +variable "subnet_ids" { + description = "(Required) A map of subnet ids to associate with the NAT Gateway" + type = map(string) +} + +variable "public_ip_prefix_name" { + description = "(Required) The name of the public IP prefix to create and associate with the NAT Gateway." + type = string + default = null +} + +variable "public_ip_prefix_length" { + description = "(Required) The length of the public IP prefix to create and associate with the NAT Gateway. Must be between 28 and 30." + type = number + default = 31 +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/network_security_group/main.tf b/samples/web-app-custom-image/python/terraform/modules/network_security_group/main.tf new file mode 100644 index 0000000..c649652 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/network_security_group/main.tf @@ -0,0 +1,53 @@ +resource "azurerm_network_security_group" "example" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + tags = var.tags + + dynamic "security_rule" { + for_each = try(var.security_rules, []) + content { + name = try(security_rule.value.name, null) + priority = try(security_rule.value.priority, null) + direction = try(security_rule.value.direction, null) + access = try(security_rule.value.access, null) + protocol = try(security_rule.value.protocol, null) + source_port_range = try(security_rule.value.source_port_range, null) + source_port_ranges = try(security_rule.value.source_port_ranges, null) + destination_port_range = try(security_rule.value.destination_port_range, null) + destination_port_ranges = try(security_rule.value.destination_port_ranges, null) + source_address_prefix = try(security_rule.value.source_address_prefix, null) + source_address_prefixes = try(security_rule.value.source_address_prefixes, null) + destination_address_prefix = try(security_rule.value.destination_address_prefix, null) + destination_address_prefixes = try(security_rule.value.destination_address_prefixes, null) + source_application_security_group_ids = try(security_rule.value.source_application_security_group_ids, null) + destination_application_security_group_ids = try(security_rule.value.destination_application_security_group_ids, null) + } + } + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_subnet_network_security_group_association" "example" { + for_each = var.subnet_ids + subnet_id = each.value + network_security_group_id = azurerm_network_security_group.example.id +} + +resource "azurerm_monitor_diagnostic_setting" "settings" { + name = "DiagnosticsSettings" + target_resource_id = azurerm_network_security_group.example.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + enabled_log { + category = "NetworkSecurityGroupEvent" + } + + enabled_log { + category = "NetworkSecurityGroupRuleCounter" + } +} diff --git a/samples/web-app-custom-image/python/terraform/modules/network_security_group/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/network_security_group/outputs.tf new file mode 100644 index 0000000..b8ca8d5 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/network_security_group/outputs.tf @@ -0,0 +1,9 @@ +output "name" { + description = "Specifies the name of the network security group" + value = azurerm_network_security_group.example.name +} + +output "id" { + description = "Specifies the resource id of the network security group" + value = azurerm_network_security_group.example.id +} diff --git a/samples/web-app-custom-image/python/terraform/modules/network_security_group/variables.tf b/samples/web-app-custom-image/python/terraform/modules/network_security_group/variables.tf new file mode 100644 index 0000000..04eb07e --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/network_security_group/variables.tf @@ -0,0 +1,51 @@ +variable "name" { + description = "(Required) Specifies the name of the Azure Network Security Group" + type = string +} + +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group. of the Azure Network Security Group" + type = string +} + +variable "location" { + description = "(Required) Specifies the location of the Azure Network Security Group" + type = string +} + +variable "security_rules" { + description = "(Optional) Specifies the security rules of the Azure Network Security Group" + type = list(object({ + name = string + priority = number + direction = string + access = string + protocol = string + source_port_range = string + source_port_ranges = list(string) + destination_port_range = string + destination_port_ranges = list(string) + source_address_prefix = string + source_address_prefixes = list(string) + destination_address_prefix = string + destination_address_prefixes = list(string) + source_application_security_group_ids = list(string) + destination_application_security_group_ids = list(string) + })) + default = [] +} + +variable "subnet_ids" { + description = "(Required) A map of subnet ids to associate with the Azure Network Security Group" + type = map(string) +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure Network Security Group" + default = {} +} + +variable "log_analytics_workspace_id" { + description = "Specifies the resource id of the Azure Log Analytics workspace" + type = string +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/main.tf b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/main.tf new file mode 100644 index 0000000..393f9dc --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/main.tf @@ -0,0 +1,26 @@ +resource "azurerm_private_dns_zone" "example" { + name = var.name + resource_group_name = var.resource_group_name + tags = var.tags + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_private_dns_zone_virtual_network_link" "example" { + for_each = var.virtual_networks_to_link + + name = "link_to_${lower(basename(each.key))}" + resource_group_name = var.resource_group_name + private_dns_zone_name = azurerm_private_dns_zone.example.name + virtual_network_id = "/subscriptions/${each.value.subscription_id}/resourceGroups/${each.value.resource_group_name}/providers/Microsoft.Network/virtualNetworks/${each.key}" + + lifecycle { + ignore_changes = [ + tags + ] + } +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/outputs.tf new file mode 100644 index 0000000..ca141f3 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/outputs.tf @@ -0,0 +1,9 @@ +output "name" { + description = "Specifies the name of the private dns zone" + value = azurerm_private_dns_zone.example.name +} + +output "id" { + description = "Specifies the resource id of the private dns zone" + value = azurerm_private_dns_zone.example.id +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/variables.tf b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/variables.tf new file mode 100644 index 0000000..8d0c0cc --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_dns_zone/variables.tf @@ -0,0 +1,20 @@ +variable "name" { + description = "(Required) Specifies the name of the Azure Private DNS Zone" + type = string +} + +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group. of the Azure Private DNS Zone" + type = string +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure Private DNS Zone" + default = {} +} + +variable "virtual_networks_to_link" { + description = "(Optional) Specifies the subscription id, resource group name, and name of the virtual networks to which create a virtual network link" + type = map(any) + default = {} +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf new file mode 100644 index 0000000..62bfbfb --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf @@ -0,0 +1,26 @@ +resource "azurerm_private_endpoint" "example" { + name = var.name + location = var.location + resource_group_name = var.resource_group_name + subnet_id = var.subnet_id + tags = var.tags + + private_service_connection { + name = "${var.name}Connection" + private_connection_resource_id = var.private_connection_resource_id + is_manual_connection = var.is_manual_connection + subresource_names = try([var.subresource_name], null) + request_message = try(var.request_message, null) + } + + private_dns_zone_group { + name = var.private_dns_zone_group_name + private_dns_zone_ids = var.private_dns_zone_group_ids + } + + lifecycle { + ignore_changes = [ + tags + ] + } +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/outputs.tf new file mode 100644 index 0000000..367ab51 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/outputs.tf @@ -0,0 +1,19 @@ +output "name" { + description = "Specifies the name of the private endpoint." + value = azurerm_private_endpoint.example.name +} + +output "id" { + description = "Specifies the resource id of the private endpoint." + value = azurerm_private_endpoint.example.id +} + +output "private_dns_zone_group" { + description = "Specifies the private dns zone group of the private endpoint." + value = azurerm_private_endpoint.example.private_dns_zone_group +} + +output "private_dns_zone_configs" { + description = "Specifies the private dns zone(s) configuration" + value = azurerm_private_endpoint.example.private_dns_zone_configs +} diff --git a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf new file mode 100644 index 0000000..2b7a888 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf @@ -0,0 +1,61 @@ +variable "name" { + description = "(Required) Specifies the name of the Azure Private Endpoint. Changing this forces a new resource to be created." + type = string +} + +variable "resource_group_name" { + description = "(Required) The name of the resource group. Changing this forces a new resource to be created." + type = string +} + +variable "private_connection_resource_id" { + description = "(Required) Specifies the resource id of the private link service" + type = string +} + +variable "location" { + description = "(Required) Specifies the supported Azure location where the resource exists. Changing this forces a new resource to be created." + type = string +} + +variable "subnet_id" { + description = "(Required) Specifies the resource id of the subnet" + type = string +} + +variable "is_manual_connection" { + description = "(Optional) Specifies whether the Azure Private Endpoint connection requires manual approval from the remote resource owner." + type = string + default = false +} + +variable "subresource_name" { + description = "(Optional) Specifies a subresource name which the Azure Private Endpoint is able to connect to." + type = string + default = null +} + +variable "request_message" { + description = "(Optional) Specifies a message passed to the owner of the remote resource when the Azure Private Endpoint attempts to establish the connection to the remote resource." + type = string + default = null +} + +variable "private_dns_zone_group_name" { + description = "(Required) Specifies the Name of the Private DNS Zone Group. Changing this forces a new private_dns_zone_group resource to be created." + type = string +} + +variable "private_dns_zone_group_ids" { + description = "(Required) Specifies the list of Private DNS Zones to include within the private_dns_zone_group." + type = list(string) +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure Azure Private Endpoint." + default = {} +} + +variable "private_dns" { + default = {} +} diff --git a/samples/web-app-custom-image/python/terraform/modules/virtual_network/main.tf b/samples/web-app-custom-image/python/terraform/modules/virtual_network/main.tf new file mode 100644 index 0000000..cec00f4 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/virtual_network/main.tf @@ -0,0 +1,55 @@ +resource "azurerm_virtual_network" "example" { + name = var.vnet_name + address_space = var.address_space + location = var.location + resource_group_name = var.resource_group_name + tags = var.tags + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +resource "azurerm_subnet" "example" { + for_each = { for subnet in var.subnets : subnet.name => subnet if subnet != null } + + name = each.key + resource_group_name = var.resource_group_name + virtual_network_name = azurerm_virtual_network.example.name + address_prefixes = each.value.address_prefixes + private_endpoint_network_policies = each.value.private_endpoint_network_policies + private_link_service_network_policies_enabled = each.value.private_link_service_network_policies_enabled + + dynamic "delegation" { + for_each = each.value.delegation != null ? [each.value.delegation] : [] + content { + name = "delegation" + + service_delegation { + name = delegation.value + } + } + } + + lifecycle { + ignore_changes = [ + delegation + ] + } +} + +resource "azurerm_monitor_diagnostic_setting" "example" { + name = "DiagnosticsSettings" + target_resource_id = azurerm_virtual_network.example.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + enabled_log { + category = "VMProtectionAlerts" + } + + enabled_metric { + category = "AllMetrics" + } +} diff --git a/samples/web-app-custom-image/python/terraform/modules/virtual_network/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/virtual_network/outputs.tf new file mode 100644 index 0000000..b464308 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/virtual_network/outputs.tf @@ -0,0 +1,19 @@ +output "name" { + description = "Specifies the name of the virtual network" + value = azurerm_virtual_network.example.name +} + +output "vnet_id" { + description = "Specifies the resource id of the virtual network" + value = azurerm_virtual_network.example.id +} + +output "subnet_ids" { + description = "Contains a list of the the resource id of the subnets" + value = { for subnet in azurerm_subnet.example : subnet.name => subnet.id } +} + +output "subnet_ids_as_list" { + description = "Returns the list of the subnet ids as a list of strings." + value = [for subnet in azurerm_subnet.example : subnet.id] +} diff --git a/samples/web-app-custom-image/python/terraform/modules/virtual_network/variables.tf b/samples/web-app-custom-image/python/terraform/modules/virtual_network/variables.tf new file mode 100644 index 0000000..f8c0b0e --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/virtual_network/variables.tf @@ -0,0 +1,40 @@ +variable "resource_group_name" { + description = "Resource Group name" + type = string +} + +variable "location" { + description = "Location in which to deploy the network" + type = string +} + +variable "vnet_name" { + description = "VNET name" + type = string +} + +variable "address_space" { + description = "VNET address space" + type = list(string) +} + +variable "subnets" { + description = "Subnets configuration" + type = list(object({ + name = string + address_prefixes = list(string) + private_endpoint_network_policies = string + private_link_service_network_policies_enabled = bool + delegation = string + })) +} + +variable "tags" { + description = "(Optional) Specifies the tags of the Azure Virtual Network resource." + default = {} +} + +variable "log_analytics_workspace_id" { + description = "Specifies the resource id of the Azure Log Analytics workspace." + type = string +} diff --git a/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf b/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf new file mode 100644 index 0000000..04fc14d --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf @@ -0,0 +1,85 @@ +resource "azurerm_linux_web_app" "example" { + name = var.name + resource_group_name = var.resource_group_name + location = var.location + service_plan_id = var.service_plan_id + https_only = var.https_only + virtual_network_subnet_id = var.virtual_network_subnet_id + public_network_access_enabled = var.public_network_access_enabled + client_affinity_enabled = false + tags = var.tags + + identity { + type = "UserAssigned" + identity_ids = var.managed_identity_id != null ? [var.managed_identity_id] : [] + } + + site_config { + always_on = var.always_on + http2_enabled = var.http2_enabled + minimum_tls_version = var.minimum_tls_version + vnet_route_all_enabled = var.vnet_route_all_enabled + application_stack { + docker_image_name = "${var.image_name}:${var.image_tag}" + docker_registry_url = var.docker_registry_url + docker_registry_username = var.docker_registry_username + docker_registry_password = var.docker_registry_password + } + } + + app_settings = var.app_settings + + lifecycle { + ignore_changes = [ + tags + ] + } +} + +# Deploy code from a public GitHub repo +resource "azurerm_app_service_source_control" "example" { + count = var.repo_url == "" ? 0 : 1 + app_id = azurerm_linux_web_app.example.id + repo_url = var.repo_url + branch = var.repo_branch + use_manual_integration = true + use_mercurial = false +} + +resource "azurerm_monitor_diagnostic_setting" "example" { + name = "DiagnosticsSettings" + target_resource_id = azurerm_linux_web_app.example.id + log_analytics_workspace_id = var.log_analytics_workspace_id + + enabled_log { + category = "AppServiceHTTPLogs" + } + + enabled_log { + category = "AppServiceConsoleLogs" + } + + enabled_log { + category = "AppServiceAppLogs" + } + + enabled_log { + category = "AppServiceAuditLogs" + } + + enabled_log { + category = "AppServiceIPSecAuditLogs" + } + + enabled_log { + category = "AppServicePlatformLogs" + } + + enabled_log { + category = "AppServiceAuthenticationLogs" + } + + enabled_metric { + category = "AllMetrics" + } +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/web_app/outputs.tf b/samples/web-app-custom-image/python/terraform/modules/web_app/outputs.tf new file mode 100644 index 0000000..d7b6981 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/web_app/outputs.tf @@ -0,0 +1,24 @@ +output "id" { + value = azurerm_linux_web_app.example.id + description = "Specifies the resource id of the Web App" +} + +output "name" { + value = azurerm_linux_web_app.example.name + description = "Specifies the name of the Web App" +} + +output "default_hostname" { + value = azurerm_linux_web_app.example.default_hostname + description = "Specifies the default hostname of the Web App" +} + +output "outbound_ip_addresses" { + value = azurerm_linux_web_app.example.outbound_ip_addresses + description = "Specifies the outbound IP addresses of the Web App" +} + +output "principal_id" { + value = azurerm_linux_web_app.example.identity[0].principal_id + description = "Specifies the Principal ID of the System Assigned Managed Identity" +} diff --git a/samples/web-app-custom-image/python/terraform/modules/web_app/variables.tf b/samples/web-app-custom-image/python/terraform/modules/web_app/variables.tf new file mode 100644 index 0000000..be77f72 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/modules/web_app/variables.tf @@ -0,0 +1,126 @@ +variable "resource_group_name" { + description = "(Required) Specifies the name of the resource group." + type = string +} + +variable "location" { + description = "(Required) Specifies the location for the Web App." + type = string +} + +variable "name" { + description = "(Required) Specifies the name of the Web App." + type = string +} + +variable "service_plan_id" { + description = "(Required) Specifies the ID of the App Service Plan within which to create this Web App." + type = string +} + +variable "https_only" { + description = "(Optional) Specifies whether the Web App requires HTTPS connections." + type = bool + default = false +} + +variable "virtual_network_subnet_id" { + description = "(Optional) The subnet id which will be used by this Web App for regional virtual network integration." + type = string + default = null +} + +variable "vnet_route_all_enabled" { + description = "(Optional) Specifies whether to route all traffic from the Web App into the virtual network. This is only applicable if virtual_network_subnet_id is specified. Defaults to false." + type = bool + default = false +} + +variable "public_network_access_enabled" { + description = "(Optional) Specifies whether the public network access is enabled or disabled." + type = bool + default = true +} + +variable "always_on" { + description = "(Optional) Specifies whether the Web App is Always On enabled." + type = bool + default = true +} + +variable "http2_enabled" { + description = "(Optional) Specifies whether HTTP/2 is enabled for the Web App." + type = bool + default = false +} + +variable "minimum_tls_version" { + description = "(Optional) Specifies the minimum version of TLS required for SSL requests." + type = string + default = "1.2" +} + +variable "app_settings" { + description = "(Optional) A map of key-value pairs for App Settings." + type = map(string) + default = {} +} + +variable "repo_url" { + description = "(Optional) Specifies the Git repository URL." + type = string + default = "" +} + +variable "repo_branch" { + description = "(Optional) Specifies the Git repository branch." + type = string + default = "main" +} + +variable "tags" { + description = "(Optional) Specifies the tags to be applied to the resources." + type = map(any) + default = {} +} + +variable "log_analytics_workspace_id" { + description = "Specifies the resource id of the Azure Log Analytics workspace." + type = string +} + +variable "image_name" { + description = "(Required) Specifies the name of the container image to deploy to the Web App." + type = string + default = "custom-image-webapp" +} + +variable "image_tag" { + description = "(Required) Specifies the tag of the container image to deploy to the Web App." + type = string + default = "v1" +} + +variable "docker_registry_url" { + description = "(Optional) Specifies the URL of the Docker registry where the container image is stored. This is required if the container image is stored in a private registry." + type = string + default = null +} + +variable "managed_identity_id" { + description = "(Optional) Specifies the ID of the user-assigned managed identity to be assigned to the Web App." + type = string + default = null +} + +variable "docker_registry_username" { + description = "Specifies the username of the Docker registry. This is required if the container image is stored in a private registry." + type = string + default = null +} + +variable "docker_registry_password" { + description = "Specifies the password of the Docker registry. This is required if the container image is stored in a private registry." + type = string + default = null +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/outputs.tf b/samples/web-app-custom-image/python/terraform/outputs.tf new file mode 100644 index 0000000..a4d9b25 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/outputs.tf @@ -0,0 +1,23 @@ +output "resource_group_name" { + value = local.resource_group_name +} + +output "container_registry_name" { + value = module.container_registry.name +} + +output "container_registry_login_server" { + value = module.container_registry.login_server +} + +output "app_service_plan_name" { + value = module.app_service_plan.name +} + +output "web_app_name" { + value = module.web_app.name +} + +output "web_app_url" { + value = module.web_app.default_hostname +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/providers.tf b/samples/web-app-custom-image/python/terraform/providers.tf new file mode 100644 index 0000000..e9f72ea --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/providers.tf @@ -0,0 +1,28 @@ +terraform { + required_providers { + azurerm = { + source = "hashicorp/azurerm" + version = "=4.60.0" + } + null = { + source = "hashicorp/null" + version = "~> 3.0" + } + } +} + +provider "azurerm" { + features { + resource_group { + prevent_deletion_if_contains_resources = false + } + } + + # Set the hostname of the Azure Metadata Service (for example management.azure.com) + # used to obtain the Cloud Environment when using LocalStack's Azure emulator. + # This allows the provider to correctly identify the environment and avoid making calls to the real Azure endpoints. + metadata_host = "localhost.localstack.cloud:4566" + + # Set the subscription ID to a dummy value when using LocalStack's Azure emulator. + subscription_id = "00000000-0000-0000-0000-000000000000" +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/push_image.sh b/samples/web-app-custom-image/python/terraform/push_image.sh new file mode 100755 index 0000000..a86add2 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/push_image.sh @@ -0,0 +1,44 @@ +#!/bin/bash + +LOCAL_IMAGE="${IMAGE_NAME}:${IMAGE_TAG}" +FULL_IMAGE="${ACR_LOGIN_SERVER}/${IMAGE_NAME}:${IMAGE_TAG}" + +echo "Logging into Azure Container Registry [$ACR_NAME]..." +az acr login --name "$ACR_NAME" --only-show-errors + +if [ $? -eq 0 ]; then + echo "Logged into Azure Container Registry [$ACR_NAME] successfully." +else + echo "Failed to log into Azure Container Registry [$ACR_NAME]." + exit 1 +fi + +echo "Building custom Docker image [$LOCAL_IMAGE]..." +docker build -t "$LOCAL_IMAGE" ../src/ + +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] built successfully." +else + echo "Failed to build Docker image [$LOCAL_IMAGE]." + exit 1 +fi + +echo "Tagging Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]..." +docker tag "$LOCAL_IMAGE" "$FULL_IMAGE" + +if [ $? -eq 0 ]; then + echo "Docker image [$LOCAL_IMAGE] tagged as [$FULL_IMAGE] successfully." +else + echo "Failed to tag Docker image [$LOCAL_IMAGE] as [$FULL_IMAGE]." + exit 1 +fi + +echo "Pushing image [$FULL_IMAGE] to ACR..." +docker push "$FULL_IMAGE" + +if [ $? -eq 0 ]; then + echo "Docker image [$FULL_IMAGE] pushed to ACR successfully." +else + echo "Failed to push Docker image [$FULL_IMAGE] to ACR." + exit 1 +fi \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/terraform.tfvars b/samples/web-app-custom-image/python/terraform/terraform.tfvars new file mode 100644 index 0000000..919af4f --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/terraform.tfvars @@ -0,0 +1,3 @@ +prefix = "local" +suffix = "test" +location = "westeurope" \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/variables.tf b/samples/web-app-custom-image/python/terraform/variables.tf new file mode 100644 index 0000000..598df33 --- /dev/null +++ b/samples/web-app-custom-image/python/terraform/variables.tf @@ -0,0 +1,280 @@ +variable "prefix" { + description = "(Optional) Specifies the prefix for the name of the Azure resources." + type = string + default = "local" + + validation { + condition = var.prefix == null || length(var.prefix) >= 2 + error_message = "The prefix must be at least 2 characters long." + } +} + +variable "suffix" { + description = "(Optional) Specifies the suffix for the name of the Azure resources." + type = string + default = "test" + + validation { + condition = var.suffix == null || length(var.suffix) >= 2 + error_message = "The suffix must be at least 2 characters long." + } +} + +variable "location" { + description = "(Required) Specifies the location for all resources." + type = string + default = "westeurope" +} + +variable "acr_sku" { + description = "Specifies the name of the container registry" + type = string + default = "Premium" + + validation { + condition = contains(["Basic", "Standard", "Premium"], var.acr_sku) + error_message = "The container registry sku is invalid." + } +} + +variable "acr_admin_enabled" { + description = "Specifies whether admin is enabled for the container registry" + type = bool + default = true +} + +variable "acr_georeplication_locations" { + description = "(Optional) A list of Azure locations where the container registry should be geo-replicated." + type = list(string) + default = [] +} + +variable "os_type" { + description = "(Required) Specifies the O/S type for the App Services to be hosted in this plan. Possible values include Windows, Linux, and WindowsContainer. Changing this forces a new resource to be created." + type = string + default = "Linux" + + validation { + condition = contains([ + "Windows", + "Linux", + "WindowsContainer" + ], var.os_type) + error_message = "The os_type must be either 'Windows', 'Linux', or 'WindowsContainer'." + } +} + +variable "zone_balancing_enabled" { + description = "(Optional) Should the Service Plan balance across Availability Zones in the region." + type = bool + default = false +} + +variable "sku_tier" { + description = "(Optional) Specifies the tier name for the hosting plan." + type = string + default = "Standard" + + validation { + condition = contains([ + "Basic", + "Standard", + "ElasticPremium", + "Premium", + "PremiumV2", + "Premium0V3", + "PremiumV3", + "PremiumMV3", + "Isolated", + "IsolatedV2", + "WorkflowStandard", + "FlexConsumption" + ], var.sku_tier) + error_message = "The sku_tier must be one of the allowed values." + } +} +variable "sku_name" { + description = "(Optional) Specifies the SKU name for the hosting plan." + type = string + default = "S1" + + validation { + condition = contains([ + "B1", "B2", "B3", + "S1", "S2", "S3", + "EP1", "EP2", "EP3", + "P1", "P2", "P3", + "P1V2", "P2V2", "P3V2", + "P0V3", "P1V3", "P2V3", "P3V3", + "P1MV3", "P2MV3", "P3MV3", "P4MV3", "P5MV3", + "I1", "I2", "I3", + "I1V2", "I2V2", "I3V2", "I4V2", "I5V2", "I6V2", + "WS1", "WS2", "WS3", + "FC1" + ], var.sku_name) + error_message = "The sku_name must be one of the allowed values." + } +} + +variable "python_version" { + description = "(Optional) Specifies the version of Python to run. Possible values include 3.13, 3.12, 3.11, 3.10, 3.9, 3.8 and 3.7." + type = string + default = "3.12" + + validation { + condition = contains([ + "3.13", + "3.12", + "3.11", + "3.10", + "3.9", + "3.8", + "3.7" + ], var.python_version) + error_message = "The python_version must be one of the supported versions: 3.13, 3.12, 3.11, 3.10, 3.9, 3.8, 3.7." + } +} + +variable "https_only" { + description = "(Optional) Specifies whether the Linux Web App require HTTPS connections. Defaults to false." + type = bool + default = false +} + +variable "minimum_tls_version" { + description = "(Optional) Specifies the minimum version of TLS required for SSL requests. Possible values include: 1.0, 1.1, 1.2 and 1.3. Defaults to 1.2." + type = string + default = "1.2" + + validation { + condition = contains([ + "1.0", + "1.1", + "1.2", + "1.3" + ], var.minimum_tls_version) + error_message = "The minimum_tls_version must be one of the allowed values." + } +} + +variable "always_on" { + description = "(Optional) Specifies whether the Linux Web App is Always On enabled. Defaults to true." + type = bool + default = true +} + +variable "http2_enabled" { + description = "(Optional) Specifies whether HTTP/2 is enabled for the Linux Web App." + type = bool + default = false +} + +variable "public_network_access_enabled" { + description = "(Optional) Specifies whether the public network access is enabled or disabled." + type = bool + default = true +} + +variable "repo_url" { + description = "(Optional) Specifies the Git repository URL." + type = string + default = "" + + validation { + condition = var.repo_url == "" || can(regex("^https?://", var.repo_url)) + error_message = "The repo_url must be empty or a valid HTTP/HTTPS URL." + } +} + +variable "login_name" { + description = "(Required) Specifies the login name for the application." + type = string + default = "paolo" +} + +variable "tags" { + description = "(Optional) Specifies the tags to be applied to the resources." + type = map(string) + default = { + environment = "test" + iac = "terraform" + } +} + +variable "vnet_name" { + description = "Specifies the name of the virtual network." + default = "VNet" + type = string +} + +variable "vnet_address_space" { + description = "Specifies the address space of the virtual network." + default = ["10.0.0.0/8"] + type = list(string) +} + +variable "webapp_subnet_name" { + description = "Specifies the name of the web app subnet." + default = "app-subnet" + type = string +} + +variable "webapp_subnet_address_prefix" { + description = "Specifies the address prefix of the web app subnet." + default = ["10.0.0.0/24"] + type = list(string) +} + +variable "pe_subnet_name" { + description = "Specifies the name of the subnet that contains the private endpoints." + default = "pe-subnet" + type = string +} + +variable "pe_subnet_address_prefix" { + description = "Specifies the address prefix of the subnet that contains the private endpoints." + default = ["10.0.1.0/24"] + type = list(string) +} + +variable "nat_gateway_name" { + description = "(Required) Specifies the name of the NAT Gateway" + type = string + default = "NatGateway" +} + +variable "nat_gateway_sku_name" { + description = "(Optional) The SKU which should be used. At this time the only supported value is Standard. Defaults to Standard" + type = string + default = "Standard" +} + +variable "nat_gateway_idle_timeout_in_minutes" { + description = "(Optional) The idle timeout which should be used in minutes. Defaults to 4." + type = number + default = 4 +} + +variable "nat_gateway_zones" { + description = " (Optional) A list of Availability Zones in which this NAT Gateway should be located. Changing this forces a new NAT Gateway to be created." + type = list(string) + default = ["1"] +} + +variable "websites_port" { + description = "(Optional) Specifies the port on which the Web App will listen. Defaults to 8000." + type = number + default = 80 +} + +variable "image_name" { + description = "(Required) Specifies the name of the container image to deploy to the Web App." + type = string + default = "custom-image-webapp" +} + +variable "image_tag" { + description = "(Required) Specifies the tag of the container image to deploy to the Web App." + type = string + default = "v1" +} \ No newline at end of file diff --git a/samples/web-app-custom-image/python/visio/web-app-custom-image.vsdx b/samples/web-app-custom-image/python/visio/web-app-custom-image.vsdx new file mode 100644 index 0000000000000000000000000000000000000000..bd6c655ca337c56a27d0a12b184aefebad4e23b9 GIT binary patch literal 259502 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�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 j0o3b}nt-M*4Z!%-N&d Date: Fri, 8 May 2026 09:53:14 +0200 Subject: [PATCH 2/7] Changed README --- samples/web-app-custom-image/python/scripts/README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/web-app-custom-image/python/scripts/README.md b/samples/web-app-custom-image/python/scripts/README.md index 7120446..9d2eda8 100644 --- a/samples/web-app-custom-image/python/scripts/README.md +++ b/samples/web-app-custom-image/python/scripts/README.md @@ -10,7 +10,6 @@ Before deploying this solution, ensure you have the following tools installed: - [Docker](https://docs.docker.com/get-docker/): Container runtime required for LocalStack and building the custom image - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli): Azure command-line interface - [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper -- [Python](https://www.python.org/downloads/): Python runtime (version 3.12 or above) - [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs ### Installing azlocal CLI From 710248236ff6ed3a0db384a76a943d6d5a44f132 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 8 May 2026 08:01:26 +0000 Subject: [PATCH 3/7] Fix admin_enabled variable type from string to bool in container_registry module Agent-Logs-Url: https://github.com/localstack/localstack-azure-samples/sessions/f4b9445e-0f95-4086-99a6-d7fc7d8e5026 Co-authored-by: paolosalvatori <1658419+paolosalvatori@users.noreply.github.com> --- .../python/terraform/modules/container_registry/variables.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf b/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf index 50429a5..c3fc7cc 100644 --- a/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf +++ b/samples/web-app-custom-image/python/terraform/modules/container_registry/variables.tf @@ -15,7 +15,7 @@ variable "location" { variable "admin_enabled" { description = "(Optional) Specifies whether the admin user is enabled. Defaults to false." - type = string + type = bool default = false } From 88058dd863651e60eeabb5cdbe08bc408299b789 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 8 May 2026 08:04:03 +0000 Subject: [PATCH 4/7] Fix Terraform type mismatches, broken README link, and undefined variable Agent-Logs-Url: https://github.com/localstack/localstack-azure-samples/sessions/406e9650-f8ef-48d0-875c-d862428b657f Co-authored-by: paolosalvatori <1658419+paolosalvatori@users.noreply.github.com> --- samples/web-app-custom-image/python/README.md | 3 ++- samples/web-app-custom-image/python/scripts/deploy.sh | 3 +-- .../python/terraform/modules/log_analytics/main.tf | 2 +- .../python/terraform/modules/private_endpoint/main.tf | 2 +- .../python/terraform/modules/private_endpoint/variables.tf | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/samples/web-app-custom-image/python/README.md b/samples/web-app-custom-image/python/README.md index 053c2d1..389054c 100644 --- a/samples/web-app-custom-image/python/README.md +++ b/samples/web-app-custom-image/python/README.md @@ -28,7 +28,8 @@ The solution is composed of the following Azure resources: - [Azure Subscription](https://azure.microsoft.com/free/) - [Azure CLI](https://learn.microsoft.com/en-us/cli/azure/install-azure-cli) -- [Docker](https://docs.docker.com/get-docker/)udio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep. +- [Docker](https://docs.docker.com/get-docker/) +- [Bicep](https://marketplace.visualstudio.com/items?itemName=ms-azuretools.vscode-bicep), if you plan to install the sample via Bicep. - [Terraform](https://developer.hashicorp.com/terraform/downloads), if you plan to install the sample via Terraform. - [Azlocal CLI](https://azure.localstack.cloud/user-guides/sdks/az/): LocalStack Azure CLI wrapper - [jq](https://jqlang.org/): JSON processor for scripting and parsing command outputs diff --git a/samples/web-app-custom-image/python/scripts/deploy.sh b/samples/web-app-custom-image/python/scripts/deploy.sh index 4ba852d..fbd7ada 100755 --- a/samples/web-app-custom-image/python/scripts/deploy.sh +++ b/samples/web-app-custom-image/python/scripts/deploy.sh @@ -168,8 +168,7 @@ if [[ $? != 0 ]]; then az identity create \ --name "$MANAGED_IDENTITY_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ - --location "$LOCATION" \ - --subscription "$SUBSCRIPTION_ID" 1>/dev/null + --location "$LOCATION" 1>/dev/null if [[ $? == 0 ]]; then echo "[$MANAGED_IDENTITY_NAME] user-assigned managed identity successfully created in the [$RESOURCE_GROUP_NAME] resource group" diff --git a/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf b/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf index 2f88414..fcd4398 100644 --- a/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf +++ b/samples/web-app-custom-image/python/terraform/modules/log_analytics/main.tf @@ -4,7 +4,7 @@ resource "azurerm_log_analytics_workspace" "example" { resource_group_name = var.resource_group_name sku = var.sku tags = var.tags - retention_in_days = var.retention_in_days != "" ? var.retention_in_days : null + retention_in_days = var.retention_in_days != null ? var.retention_in_days : null lifecycle { ignore_changes = [ diff --git a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf index 62bfbfb..b21566e 100644 --- a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf +++ b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/main.tf @@ -9,7 +9,7 @@ resource "azurerm_private_endpoint" "example" { name = "${var.name}Connection" private_connection_resource_id = var.private_connection_resource_id is_manual_connection = var.is_manual_connection - subresource_names = try([var.subresource_name], null) + subresource_names = var.subresource_name != null ? [var.subresource_name] : null request_message = try(var.request_message, null) } diff --git a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf index 2b7a888..ca1cde1 100644 --- a/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf +++ b/samples/web-app-custom-image/python/terraform/modules/private_endpoint/variables.tf @@ -25,7 +25,7 @@ variable "subnet_id" { variable "is_manual_connection" { description = "(Optional) Specifies whether the Azure Private Endpoint connection requires manual approval from the remote resource owner." - type = string + type = bool default = false } From 3729841e97e78d9fc6c4efdf3c409c673b8661ba Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 8 May 2026 08:07:16 +0000 Subject: [PATCH 5/7] Fix identity block and NAT gateway prefix length documentation Agent-Logs-Url: https://github.com/localstack/localstack-azure-samples/sessions/e100db37-5dea-4c4e-a4aa-4aad5ef381bd Co-authored-by: paolosalvatori <1658419+paolosalvatori@users.noreply.github.com> --- .../python/terraform/modules/nat_gateway/variables.tf | 2 +- .../python/terraform/modules/web_app/main.tf | 9 ++++++--- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf index b66d7ef..a6b8e69 100644 --- a/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf +++ b/samples/web-app-custom-image/python/terraform/modules/nat_gateway/variables.tf @@ -49,7 +49,7 @@ variable "public_ip_prefix_name" { } variable "public_ip_prefix_length" { - description = "(Required) The length of the public IP prefix to create and associate with the NAT Gateway. Must be between 28 and 30." + description = "(Required) The length of the public IP prefix to create and associate with the NAT Gateway. Must be between 28 and 31." type = number default = 31 } \ No newline at end of file diff --git a/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf b/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf index 04fc14d..ad2ec1a 100644 --- a/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf +++ b/samples/web-app-custom-image/python/terraform/modules/web_app/main.tf @@ -9,9 +9,12 @@ resource "azurerm_linux_web_app" "example" { client_affinity_enabled = false tags = var.tags - identity { - type = "UserAssigned" - identity_ids = var.managed_identity_id != null ? [var.managed_identity_id] : [] + dynamic "identity" { + for_each = var.managed_identity_id != null ? [1] : [] + content { + type = "UserAssigned" + identity_ids = [var.managed_identity_id] + } } site_config { From df1105ec1ad1091f8236f1e9eb9acde71b7ef835 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 8 May 2026 12:32:45 +0200 Subject: [PATCH 6/7] Fixed script --- .../web-app-cosmosdb-mongodb-api/python/scripts/call-web-app.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/web-app-cosmosdb-mongodb-api/python/scripts/call-web-app.sh b/samples/web-app-cosmosdb-mongodb-api/python/scripts/call-web-app.sh index 5f79052..075a3b4 100755 --- a/samples/web-app-cosmosdb-mongodb-api/python/scripts/call-web-app.sh +++ b/samples/web-app-cosmosdb-mongodb-api/python/scripts/call-web-app.sh @@ -133,7 +133,6 @@ call_web_app() { echo "Mapped host port [$host_port] retrieved successfully for container [$container_name]" else echo "Failed to get mapped host port for container [$container_name]" - exit 1 fi # Retrieve LocalStack proxy port From 6e58a694a27d6c7bfa86c68dab1a6244513b7103 Mon Sep 17 00:00:00 2001 From: Paolo Salvatori Date: Fri, 8 May 2026 12:52:16 +0200 Subject: [PATCH 7/7] Add retries to Azure Functions Core Tools installation --- .github/workflows/run-samples.yml | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/.github/workflows/run-samples.yml b/.github/workflows/run-samples.yml index 1504ae2..0f32806 100644 --- a/.github/workflows/run-samples.yml +++ b/.github/workflows/run-samples.yml @@ -157,7 +157,20 @@ jobs: - name: Install Azure Functions Core Tools # Required for publishing function app samples to the emulator. - run: npm install -g azure-functions-core-tools@4 --unsafe-perm true + run: | + MAX_RETRIES=3 + DELAY=15 + for i in $(seq 1 $MAX_RETRIES); do + echo "Attempt $i/$MAX_RETRIES..." + npm install -g azure-functions-core-tools@4 --unsafe-perm true && break + if [ "$i" -eq "$MAX_RETRIES" ]; then + echo "All $MAX_RETRIES attempts failed" + exit 1 + fi + echo "Retrying in ${DELAY}s..." + sleep $DELAY + DELAY=$((DELAY * 2)) + done - name: Install MSSQL ODBC and Tools # Required for the 'web-app-sql-database' sample which uses 'sqlcmd' to