Today I needed to migrate an Azure Functions project that used to connect to Azure Storage with a normal connection string. Since that’s prohibited by policy in my new Azure subscription, we needed to change that.
This also meant we needed to move the Function App to a dedicated plan since Managed Identity is not supported with Consumption or Elastic Premium plans.
Here’s the full bicep file for Storage, App Service Plan, Function app and required roles. Note that we’re deploying a Windows app service plan with .NET 9 Isolated.
var location = 'germanywestcentral'
var resourceName = 'myapp'
resource storageAccount 'Microsoft.Storage/storageAccounts@2023-05-01' = {
name: 'st${resourceName}'
location: location
sku: {
name: 'Standard_LRS'
}
kind: 'StorageV2'
properties: {
minimumTlsVersion: 'TLS1_2'
allowBlobPublicAccess: false
allowSharedKeyAccess: false
}
}
resource hostingPlan 'Microsoft.Web/serverfarms@2024-04-01' = {
name: 'asp${resourceName}'
location: location
sku: {
name: 'B1'
}
}
resource functionApp 'Microsoft.Web/sites@2024-04-01' = {
name: 'func${resourceName}'
location: location
kind: 'functionapp'
identity: {
type: 'SystemAssigned'
}
properties: {
serverFarmId: hostingPlan.id
siteConfig: {
alwaysOn: true
appSettings: [
{
name: 'AzureWebJobsStorage__accountname'
value: storageAccount.name
}
{
name: 'FUNCTIONS_EXTENSION_VERSION'
value: '~4'
}
{
name: 'FUNCTIONS_WORKER_RUNTIME'
value: 'dotnet-isolated'
}
]
ftpsState: 'FtpsOnly'
minTlsVersion: '1.2'
netFrameworkVersion: 'v9.0'
}
httpsOnly: true
}
}
// role assignents for accessing the storage
var blobOwnerRoleId = 'b7e6dc6d-f1e8-4753-8033-0f276bb0955b'
resource roleDefinitionBlobContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: blobOwnerRoleId
}
resource roleAssignmentBlobContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(blobOwnerRoleId, functionApp.name)
scope: storageAccount
properties: {
roleDefinitionId: roleDefinitionBlobContributor.id
principalId: functionApp.identity.principalId
}
}
var storageContributorRoleId = '17d1049b-9a84-46fb-8f53-869881c3d3ab'
resource roleDefinitionStorageContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: storageContributorRoleId
}
resource roleAssignmentStorageContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storageContributorRoleId, functionApp.name)
scope: storageAccount
properties: {
roleDefinitionId: roleDefinitionStorageContributor.id
principalId: functionApp.identity.principalId
}
}
// required for storage queue triggers
var storageQueueContributorRoleId = '974c5e8b-45b9-4653-ba55-5f855dd0fb88'
resource roleDefinitionStorageQueueContributor 'Microsoft.Authorization/roleDefinitions@2022-04-01' existing = {
name: storageQueueContributorRoleId
}
resource roleAssignmentStorageQueueContributor 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(storageQueueContributorRoleId, functionApp.name)
scope: storageAccount
properties: {
roleDefinitionId: roleDefinitionStorageQueueContributor.id
principalId: functionApp.identity.principalId
}
}