A collection of production-ready Bicep templates for deploying Azure resources, starting with Function Apps on isolated App Service Plans.
Azure Bicep documentation is often inconsistent and can be difficult to piece together into a working deployment. API versions change, properties get deprecated, and examples in the docs don't always reflect what actually works. This repository exists to capture tested, working combinations of Azure resources and configuration so they can be reliably reused.
The goal is to keep these templates up to date as Bicep and Azure APIs evolve, and to expand the collection over time with additional resource types and resource combinations beyond what's currently here.
Currently, the templates cover Azure Function Apps using isolated (Premium v3) App Service Plans, with variants for Windows/Linux and with/without VNet integration. All templates include managed identity authentication, monitoring, and security best practices.
BicepInfraResourceDeployTemplates/
βββ templates/
β βββ basic-windows/ # Basic Windows Function App
β β βββ main.bicep
β β βββ parameters.dev.json
β β βββ README.md
β βββ basic-linux/ # Basic Linux Function App
β β βββ main.bicep
β β βββ parameters.dev.json
β β βββ README.md
β βββ vnet-windows/ # VNet-integrated Windows Function App
β β βββ main.bicep
β β βββ parameters.dev.json
β β βββ README.md
β βββ vnet-linux/ # VNet-integrated Linux Function App
β βββ main.bicep
β βββ parameters.dev.json
β βββ README.md
βββ scripts/
β βββ Deploy-FunctionApp.ps1 # PowerShell deployment script
βββ main.bicep # Original working template
βββ README.md # This file
A straightforward Windows-based function app deployment with:
- Premium v3 App Service Plan
- Optimized for .NET workloads
- Managed Identity for storage access
- Application Insights monitoring
- No network isolation
Best for: Development environments, simple workloads, getting started
A Linux container-based function app deployment with:
- Premium v3 App Service Plan for Linux
- Managed Identity for storage access
- Application Insights monitoring
- Optimized for Python/Node.js workloads
Best for: Python or Node.js workloads, containerized applications
Enterprise-grade Windows function app with network isolation:
- VNet integration with dedicated subnet
- Private endpoints for storage (Blob, Table, Queue)
- Private DNS zones
- No public storage access
- Full traffic routing through VNet
Best for: Production workloads, compliance requirements, enterprise security
Enterprise-grade Linux function app with network isolation:
- VNet integration with dedicated subnet
- Private endpoints for storage (Blob, Table, Queue)
- Private DNS zones
- No public storage access
- Container-based hosting with network security
Best for: Production Python/Node.js workloads with strict security requirements
- Azure PowerShell Az module: Install with
Install-Module -Name Az -AllowClobber -Scope CurrentUser - Azure Subscription: Active Azure subscription with appropriate permissions
- Bicep CLI: Installed automatically with Azure CLI or download separately
- Note: If you installed Bicep using the Azure CLI, you may need to add
%USERPROFILE%\.Azure\binto your system or user PATH environment variables on Windows
- Note: If you installed Bicep using the Azure CLI, you may need to add
- PowerShell 7+: Recommended for cross-platform support
cd path/to/BicepInfraResourceDeployTemplatesConnect-AzAccount# Basic Windows deployment
.\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "basic-windows" `
-Environment "dev" `
-ResourceGroupName "rg-myapp-dev"
-Location " centralus"
# VNet-enabled Linux deployment
.\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "vnet-linux" `
-Environment "prod" `
-ResourceGroupName "rg-myapp-prod" `
-Location "westus2"
# Validation only (WhatIf mode)
.\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "basic-windows" `
-Environment "dev" `
-ResourceGroupName "rg-test" `
-WhatIf| Parameter | Required | Description | Example |
|---|---|---|---|
TemplateName |
β | Template to deploy | basic-windows, vnet-linux |
Environment |
β | Environment name | dev, test, prod |
ResourceGroupName |
β | Target resource group | rg-myapp-dev |
Location |
β | Azure region | eastus (default) |
SubscriptionId |
β | Azure subscription ID | xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx |
AppName |
β | Custom function app name | my-custom-func-app |
ResourceToken |
β | Custom naming token | mytoken123 |
WhatIf |
β | Validation mode (no deployment) | Switch parameter |
If the PowerShell script isn't working or you prefer using Azure CLI, you can deploy directly using the az deployment group create command.
# Navigate to the template folder
cd templates\basic-windows
# Deploy using Azure CLI
az deployment group create `
--resource-group rg-myapp-dev `
--template-file main.bicep `
--parameters functionAppRuntime=dotnet-isolated `
functionAppRuntimeVersion=8.0 `
appName=myapp-func-devIf you need to troubleshoot deployment issues, add the --debug flag:
az deployment group create `
--resource-group rg-myapp-dev `
--template-file main.bicep `
--parameters functionAppRuntime=dotnet-isolated `
functionAppRuntimeVersion=8.0 `
appName=myapp-func-dev `
--debugYou can also use parameter files instead of inline parameters:
# Deploy using a parameter file
az deployment group create `
--resource-group rg-myapp-dev `
--template-file main.bicep `
--parameters parameters.dev.jsonBefore deploying, validate your changes without actually creating resources:
az deployment group what-if `
--resource-group rg-myapp-dev `
--template-file main.bicep `
--parameters parameters.dev.json# Navigate to the VNet template folder
cd templates\vnet-windows
# Deploy with custom parameters
az deployment group create `
--resource-group rg-myapp-prod `
--template-file main.bicep `
--parameters functionAppRuntime=dotnet-isolated `
functionAppRuntimeVersion=8.0 `
appName=myapp-func-prod `
location=eastus2 `
--debug- Login first: Run
az loginbefore deploying - Set subscription: Use
az account set --subscription <subscription-id>to select the correct subscription - Create resource group: If it doesn't exist, create it with
az group create --name <rg-name> --location <location> - Parameter overrides: Command-line parameters override those in parameter files
- Debug mode: The
--debugflag provides detailed HTTP request/response information useful for troubleshooting
Each template includes a parameters.dev.json file. Create additional files for other environments:
# Copy and modify for production
Copy-Item .\templates\basic-windows\parameters.dev.json .\templates\basic-windows\parameters.prod.jsonEdit the new file to adjust settings:
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentParameters.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"location": {
"value": "westus2"
},
"functionAppRuntime": {
"value": "dotnet-isolated"
},
"functionAppRuntimeVersion": {
"value": "8.0"
},
"maximumInstanceCount": {
"value": 200
},
"instanceMemoryMB": {
"value": 4096
}
}
}Each template folder contains a main.bicep file. You can:
- Add new parameters
- Modify SKUs or tiers
- Add additional Azure resources
- Change networking configurations
See the individual template README files for specific guidance.
.\scripts\Deploy-FunctionApp.ps1 -TemplateName "basic-windows" -Environment "dev" -ResourceGroupName "rg-dev-sandbox".\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "vnet-windows" `
-Environment "prod" `
-ResourceGroupName "rg-prod-funcapp" `
-Location "eastus2" `
-SubscriptionId "your-subscription-id".\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "vnet-linux" `
-Environment "prod" `
-ResourceGroupName "rg-python-secure"All templates include:
- β Managed Identity: No storage keys in configuration
- β HTTPS Only: Enforced at the function app level
- β TLS 1.2+: Minimum TLS version configured
- β No Public Blob Access: Storage accounts secured
- β Shared Key Disabled: Storage authentication via managed identity only
- β Application Insights: With AAD authentication
VNet templates additionally include:
- β Private Endpoints: For all storage services
- β Network Isolation: Public access disabled
- β Private DNS: Automatic DNS resolution
- β VNet Integration: Function app in dedicated subnet
All deployments include:
- Application Insights: Telemetry, logs, and metrics
- Log Analytics Workspace: 30-day retention
- Managed Identity for App Insights: Secure authentication
Access Application Insights in the Azure Portal to:
- View live metrics
- Query logs with KQL
- Set up alerts
- Create dashboards
Ensure you have the necessary permissions:
ContributororOwnerrole on the resource groupUser Access Administratorfor role assignments
Update Bicep CLI to the latest version:
az bicep upgradeCheck that:
- Managed identity is assigned to the function app
- Role assignments completed successfully
- For VNet deployments, private endpoints are connected
After deployment:
- Verify private endpoints are in "Approved" state
- Check DNS resolution from within the VNet
- Ensure subnet delegation is correct
Run the deployment script again with the same parameters. Bicep will:
- Update resources that changed
- Leave unchanged resources as-is
- Add new resources if template was modified
# Re-run to update
.\scripts\Deploy-FunctionApp.ps1 `
-TemplateName "basic-windows" `
-Environment "dev" `
-ResourceGroupName "rg-myapp-dev"- Azure Functions Documentation
- Bicep Documentation
- Azure Function App Best Practices
- VNet Integration
- Managed Identity for Azure Resources
When you have a working configuration:
- Create a new folder under
templates/ - Add
main.bicep, parameter files, and README.md - Test the deployment thoroughly
- Document any special requirements
This project is licensed under the MIT License.
Potential future templates:
- Flex Consumption plan deployments
- Container Apps integration
- API Management integration
- Azure Service Bus triggers
- Multi-region deployments
- Cosmos DB integration
Version: 1.0.0
Last Updated: January 2026