Data is transferred between different applications and services using messages. A message is in binary format and can contain JSON, XML, or just text[1].
To authenticate to Service Bus is possible to use shared access key but then Service Bus connection string which contains this key should be stored in configuration files or code which make it not so secure. To make access to the Service Bus more secure is possible to use system-assigned managed identity and store Service Bus connection string in Key Vault or store Service Bus connection string in Key Vault and set trigger connection string at runtime.
Authentication through System-assigned managed identity.
For sending message to ServiceBus a system-assigned managed identity must be enabled for sender function application and assigned Azure Service Bus Data Owner role. Enabling a system-assigned managed identity for the function application will register this application with Azure Active Directory and grant it permissions to access resources protected by Azure AD.
Assigning of Azure Service Bus Data Owner role to the function application will allow it to manipulate with Service Bus data (read from or send data to it).
To send message to Service Bus, should be initialized:
- TokenProvider for authorization;
- TopicClient for sending Messages.
1.Function requests authorization token.
1.1. Token is requested from active directory using system-assigned managed identity for verification.
1.2. Active directory validates received system-assigned managed identity. If system-assigned managed identity was successfully validated, active directory sends authorization token as a response.
2.Function using TopicClient class sends message with authentication token to Service Bus.
3.1. Service Bus automatically sends request to active directory to validate token.
3.2. Active directory validates token and send response. If token was successfully validated, Service Bus accepts message.
To trigger function from Service Bus must be:
- Enabled a system-assigned managed identity in receiver function application;
- Service Bus connection string saved as secret in Key Vault;
- Receiver function application is granted with Get Secret permissions;
- Service Bus trigger Connection setting configured to
@Microsoft.KeyVault(SecretUri=https://<keyvaultstorage>.vault.azure.net/secrets/<SecretName>/<SecretVersion>)
1.Function requests Service Bus connection string as secret from KeyVault using system-assigned managed identity.
2. Active directory validates received system-assigned managed identity.
3.If system-assigned managed identity was successfully validated, Key Vault sends secret as a response.
4.Function initializes ServiceBusTrigger with connection string to receive Service Bus messages.
It is possible to implement sending messages to ServiceBus using user-assigned managed identity by implementing token provider for Service Bus, but possibility to configure ServiceBusTrigger using user-assigned managed identity is still not implemented by Azure [2].
This approach has such disadvantages:
- Azure Service Bus Data Owner role should be assigned to every function application which will trigger service bus.
- For receiving messages from Service Bus function application should be granted with Get Secret permissions by KeyVault.
It makes deployment of such system complicated.
Set Service Bus Trigger connection string at runtime
This approach uses WebJobsStartup configuration to change configurations of function applications during its startup [6]. To implement this we should create a class which implements IWebJobsStartup, with function Configure. Inside of this function Service Bus connection string is received as the secret from KeyVault. Then using post configure options, Service Bus Trigger connection string is set to received value.
To trigger function from Service Bus must be:
- Service Bus connection string saved as secret in Key Vault
- Added to function application user-assigned managed identity with permissions to read KeyVault secrets.
- Connection parameter of ServiceBus and ServiceBusTrigger attribute assigned to an empty string.
- Used class inherited from WebJobsStartup which sets up ServiceBus Connection parameter.
builder.Services.PostConfigure<ServiceBusOptions>(options =>
{
options.ConnectionString = keyVault.GetSecretValue("ServiceBusConnectionString");
});
1. By function application startup runs Configure method from FunctionWebJobsStartup class
1.1 Using user-assigned managed identity it requests Service Bus connection string as a secret from KeyVault
1.2 KeyVault verifies managed identity.
1.3 In case it has permissions to read secrets, returns secret.
1.4 Configure method receives connection string and sets it to ConnectionString parameter of Service Bus options.
2. Then this parameter will automatically fill Connection value of ServiceBus or ServiceBusTrigger attributes for appropriately sending to or receiving messages from Service Bus.
Attention!!! To make startup configuration working properly, Connection value initially must be assigned with an empty string.
3. Functions of this function application start and do their work in cooperation with Service Bus.
-------------
- https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-messaging-overview
- https://docs.microsoft.com/en-us/azure/app-service/app-service-key-vault-references
- https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-create-namespace-portal
- https://docs.microsoft.com/en-us/azure/service-bus-messaging/service-bus-managed-service-identity
- https://docs.microsoft.com/en-us/dotnet/api/microsoft.servicebus.tokenprovider?view=azure-dotnet
- https://briandunnington.github.io/azure_functions_dynamic_connection_string