App Configuration References
Overview
I recently undertook a backend upgrade to .NET 8 which included a Function App that was relying on App Configuration for the Service Bus Trigger bindings, one thing that I learnt during this upgrade is that the in-process Azure Functions have access to the configuration early enough to allow the Service Bus Triggers to use the config values whereas the dotnet-isolated Functions do not.
Whilst there is a current plan to make the .NET 8 runtime available to the in-process Functions, this is the last version that it will happen, so it feels like it's time to fully adopt the isolated approach to future proof our solutions.
It would be easy enough to either add the configuration values directly to the Function App, this post will provide detail around how to overcome this ServiceBusTrigger issue with App Configuration references to ensure the config remains centralised.
Implementation
There are 2 main sides to getting this working and that is the actual reference and then ensuring managed identity is set up correctly to allow the Function App to read from App Configuration.
Configuration
The following is a Bicep example of adding a reference to a value which includes a label. I've previously covered off a Versioned App Configuration approach and this is a follow on from that.
resource functionAppSettings 'Microsoft.Web/sites/config@2022-03-01' = {
parent: functionAppResource
name: 'appsettings'
properties: {
AzureWebJobsStorage: '@Microsoft.KeyVault(SecretUri=https://${keyvaultName}${az.environment().suffixes.keyvaultDns}/secrets/AzureWebJobsStorage/)'
FUNCTIONS_EXTENSION_VERSION: '~4'
FUNCTIONS_WORKER_RUNTIME: 'dotnet-isolated'
MyAppConfigurationReference: '@Microsoft.AppConfiguration(Endpoint=https://${appConfigurationName}.azconfig.io; Key=MyAppConfigurationReference; Label=${version})'
}
}
Managed Identity
The MI approach:
var roleDefinitionAppConfigReaderId = subscriptionResourceId('Microsoft.Authorization/roleDefinitions', '516239f1-63e1-4d78-a4de-a74fb236a071')
resource appConfigurationResource 'Microsoft.AppConfiguration/configurationStores@2022-05-01' existing = {
name: appConfigurationName
}
resource roleDefinitionAppConfigurationFunctionApp 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(subscription().subscriptionId, resourceGroup().name, 'something-relevant-to-the-role-assignment')
scope: appConfigurationResource
properties: {
roleDefinitionId: roleDefinitionAppConfigReaderId
principalId: functionAppResource.identity.principalId
}
}
The GUID in the variable at the top is actually the role definition ID for the App Configuration Data Reader role, it's an OOTB role and defined so all Azure subscriptions should be able to use it. it's easy to check though within IAM of the App Configuration resource:
Summary
I am a fan of centralised configuration which is not duplicated across different resources so that's why I use App Configuration, this is just another useful approach that can help with that journey.