Azure Service Bus with Bicep & Managed Identity in ASP.NET Core

Azure Service Bus can be used by clients with two different authentication mechanisms – either through Shared access policies with Manage, Send and Listen capabilities or through the Role-based access control (RBAC). The latter one is recommended as it also allows you to make use of Managed Identites instead of relying on connection strings. In this post we’ll take a look at how this can be set up using Bicep and connected to an ASP.NET Core app.

Btw. you can run both mechanisms in parallel for example if you need to connect a client that does not support Managed Identities.

First we create our service bus and output its name for later reference.

param serviceBusName string
param location string
resource serviceBus 'Microsoft.ServiceBus/namespaces@2021-11-01' = {
name: serviceBusName
location: location
sku: {
name: 'Standard'
}
}
output name string = serviceBus.name

Next we create a reusable module to assign Service Bus roles to Managed Identites e.g. for WebApps or Functions. There are three different roles available: Reader, Sender and Owner. Each have their own global role Id that we need to use depending on the permissions we want to set.

param serviceBusName string
param principalId string
@allowed([
'Reader'
'Sender'
'Owner'
])
param role string
var readerRoleId = '4f6d3b9b-027b-4f4c-9142-0e5a2a2247e0'// Azure Service Bus Data Receiver
var senderRoleId = '69a216fc-b8fb-44d8-bc22-1f3c2cd27a39'// Azure Service Bus Data Sender
var ownerRoleId = '090c5cfd-751d-490a-894a-3ce6f1109419'// Azure Service Bus Data Owner
var roleId = role == 'Reader' ? readerRoleId : role == 'Sender' ? senderRoleId : ownerRoleId
resource servicebus 'Microsoft.ServiceBus/namespaces@2021-11-01' existing = {
name: serviceBusName
}
resource roleAssignment 'Microsoft.Authorization/roleAssignments@2022-04-01' = {
name: guid(servicebus.id, roleId, principalId)
scope: servicebus
properties: {
roleDefinitionId: subscriptionResourceId('Microsoft.Authorization/roleDefinitions', roleId)
principalId: principalId
}
}

Lastly we call the role assignment modules with the apps Principal Id, Service Bus name and desired role name. In this example we have a function app that listens to queue messages and a web app that can send them.

module serviceBusAssign 'service-bus-role-assignment.bicep' = {
name: 'sb-assign-notifications-${envName}'
params: {
serviceBusName: serviceBus.outputs.name
principalId: functionApp.outputs.principalId
role: 'Reader'
}
}
module serviceBusAssign 'service-bus-role-assignment.bicep' = {
name: 'sb-assign-${envName}'
params: {
serviceBusName: serviceBus.outputs.name
principalId: webappHttpApi.outputs.principalId
role: 'Sender'
}
}

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.