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 (0)