I'm building environment creation via bicep files and Azure Dev Ops pipelines. The main services that I'm using are:
- 2 x App Services
- SQL server
- Storage
- Azure Functions
- Virtual Network
When I'm disabling connectivity to internat, decided to put everything in vnet. All parts are created via bicep files correctly. The problem starts when trying to deploy Azure functions. I'm having error:
Creation of storage file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible.
After that error I was trying to figure out what can be wrong with my bicep files. I've decided to try create this manually with such important steps inside creator.
- Create Function App
- Attached App service plan created via bicep S1 - Standard
- Use existing storage account created from bicep
- Disable public access
- Enable Network injection
- Choose existing virtual network crated via bicep
- Choose outbound access to subnet dedicated to functions and created via bicep
- No private endpoints
With all that points the Function App was successfully created. Please help me figure out what I have missed in the bicep file that having this error while disabling public access to storage.
Below relevant bicep files: vnet.bicep:
param nameBase string
param location string
resource vnet 'Microsoft.Network/virtualNetworks@2022-09-01' = {
name: '${nameBase}-vnet'
location: location
properties: {
addressSpace: {
addressPrefixes: [
'10.0.0.0/16'
]
}
subnets: [
{
name: 'deafult'
properties: {
addressPrefix: '10.0.0.0/24'
}
}
{
name: 'api'
properties: {
addressPrefix: '10.0.1.0/24'
delegations: [
{
name: 'Microsoft.Web/serverFarms'
properties: {
serviceName: 'Microsoft.Web/serverFarms'
}
}
]
}
}
{
name: 'ui'
properties: {
addressPrefix: '10.0.2.0/24'
delegations: [
{
name: 'Microsoft.Web/serverFarms'
properties: {
serviceName: 'Microsoft.Web/serverFarms'
}
}
]
}
}
{
name: 'functions'
properties: {
addressPrefix: '10.0.3.0/24'
delegations: [
{
name: 'Microsoft.Web/serverFarms'
properties: {
serviceName: 'Microsoft.Web/serverFarms'
}
}
]
serviceEndpoints: [
{
service: 'Microsoft.Storage'
}
]
}
}
{
name: 'storage'
properties: {
addressPrefix: '10.0.4.0/24'
serviceEndpoints: [
{
service: 'Microsoft.Storage'
}
]
}
}
]
}
}
output subnetId string = vnet.properties.subnets[0].id
output subnetIdApi string = vnet.properties.subnets[1].id
output subnetIdUi string = vnet.properties.subnets[2].id
output subnetIdFunctions string = vnet.properties.subnets[3].id
output subnetIdStorage string = vnet.properties.subnets[4].id
functions.bicep:
param name string
param client string
param env string
param location string
param subnetIdFunctions string
param subnetIdStorage string
resource storage 'Microsoft.Storage/storageAccounts@2022-05-01' = {
name: 'storage${client}${env}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
isHnsEnabled: true
isSftpEnabled: true
minimumTlsVersion: 'TLS1_2'
publicNetworkAccess: 'Enabled'
allowBlobPublicAccess: false
supportsHttpsTrafficOnly: true
allowSharedKeyAccess: true
encryption: {
keySource: 'Microsoft.Storage'
requireInfrastructureEncryption: false
services: {
blob: {
enabled: true
keyType: 'Account'
}
file: {
enabled: true
keyType: 'Account'
}
queue: {
enabled: true
keyType: 'Service'
}
table: {
enabled: true
keyType: 'Service'
}
}
}
keyPolicy: {
keyExpirationPeriodInDays: 7
}
networkAcls: {
bypass: 'AzureServices'
defaultAction: 'Deny'
virtualNetworkRules: [
{
id: subnetIdStorage
action: 'Allow'
}
]
}
}
}
output storageAccountName string = storage.name
resource applicationInsights 'Microsoft.Insights/components@2020-02-02' = {
name: '${name}-functions-insights'
location: location
kind: 'web'
properties: {
Application_Type: 'web'
Request_Source: 'rest'
}
}
resource serviceplan 'Microsoft.Web/serverfarms@2021-03-01' = {
name: '${name}-functions-serviceplan'
location: location
sku: {
name: 'S1'
tier: 'Standard'
}
}
var functionAppName = '${name}-functions'
resource functionApp 'Microsoft.Web/sites@2021-03-01' = {
name: functionAppName
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
virtualNetworkSubnetId: subnetIdFunctions
serverFarmId: serviceplan.id
siteConfig: {
appSettings: [
{
name: 'AzureWebJobsStorage'
value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storage.listKeys().keys[0].value}'
}
{
name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
value: 'DefaultEndpointsProtocol=https;AccountName=${storage.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storage.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: 'dotnet'
}
]
ftpsState: 'FtpsOnly'
minTlsVersion: '1.2'
}
httpsOnly: true
}
}