Virtual Network Integration feature is important to secure ingress/egress of Function App. See Azure Functions networking options for more detail.
In this article, I explain how we can deploy such configuration via bicep.
Basic bicep
I use Quickstart: Create and deploy Azure Functions resources using Bicep as base script.
Add VNET section
Firstly, we need VNET to use VNET integration. So I added following code before creating storage account.
- We need to set
delegation
to support VNET integration. Set it forMicrosoft.Web/serverFarms
. See What is subnet delegation? for detail.
var vnetName = 'vnet-${appName}' var subnetNeme = 'snet-${appName}' resource vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: vnetName location: location properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: subnetNeme properties: { addressPrefix: '10.0.0.0/24' delegations: [ { name: 'Microsoft.Web/serverFarms' properties: { serviceName: 'Microsoft.Web/serverFarms' } } ] } } ] } }
Change SKU
Serverless plan doesn't support VNET Integration, so I changed SKU to Standard
for hosting plan.
resource hostingPlan 'Microsoft.Web/serverfarms@2021-03-01' = { name: hostingPlanName location: location sku: { name: 'S1' tier: 'Standard' } properties: {} }
Add VNET info
Finally, I added virtualNetworkSubnetId
property for functionApp
.
resource functionApp 'Microsoft.Web/sites@2021-03-01' = { name: functionAppName location: location kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { virtualNetworkSubnetId: vnet.properties.subnets[0].id serverFarmId: hostingPlan.id
Complete Bicep
@description('The name of the function app that you wish to create.') param appName string = 'fnapp${uniqueString(resourceGroup().id)}' @description('Storage Account type') @allowed([ 'Standard_LRS' 'Standard_GRS' 'Standard_RAGRS' ]) param storageAccountType string = 'Standard_LRS' @description('Location for all resources.') param location string = resourceGroup().location @description('Location for Application Insights') param appInsightsLocation string @description('The language worker runtime to load in the function app.') @allowed([ 'node' 'dotnet' 'java' ]) param runtime string = 'node' var functionAppName = appName var hostingPlanName = appName var applicationInsightsName = appName var vnetName = 'vnet-${appName}' var subnetNeme = 'snet-${appName}' var storageAccountName = '${uniqueString(resourceGroup().id)}azfunctions' var functionWorkerRuntime = runtime resource vnet 'Microsoft.Network/virtualNetworks@2021-08-01' = { name: vnetName location: location properties: { addressSpace: { addressPrefixes: [ '10.0.0.0/16' ] } subnets: [ { name: subnetNeme properties: { addressPrefix: '10.0.0.0/24' delegations: [ { name: 'Microsoft.Web/serverFarms' properties: { serviceName: 'Microsoft.Web/serverFarms' } } ] } } ] } } resource storageAccount 'Microsoft.Storage/storageAccounts@2021-08-01' = { name: storageAccountName location: location sku: { name: storageAccountType } kind: 'Storage' } resource hostingPlan 'Microsoft.Web/serverfarms@2021-03-01' = { name: hostingPlanName location: location sku: { name: 'S1' tier: 'Standard' } properties: {} } resource functionApp 'Microsoft.Web/sites@2021-03-01' = { name: functionAppName location: location kind: 'functionapp' identity: { type: 'SystemAssigned' } properties: { virtualNetworkSubnetId: vnet.properties.subnets[0].id serverFarmId: hostingPlan.id siteConfig: { appSettings: [ { name: 'AzureWebJobsStorage' value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}' } { name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING' value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountName};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}' } { name: 'WEBSITE_CONTENTSHARE' value: toLower(functionAppName) } { name: 'FUNCTIONS_EXTENSION_VERSION' value: '~2' } { name: 'WEBSITE_NODE_DEFAULT_VERSION' value: '~10' } { name: 'APPINSIGHTS_INSTRUMENTATIONKEY' value: applicationInsights.properties.InstrumentationKey } { name: 'FUNCTIONS_WORKER_RUNTIME' value: functionWorkerRuntime } ] ftpsState: 'FtpsOnly' minTlsVersion: '1.2' } httpsOnly: true } } resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = { name: applicationInsightsName location: appInsightsLocation kind: 'web' properties: { Application_Type: 'web' Request_Source: 'rest' } }
Result
Hope this helps me in the future!
Top comments (1)
thanks!