I'm trying to send a message to an Azure ServiceBus Queue from an Azure Function (C#). In order to do that I need the ConnectionString for the Service Bus Namespace (or possibly pass a Azure.Core.TokenCredential
).
I does work when passing the ConnectionString to the ServiceBusClient
constructor.
string connectionString = "Endpoint=sb://<servicebus-name>.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=<access-key>";
var client = new ServiceBusClient(connectionString);
var sender = client.CreateSender(queueName);
...
sender.SendMessagesAsync()
The thing is that deployment should be automated and the Function and the ServiceBus are deployed using a resource template. Hence, the SharedAccessKey
is created at deploy time. If I could read the AccessKey in the resource template I could set an Application Setting which could then be read by the Function. However, I can't find a way to get the AccessKey within the resource template. Is it possible?
Another thing I've tried is creating ServiceBusClient
using a TokenCredential
like this:
var credentials = new DefaultAzureCredential();
string[] ss = queueUrl.Split('/', StringSplitOptions.RemoveEmptyEntries);
var fullyQualifiedName = ss[^2];
var queueName = ss[^1];
var client = new ServiceBusClient(fullyQualifiedName, credentials);
var sender = client.CreateSender(queueName);
using ServiceBusMessageBatch messageBatch = sender.CreateMessageBatchAsync().Result;
When doing this I get:
Unauthorized access. 'Send' claim(s) are required to perform this operation. Resource: 'sb://<servicebus-name>.servicebus.windows.net/<queuename>'.
I don't fully understand how DefaultAzureCredential
is supposed to work. Is it possible to solve this permission issue in someway (This is in an Azure Function)?
My workaround
I have a workaround which requires an extra step after the resource template is deployed. Using the Azure CLI to read the ServiceBus Namespace ConnectionString and then update the application setting with that value. The Function is then reading the connection string from Application setting.
$ cs=$(az servicebus namespace authorization-rule keys list --namespace-name <Namespace> -n RootManageSharedAccessKey -g <resource-group> -o json | jq -r '.primaryConnectionString')
$ az functionapp config appsettings set --settings ServiceBusNamespaceConnectionStringCLI=$cs -g <resource-group> -n <function-name>
...
- name: ServiceBusNamespaceConnectionStringCLI
slotSetting: false
value: Endpoint=sb://<servicebus-name>.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=<access-key>
I'd prefer not using this extra step and do it all in the template or code if possible. Any ideas?
CodePudding user response:
Thanks to this answer Get the Service Bus SharedAccessKey Programatically Using Bicep I found out how to get the connectionString in the resource template. This is how I pass the connection string to the Function using an application setting.
"appSettings": [
{
"name": "ServiceBusConnectionString",
"value": "[listKeys(resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules', variables('serviceBusName'), ' RootManageSharedAccessKey'), '2021-06-01-preview').primaryConnectionString]"
}