You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

手动创建Azure Functions正常,Bicep部署遇存储403错误求助

问题排查:Azure Functions部署时存储访问403错误

问题场景

通过Bicep文件+Azure DevOps流水线构建环境,核心服务包含2个App Services、SQL Server、Storage、Azure Functions、Virtual Network。为禁用公网访问,所有资源均纳入VNet,Bicep可正常创建所有资源,但部署Azure Functions时出现以下错误:

Creation of storage file share failed with: 'The remote server returned an error: (403) Forbidden.'. Please check if the storage account is accessible.

手动创建Function App的成功步骤:

  • 创建Function App
  • 关联Bicep创建的S1标准层App Service Plan
  • 使用Bicep创建的现有存储账户
  • 禁用公网访问
  • 启用网络注入
  • 选择Bicep创建的现有虚拟网络
  • 选择专用于Functions的Bicep创建子网作为出站访问
  • 不使用专用端点

相关Bicep代码

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
  }
}

问题排查与修复

核心问题

存储账户的网络ACL仅允许storage子网访问,但Function App部署在functions子网,导致创建文件共享时被存储账户拒绝访问。同时缺少强制VNet路由的配置,部分流量可能未走VNet通道。

修复步骤

  1. 更新存储账户的网络ACL规则:在functions.bicep的storage资源中,将functions子网添加到virtualNetworkRules列表:
networkAcls: {
  bypass: 'AzureServices'
  defaultAction: 'Deny'
  virtualNetworkRules: [
    {
      id: subnetIdStorage
      action: 'Allow'
    }
    {
      id: subnetIdFunctions
      action: 'Allow'
    }
  ]
}
  1. 添加VNet路由强制配置:在Function App的appSettings中加入以下配置,确保所有出站流量通过VNet路由:
{
  name: 'WEBSITE_VNET_ROUTE_ALL'
  value: '1'
}
  1. 确认子网配置有效性:当前vnet.bicep中functions子网已正确配置Microsoft.Web/serverFarms委托和Microsoft.Storage服务端点,无需修改。

补充说明

手动创建成功是因为配置网络注入时,隐式完成了子网访问权限的关联;而Bicep部署需要显式声明存储ACL规则和VNet路由配置,否则会出现403访问拒绝错误。

内容的提问来源于stack exchange,提问作者kjubersson

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 15:37:01