Thanks to @ThiagoAlmeida I've had confirmation that this is indeed a bug with Flex Consumption apps in Azure. His comment is below but here is the relevant section from it:
This is a known issue by the product group, the service association link is not being deleted in time and leaves that association still there (/legionservicelink is the Flex Consumption VNet integration association link).
The error only occurs for me when you deploy the Function App using Bicep and attach it to a network separately in the same script. For clarity these are the steps to reproduce the error:
resource appHost 'Microsoft.Web/serverfarms@2021-03-01' = {
name: hostingPlanName
location: location
sku: sku
kind: 'functionapp'
properties: {
reserved: true
}
}
resource functionApp 'Microsoft.Web/sites@2023-12-01' = {
name: functionAppName
location: location
kind: 'functionapp,linux'
identity: {
type: 'SystemAssigned'
}
properties: {
reserved: true
enabled: true
hostNameSslStates: hostNameSslStates
functionAppConfig: functionAppConfig
serverFarmId: appHost.id
siteConfig: siteConfig
}
}
resource hostNameBindings 'Microsoft.Web/sites/hostNameBindings@2018-11-01' = {
parent: functionApp
name: '${functionAppName}.azurewebsites.net'
properties: {
siteName: functionApp_siteName
hostNameType: 'Verified'
}
}
resource planNetworkConfig 'Microsoft.Web/sites/networkConfig@2021-01-01' = {
parent: functionApp
name: 'virtualNetwork'
properties: {
subnetResourceId: subnetId
swiftSupported: true
}
}
Deploy the Bicep script once.
Observe that the Function App is created and attached to the network as expected.
Run the Bicep script a second time without changing or deleting the Function App.
Observe a 500 error related to the networking section in the deployment script.
Error: Subnet xxxx is in use by /subscriptions/xxxx/resourceGroups/xxxx/providers/Microsoft.Network/virtualNetworks/xxxx/subnets/xxxx/serviceAssociationLinks/legionservicelink
There is one workaround that I've found which has overcome this issue for us. Before running the Bicep script add a deployment step that removes the network binding from the app. Like this:
az webapp vnet-integration remove --name $appName --resource-group $resourceGroupName
Because the network binding has been explicitly removed, running the Bicep script no longer corrupts the subnet.
Microsoft have advised they are working on a fix which should be available in the coming weeks.
If you remove a Flex Consumption app from a subnet manually via the portal, or delete it via the portal, or even via the Azure CLI, the subnet does not become corrupted.
It is also possible that combining the network binding with the module that creates the app itself does not encounter the same error because the app is refreshed along with its network configuration. I haven't tested this scenario because our specific situation requires us to bind the network after the app is created.