| title | Deploy a Python web app container to Azure App Service | ||||
|---|---|---|---|---|---|
| description | How to deploy a Python web app container (Django or Flask) to App Service using managed identity authentication with Azure Container Registry. | ||||
| ms.devlang | python | ||||
| ms.topic | tutorial | ||||
| ms.date | 04/10/2025 | ||||
| ms.custom |
|
In this part of the tutorial series, you learn how to deploy a containerized Python web application to Azure App Service Web App for Containers. This fully managed service lets you run containerized apps without having to maintain your own container orchestrator.
App Service simplifies deployment through continuous integration/continuous deployment (CI/CD) pipelines that work with Docker Hub, Azure Container Registry, Azure Key Vault, and other DevOps tools. This tutorial is part 4 of a 5-part tutorial series.
At the end of this article, you have a secure, production-ready App Service web app running from a Docker container image. The app uses a system-assigned managed identity to pull the image from Azure Container Registry and retrieve secrets from Azure Key Vault.
This service diagram highlights the components covered in this article.
:::image type="content" source="./media/tutorial-container-web-app/containerization-of-python-apps-deploy.png" alt-text="A screenshot of the services using in the Tutorial - Containerized Python App on Azure with deployment path highlighted." lightbox="./media/tutorial-container-web-app/containerization-of-python-apps-deploy.png" :::
Azure CLI commands can be run in the Azure Cloud Shell or on a local machine with the Azure CLI installed.
Important
We recommend using Azure Cloud Shell for all CLI-based steps in this tutorial because it:
- Comes pre-authenticated with your Azure account, avoiding login issues
- Includes all required Azure CLI extensions out of the box
- Ensures consistent behavior regardless of your local OS or environment
- Requires no local installation, ideal for users without admin rights
- Provides direct access to Azure services from the portal—no local Docker or network setup required
- Avoids local firewall or network configuration issues
Azure Key Vault is a secure service for storing secrets, API keys, connection strings, and certificates. In this script, it stores the MongoDB connection string and the web app’s SECRET_KEY.
The Key Vault is configured to use role-based access control (RBAC) to manage access through Azure roles instead of traditional access policies. The web app uses its system-assigned managed identity to retrieve secrets securely at runtime.
Note
Creating the Key Vault early ensures that roles can be assigned before any attempt to access secrets. It also helps avoid propagation delays in role assignments. Since Key Vault doesn’t depend on the App Service, provisioning it early improves reliability and sequencing.
-
In this step, you use the az keyvault create command to create an Azure Key Vault with RBAC enabled.
#!/bin/bash RESOURCE_GROUP_NAME="msdocs-web-app-rg" LOCATION="westus" KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv" az keyvault create \ --name "$KEYVAULT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --location "$LOCATION" \ --enable-rbac-authorization true# PowerShell syntax $RESOURCE_GROUP_NAME="msdocs-web-app-rg" $LOCATION="westus" $KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv" az keyvault create ` --name "$KEYVAULT_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --location "$LOCATION" ` --enable-rbac-authorization true
The App Service Plan defines the compute resources, pricing tier, and region for your web app. The web app runs your containerized application and is provisioned with a system-assigned managed identity that is used to securely authenticate to Azure Container Registry (ACR) and Azure Key Vault.
In this step, you perform the following tasks:
- Create an App Service Plan
- Create the web app with its managed identity
- Configure the web app to deploy using a specific container image
- Prepare for continuous deployment via ACR
Note
The web app must be created before assigning access to ACR or Key Vault because the managed identity is only created at deployment time. Also, assigning the container image during creation ensures the app starts up correctly with the intended configuration.
-
In this step, you use the az appservice plan create command to provision the compute environment for your app.
#!/bin/bash APP_SERVICE_PLAN_NAME="msdocs-web-app-plan" az appservice plan create \ --name "$APP_SERVICE_PLAN_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --sku B1 \ --is-linux# PowerShell syntax $APP_SERVICE_PLAN_NAME="msdocs-web-app-plan" az appservice plan create ` --name "$APP_SERVICE_PLAN_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --sku B1 ` --is-linux
-
In this step, you use the az webapp create command to create the web app. This command also enables a system-assigned managed identity and sets the container image that the app runs.
#!/bin/bash APP_SERVICE_NAME="msdocs-website-name" #APP_SERVICE_NAME must be globally unique as it becomes the website name in the URL `https://<website-name>.azurewebsites.net`. # Use the same registry name as in part 2 of this tutorial series. REGISTRY_NAME="msdocscontainerregistryname" #REGISTRY_NAME is the registry name you used in part 2 of this tutorial. CONTAINER_NAME="$REGISTRY_NAME.azurecr.io/msdocspythoncontainerwebapp:latest" #CONTAINER_NAME is of the form "yourregistryname.azurecr.io/repo_name:tag". az webapp create \ --resource-group "$RESOURCE_GROUP_NAME" \ --plan "$APP_SERVICE_PLAN_NAME" \ --name "$APP_SERVICE_NAME" \ --assign-identity '[system]' \ --deployment-container-image-name "$CONTAINER_NAME"# Powershell syntax $APP_SERVICE_NAME="msdocs-website-name" # Use the same rregistry name as in part 2 of this tutorial series. $REGISTRY_NAME="msdocscontainerregistryname" $CONTAINER_NAME = "$REGISTRY_NAME.azurecr.io/msdocspythoncontainerwebapp:latest" az webapp create ` --resource-group "$RESOURCE_GROUP_NAME" ` --plan "$APP_SERVICE_PLAN_NAME" ` --name "$APP_SERVICE_NAME" ` --assign-identity '[system]' ` --deployment-container-image-name "$CONTAINER_NAME"
[!NOTE] When running this command, you may see the following error:
No credential was provided to access Azure Container Registry. Trying to look up... Retrieving credentials failed with an exception:'Failed to retrieve container registry credentials. Please either provide the credentials or run 'az acr update -n msdocscontainerregistryname --admin-enabled true' to enable admin first.'This error occurs because the web app tries to use admin credentials to access ACR, which credentials are disabled by default. It's safe to ignore this message: the next step configures the web app to use its managed identity to authenticate with ACR.
To store secrets in Azure Key Vault, the user running the script must have the Key Vault Secrets Officer role. This role allows creating and managing secrets within the vault.
In this step, the script assigns that role to the currently logged-in user. This user can then securely store application secrets, such as the MongoDB connection string and the app’s SECRET_KEY.
This role assignment is the first of two Key Vault–related role assignments. Later, the web app’s system-assigned managed identity is granted access to retrieve secrets from the vault.
Using Azure RBAC ensures secure, auditable access based on identity, eliminating the need for hard-coded credentials.
Note
The user must be assigned the Key Vault Secrets Officer role before before attempting to store any secrets in the key vault. This assignment is done using the az role assignment create command scoped to the Key Vault.
-
In this step, you use the az role assignment create command to assign the role at the Key Vault scope.
#!/bin/bash CALLER_ID=$(az ad signed-in-user show --query id -o tsv) echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully. az role assignment create \ --role "Key Vault Secrets Officer" \ --assignee "$CALLER_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"# PowerShell syntax $CALLER_ID=$(az ad signed-in-user show --query id -o tsv) echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully. az role assignment create ` --role "Key Vault Secrets Officer" ` --assignee "$CALLER_ID" ` --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
To pull images from Azure Container Registry (ACR) securely, the web app must be configured to use its system-assigned managed identity. Using managed identity avoids the need for admin credentials and supports secure, credential-free deployment.
This process involves two key actions:
- Enabling the web app to use its managed identity when accessing ACR
- Assigning the AcrPull role to that identity on the target ACR
-
In this step, you retrieve the principal ID (unique object ID) of the web app’s managed identity using the az webapp identity show command. Next, you enable the use of the managed identity for ACR authentication by setting the
acrUseManagedIdentityCredsproperty totrueusing az webapp config set. You then assign the AcrPull role to the web app’s managed identity using the az role assignment create command. This role grants the web app permission to pull images from the registry.#!/bin/bash PRINCIPAL_ID=$(az webapp identity show \ --name "$APP_SERVICE_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query principalId \ -o tsv) echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful 'AcrPull' role assignment using `az role assignment list`. az webapp config set \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --generic-configurations '{"acrUseManagedIdentityCreds": true}' az role assignment create \ --role "AcrPull" \ --assignee "$PRINCIPAL_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.ContainerRegistry/registries/$REGISTRY_NAME"# PowerShell syntax $PRINCIPAL_ID=$(az webapp identity show ` --name "$APP_SERVICE_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --query principalId ` -o tsv) echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful AcrPull role assignment using `az role assignment list`. az webapp config set ` --resource-group "$RESOURCE_GROUP_NAME" ` --name "$APP_SERVICE_NAME" ` --generic-configurations '{ "acrUseManagedIdentityCreds": true }' az role assignment create ` --role "AcrPull" ` --assignee "$PRINCIPAL_ID" ` --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.ContainerRegistry/registries/$REGISTRY_NAME"
The web app needs permission to access secrets like the MongoDB connection string and the SECRET_KEY. To grant these permissions, you must assign the Key Vault Secrets User role to the web app’s system-assigned managed identity.
-
In this step, you use the unique identifier (principal ID) of the web app’s system-assigned managed identity to grant the web app access to the Key Vault with the Key Vault Secrets User role using the az role assignment create command.
#!/bin/bash az role assignment create \ --role "Key Vault Secrets User" \ --assignee "$PRINCIPAL_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"# PowerShell syntax az role assignment create ` --role "Key Vault Secrets User" ` --assignee "$PRINCIPAL_ID"` --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
To avoid hardcoding secrets in your application, this step stores the MongoDB connection string and the web app’s secret key in Azure Key Vault. These secrets can then be securely accessed by the web app at runtime through its managed identity, without the need to store credentials in code or configuration.
Note
While this tutorial stores only the connection string and secret key in the key vault, you can optionally store other application settings such as the MongoDB database name or collection name in Key Vault as well.
-
In this step, you use the az cosmosdb keys list command to retrieve the MongoDB connection string. You then use the az keyvault secret set command to store both the connection string and a randomly generated secret key in Key Vault.
#!/bin/bash ACCOUNT_NAME="msdocs-cosmos-db-account-name" MONGO_CONNECTION_STRING=$(az cosmosdb keys list \ --name "$ACCOUNT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --type connection-strings \ --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" -o tsv) SECRET_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9') # This key is cryptographically secure, using OpenSSL’s strong random number generator. az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoConnectionString" \ --value "$MONGO_CONNECTION_STRING" az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoSecretKey" \ --value "$SECRET_KEY"# PowerShell syntax $ACCOUNT_NAME="msdocs-cosmos-db-account-name" $MONGO_CONNECTION_STRING = az cosmosdb keys list ` --name $ACCOUNT_NAME ` --resource-group $RESOURCE_GROUP_NAME ` --type connection-strings ` --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" ` -o tsv # Generate a 32-byte cryptographically secure random value $bytes = New-Object 'Byte[]' 32 [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes) # Convert to base64 and filter to alphanumeric characters only $base64 = [Convert]::ToBase64String($bytes) $alphanumeric = $base64 -replace '[^a-zA-Z0-9]', '' # Truncate to 50 characters $SECRET_KEY = $alphanumeric.Substring(0, [Math]::Min(50, $alphanumeric.Length)) az keyvault secret set ` --vault-name "$KEYVAULT_NAME" ` --name "MongoConnectionString" ` --value "$MONGO_CONNECTION_STRING" az keyvault secret set ` --vault-name "$KEYVAULT_NAME" ` --name "MongoSecretKey" ` --value "$SECRET_KEY"
To access secrets securely at runtime, the web app must be configured to reference the secrets stored in Azure Key Vault. This step is done using Key Vault references, which inject the secret values into the app’s environment through its system-assigned managed identity.
This approach avoids hardcoding secrets and allows the app to securely retrieve sensitive values like the MongoDB connection string and secret key during execution.
-
In this step, you use the az webapp config appsettings set command to add application settings that reference the Key Vault secrets. Specifically, this sets the
MongoConnectionStringandMongoSecretKeyapp settings to reference the corresponding secrets stored in Key Vault.#!/bin/bash MONGODB_NAME="restaurants_reviews" MONGODB_COLLECTION_NAME="restaurants_reviews" az webapp config appsettings set \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --settings \ CONNECTION_STRING="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoConnectionString)" \ SECRET_KEY="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoSecretKey)" \ DB_NAME="$MONGODB_NAME" \ COLLECTION_NAME="$MONGODB_COLLECTION_NAME"# PowerShell syntax $MONGO_DB_NAME="restaurants_reviews" $MONGO_COLLECTION_NAME="restaurants_reviews" az webapp config appsettings set ` --resource-group $RESOURCE_GROUP_NAME ` --name $APP_SERVICE_NAME ` --settings ` CONNECTION_STRING="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoConnectionString)" ` SECRET_KEY="@Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoSecretKey)" ` DB_NAME=$MONGODB_NAME ` COLLECTION_NAME=$MONGODB_COLLECTION_NAME
Enabling continuous deployment allows the web app to automatically pull and run the latest container image whenever one is pushed to Azure Container Registry (ACR). This reduces manual deployment steps and helps ensure your app stays up to date.
Note
In the next step, you'll register a webhook in ACR to notify the web app when a new image is pushed.
-
In this step, you use the az webapp deployment container config command to enable continuous deployment from ACR to the web app.
#!/bin/bash az webapp deployment container config \ --name "$APP_SERVICE_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --enable-cd true# PowerShell syntax az webapp deployment container config ` --name "$APP_SERVICE_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --enable-cd true
To automate deployments, register a webhook in Azure Container Registry (ACR) that notifies the web app whenever a new container image is pushed. The webhook allows the app to automatically pull and run the latest version.
The webhook configured in Azure Container Registry (ACR) sends a POST request to the web app’s SCM endpoint (SERVICE_URI) whenever a new image is pushed to the msdocspythoncontainerwebapp repository. This action triggers the web app to pull and deploy the updated image, completing the continuous deployment pipeline between ACR and Azure App Service.
Note
The webhook URI must follow this format:
https://<app-name>.scm.azurewebsites.net/api/registry/webhook
It must end with /api/registry/webhook. If you receive a URI error, confirm that the path is correct.
-
In this step, use the az acr webhook create command to register the webhook and configure it to trigger on
pushevents.#!/bin/bash CREDENTIAL=$(az webapp deployment list-publishing-credentials \ --resource-group "$RESOURCE_GROUP_NAME" \ --name "$APP_SERVICE_NAME" \ --query publishingPassword --output tsv) # Web app publishing credentials may not be available immediately. In production, poll until non-empty. SERVICE_URI="https://$APP_SERVICE_NAME:$CREDENTIAL@$APP_SERVICE_NAME.scm.azurewebsites.net/api/registry/webhook" az acr webhook create \ --name webhookforwebapp \ --registry "$REGISTRY_NAME" \ --scope msdocspythoncontainerwebapp:* \ --uri "$SERVICE_URI" \ --actions push# PowerShell syntax $CREDENTIAL=$(az webapp deployment list-publishing-credentials ` --resource-group "$RESOURCE_GROUP_NAME" ` --name "$APP_SERVICE_NAME" ` --query publishingPassword --output tsv) # Web app publishing credentials may not be available immediately. In production, poll until non-empty. $SERVICE_URI = "https://$APP_SERVICE_NAME`:$CREDENTIAL@$APP_SERVICE_NAME.scm.azurewebsites.net/api/registry/webhook" az acr webhook create ` --name webhookforwebapp ` --registry "$REGISTRY_NAME" ` --scope msdocspythoncontainerwebapp:* ` --uri "$SERVICE_URI" ` --actions push
To verify that the web app is running, open https://<website-name>.azurewebsites.net, replacing <website-name> with the name of your App Service. You should see the restaurant review sample app. It may take a few moments to load the first time.
Once the site appears, try adding a restaurant and submitting a review to confirm that the app is functioning correctly.
Note
The az webapp browse command isn't supported in Cloud Shell. If you're using Cloud Shell, manually open a browser and navigate to the site URL.
If you're using the Azure CLI locally, you can use the az webapp browse command to open the site in your default browser:
az webapp browse --name $APP_SERVICE_NAME --resource-group $RESOURCE_GROUP_NAME
Note
The az webapp browse command isn't supported in Cloud Shell. Open a browser window and navigate to the website URL instead.
You can use the Docker extension in Visual Studio Code to build and deploy your containerized web application to Azure App Service. This extension streamlines the process of packaging your app and pushing it to the cloud. Once deployed, use the Azure Tools extension to configure the web app's settings, including the MongoDB connection string and a secret key for the application.
Initially, configure and test the app using hardcoded values to ensure it starts successfully connects to the MongoDB database. After verifying that the app works, use the Azure CLI (either locally or in the Cloud Shell) to create an Azure Key Vault. Next, grant the user creating the app in VS Code permission to store sensitive information and then store the MongoDB connection string and the app's secret key as Key Vault secrets.
Finally, in Visual Studio Code, update the web app's application settings to reference the secrets stored in Key Vault. The app can now securely access configuration values without embedding them directly in code.
These steps require the installation of the Docker extension for VS Code.
-
Refresh the Azure Container Registry in the Docker extension to confirm that the container you built appears under the REGISTRIES section of the Docker extension. If it doesn't, right-click the registry name and select Refresh.
:::image type="content" source="./media/tutorial-container-web-app/visual-studio-code-refresh-registries.png" lightbox="./media/tutorial-container-web-app/visual-studio-code-refresh-registries.png" alt-text="A screenshot showing how to fresh registries in the Docker extension for Visual Studio Code." :::
-
Select F1 or CTRL+SHIFT+P to open the command palette, type "Docker Registries", and select the Docker Registries: Deploy Image to Azure App Service... task.
-
Enter the following values as prompted to deploy the image:
- Select registry provider: Azure
- Subscription: Select the subscription that contains the Azure Container Registry you created earlier.
- Select registry: Enter the name of the registry you created earlier in this tutorial.
- Select repository: Enter the repository name msdocscontainerregistryname. If you don't see this repo, refresh the Docker extension REGISTRIES section.
- Select tag: latest for the image tag.
- Enter a globally unique name for the web app: Enter a name that is globally unique to Azure App Service. For example, if you use msdocs-website-name, the web app URL would be
http://msdocs-website-name.azurewebsites.net. - Select a resource group: Use the resource group that contains the Azure Container Registry you created earlier.
- Select a Linux App Service plan: Use an existing or create a new one.
-
View the OUTPUT window for details of the deployment. One of the output lines is "Granting permission for App Service to pull image from ACR...", which the App Service accesses the registry using managed identity.
:::image type="content" source="./media/tutorial-container-web-app/visual-studio-code-site-deployed.png" lightbox="./media/tutorial-container-web-app/visual-studio-code-site-deployed.png" alt-text="A screenshot showing prompt when Docker image is deployed App Service in Visual Studio Code." :::
The final site
https://<app-name>.azurewebsites.netisn't ready yet because you need to specify MongoDB info.[!NOTE] When you deploy with Visual Studio Code, managed identity is already set for the App Service to pull images from the registry. You can confirm managed identity is enabled by viewing logs in the OUTPUT window and looking for the message "Granting permission for App Service to pull image from ACR...".
During the deploy with VS Code, a webhook is created that enables the web app to pull new images from the Azure Container Registry.
-
Review the webhooks configuration in the Azure portal to confirm the Service URI ends with "/api/registry/webhook". To review the service URI, open the Docker extension in VS Code and find the registry you created. Right-click the registry and select Open in Portal. The container registry opens in the Azure portal. Click Services and then click Webhooks. Open the context menu and click Configure.
:::image type="content" source="./media/tutorial-container-web-app/visual-studio-create-app-webhook.png" lightbox="./media/tutorial-container-web-app/visual-studio-create-app-webhook.png" alt-text="A screenshot showing how to check a webhook configuration." :::
-
Confirm that the Service URI ends with "/api/registry/webhook". If it doesn't, add it to the end of the string and click Save
In this step, you specify the environment variables needed for the web application to connect to MongoDB.
Note
To configure environment variables for the web app from VS Code, you must have the Azure Tools extension pack installed and be signed into Azure from VS Code.
-
In the Azure view in VS Code (from the Azure Tools extension):
-
Expand RESOURCES and find App Services under your subscription. (Make sure you viewing resources by Group by Resource Type.)
-
Expand App Services and find the web app you created.
-
Expand your web app and right-click on Application Settings.
-
Select Add new setting....
:::image type="content" source="./media/tutorial-container-web-app/visual-studio-code-create-app-settings.png" lightbox="./media/tutorial-container-web-app/visual-studio-code-create-app-settings.png" alt-text="A screenshot showing how to add a setting to the App Service in VS Code." :::
-
-
Each time you add a new setting, a dialog box appears at the top of the VS Code window where you can add the setting name followed by its value. Add the following settings:
- CONNECTION_STRING: the MongoDB connection string. Later in this tutorial, you set this value to the connection string that you store in Azure Key Vault.
- DB_NAME: restaurants_reviews
- COLLECTION_NAME: restaurants_reviews
- WEBSITES_PORT: 8000 for Django and 5000 for Flask. This environment variable specifies the port on which the container is listening.
- SECRET_KEY: supersecretkeythatispassedtopythonapp. This secret key is a random string used by Django and Flask to encrypt session data. Later in this tutorial, you set this value to the random string that you store in Azure Key Vault.
In the Azure view in VS Code (from the Azure Tools extension):
-
Expand RESOURCES and find App Services under your subscription. (Make sure you viewing resources by Group by Resource Type.)
-
Right-click your web app and select Browse Website. If your web site shows an error, wait a few minutes and try again. It may take a few minutes for the web app to start up. See also Troubleshooting App Service.
In this step, you create an Azure Key Vault to store the MongoDB connection string and the web app’s SECRET_KEY. Azure Key Vault is a secure service for storing secrets, API keys, connection strings, and certificates. The Key Vault is configured to use role-based access control (RBAC) to manage access through Azure roles instead of traditional access policies. The web app uses its system-assigned managed identity to retrieve secrets securely at runtime.
Note
You can configure VS Code to use the Azure CLI or PowerShell. To select your default shell in VS Code, select F1 or CTRL+SHIFT+P to open the command palette. Then type Terminal: Select Default Profile. In the command palette, type and select: Terminal: Select Default Profile and then select your desired default shell.
-
Run the following Azure CLI command to create a new Key Vault. This command uses either the bash or PowerShell to create a Key Vault with RBAC authorization enabled.
#!/bin/bash RESOURCE_GROUP_NAME="msdocs-web-app-rg" LOCATION="westus" KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv" az keyvault create \ --name "$KEYVAULT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --location "$LOCATION" \ --enable-rbac-authorization true# PowerShell syntax $RESOURCE_GROUP_NAME="msdocs-web-app-rg" $LOCATION="westus" $KEYVAULT_NAME="${RESOURCE_GROUP_NAME}-kv" az keyvault create ` --name "$KEYVAULT_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --location "$LOCATION" ` --enable-rbac-authorization true
To store secrets in Azure Key Vault, the user executing the script must be granted the Key Vault Secrets Officer role. This role allows the user to create and manage secrets within the vault.
In this step, the script assigns that role to the currently logged-in user, enabling them to securely store sensitive application data such as the MongoDB connection string and the app’s SECRET_KEY.
By using Azure Role-Based Access Control (RBAC), this approach ensures secure, auditable access to the Key Vault based on identity — avoiding the need to embed credentials directly in code or configuration files.
Note
The user must be assigned the Key Vault Secrets Officer role before attempting to store any secrets in the key vault. This assignment is done using the az role assignment create command scoped to the Key Vault.
-
In this step, you use the az role assignment create command to assign the role at the Key Vault scope.
#!/bin/bash CALLER_ID=$(az ad signed-in-user show --query id -o tsv) echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully. az role assignment create \ --role "Key Vault Secrets Officer" \ --assignee "$CALLER_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"# PowerShell syntax $CALLER_ID=$(az ad signed-in-user show --query id -o tsv) echo $CALLER_ID # Verify this value retrieved successfully. In production, poll to verify this value is retrieved successfully. az role assignment create ` --role "Key Vault Secrets Officer" ` --assignee "$CALLER_ID" ` --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"
To avoid hardcoding secrets in your application, in this step you store the MongoDB connection string to the MongoDB instance and the web app’s secret key in Azure Key Vault. These secrets can then be securely accessed by the web app at runtime through its managed identity, without the need to store credentials in code or configuration.
Note
While this tutorial stores only the connection string and secret key in the key vault, you can optionally store other application settings such as the MongoDB database name or collection name in Key Vault as well.
-
In this step, you use the az cosmosdb keys list command to retrieve the MongoDB connection string. You then use the az keyvault secret set command to store both the connection string and a randomly generated secret key in Key Vault.
#!/bin/bash ACCOUNT_NAME="msdocs-cosmos-db-account-name" MONGO_CONNECTION_STRING=$(az cosmosdb keys list \ --name "$ACCOUNT_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --type connection-strings \ --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" -o tsv) SECRET_KEY=$(openssl rand -base64 32 | tr -dc 'a-zA-Z0-9') # This key is cryptographically secure, using OpenSSL’s strong random number generator. az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoConnectionString" \ --value "$MONGO_CONNECTION_STRING" az keyvault secret set \ --vault-name "$KEYVAULT_NAME" \ --name "MongoSecretKey" \ --value "$SECRET_KEY"# PowerShell syntax $ACCOUNT_NAME="msdocs-cosmos-db-account-name" $MONGO_CONNECTION_STRING = az cosmosdb keys list ` --name $ACCOUNT_NAME ` --resource-group $RESOURCE_GROUP_NAME ` --type connection-strings ` --query "connectionStrings[?description=='Primary MongoDB Connection String'].connectionString" ` -o tsv # Generate a 32-byte cryptographically secure random value $bytes = New-Object 'Byte[]' 32 [System.Security.Cryptography.RandomNumberGenerator]::Create().GetBytes($bytes) # Convert to base64 and filter to alphanumeric characters only $base64 = [Convert]::ToBase64String($bytes) $alphanumeric = $base64 -replace '[^a-zA-Z0-9]', '' # Truncate to 50 characters $SECRET_KEY = $alphanumeric.Substring(0, [Math]::Min(50, $alphanumeric.Length)) az keyvault secret set ` --vault-name "$KEYVAULT_NAME" ` --name "MongoConnectionString" ` --value "$MONGO_CONNECTION_STRING" az keyvault secret set ` --vault-name "$KEYVAULT_NAME" ` --name "MongoSecretKey" ` --value "$SECRET_KEY"
The web app needs permission to access the MongoDB connection string and the SECRET_KEY that you stored in the key vault. To grant these permissions, you assign the Key Vault Secrets User role to the web app’s system-assigned managed identity.
-
In this step, you use the unique identifier (principal ID) of the web app’s system-assigned managed identity to grant the web app access to the Key Vault with the Key Vault Secrets User role using the az role assignment create command.
#!/bin/bash APP_SERVICE_NAME="msdocs-website-name" PRINCIPAL_ID=$(az webapp identity show \ --name "$APP_SERVICE_NAME" \ --resource-group "$RESOURCE_GROUP_NAME" \ --query principalId \ -o tsv) echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful 'AcrPull' role assignment using `az role assignment list`. az role assignment create \ --role "Key Vault Secrets User" \ --assignee "$PRINCIPAL_ID" \ --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME"# PowerShell syntax $PRINCIPAL_ID=$(az webapp identity show ` --name "$APP_SERVICE_NAME" ` --resource-group "$RESOURCE_GROUP_NAME" ` --query principalId ` -o tsv) echo $PRINCIPAL_ID # Verify this value retrieved successfully. In production, poll for successful AcrPull role assignment using `az role assignment list`. az role assignment create ` --role "Key Vault Secrets User" ` --assignee "$PRINCIPAL_ID"` --scope "/subscriptions/$(az account show --query id -o tsv)/resourceGroups/$RESOURCE_GROUP_NAME/providers/Microsoft.KeyVault/vaults/$KEYVAULT_NAME" ``` ---
In this step, you update the environment variables needed to connect to MongoDB to use the values stored in the key vault.
-
In the Azure view in VS Code (from the Azure Tools extension):
-
Expand RESOURCES and find App Services under your subscription. (Make sure you viewing resources by Group by Resource Type.)
-
Expand App Services, expand your web app, and then expand Application Settings.
-
Modify the following settings:
- CONNECTION_STRING: @Microsoft.KeyVault(SecretUri=https://msdocs-web-app-rg-kv.vault.azure.net/secrets/MongoConnectionString)
- SECRET_KEY: @Microsoft.KeyVault(SecretUri=https://$KEYVAULT_NAME.vault.azure.net/secrets/MongoSecretKey)
[!NOTE] To verify that the application settings are set correctly, you can use the az webapp config appsettings list command to list the application settings for the web app. The form of the command is:
az webapp config appsettings list --/<resource-group msdocs-web-app-rg/> --name /<website-name/>. This command lists all the application settings for the web app, including the ones you just set. -
In the Azure view in VS Code (from the Azure Tools extension):
-
Expand RESOURCES and find App Services under your subscription. (Make sure you viewing resources by Group by Resource Type.)
-
Right-click your web app and select Browse Website. If your web site shows an error, wait a few minutes and try again. It may take a few minutes for the web app to start up. See also Troubleshooting App Service.
If you don't see the sample app, try the following steps.
- With container deployment and App Service, always check the Deployment Center / Logs page in the Azure portal. Confirm that the container was pulled and is running. The initial pull and running of the container can take a few moments.
- Try to restart the App Service and see if that resolves your issue.
- If there are programming errors, those errors show up in the application logs. On the Azure portal page for the App Service, select Diagnose and solve problems/Application logs.
- The sample app relies on a connection to Azure Cosmos DB for MongoDB. Confirm that the App Service has application settings with the correct connection info.
- Confirm that managed identity is enabled for the App Service and is used in the Deployment Center. On the Azure portal page for the App Service, go to the App Service Deployment Center resource and confirm that Authentication is set to Managed Identity.
- Check that the webhook is defined in the Azure Container Registry. The webhook enables the App Service to pull the container image. In particular, check that Service URI ends with "/api/registry/webhook". If not, add it.
- Different Azure Container Registry skus have different features, including number of webhooks. If you're reusing an existing registry, you could see the message: "Quota exceeded for resource type webhooks for the registry SKU Basic. Learn more about different SKU quotas and upgrade process: https://aka.ms/acr/tiers". If you see this message, use a new registry, or reduce the number of registry webhooks in use.
[!div class="nextstepaction"] Clean up resources