I am implementing a library for publisher and consumers of events to communicate through Azure Service Bus and I thing MassTransit could be a good option.
I am able to work publish multiple events with it, and have several consumers receiving them without any issue if I let MassTransit create whichever topics it needs and by specifying on the consumer just a receiver endpoint for the 3 event types where I specify a queue name.
Example consumer:
var busControl =
Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
CreateAzureServiceBusHost(cfg, serviceBusUri, serviceBusKeyName, serviceBusKey);
cfg.ReceiveEndpoint(queueName, endpoint =>
{
foreach (var eventDtoType in eventsTypes)
{
var adapterType = typeof(EventHandlerAdapter<>).MakeGenericType(eventDtoType);
var resolvedType = sp.GetService(adapterType);
endpoint.Consumer(adapterType, type => resolvedType);
}
});
});
Notice that I specify as the consumer an EventHandlerAdapterType<TEvent>
because I have an adapter to abstract the event handlers from MassTransit. But this is irrelevant for this question.
The publisher is configured as follows:
var busControl =
Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
CreateAzureServiceBusHost(cfg, serviceBusUri, serviceBusKeyName, serviceBusKey);
});
The problem is that I need to use this library integrated with a system that creates its own topics and it has security around it (only certain apps can publish to it, only certain apps can read messages that have been published to that topic)
So I need to create a token sas for the publisher that wants to publish events on certain topics, and for the consumers who want to read from certain topics. The creation of token is out of scope for this question though.
MY SOLUTION ATTEMPT:
I prepare the following scenario in Azure Service Bus:
- Create topic topic-attempt-one
(enabled partition although not sure if relevant)
- Create a subscription subscription-attempt-one
inside that topic-attempt-one
- Create a shared access policy on the topic SamplePublishOnly
with send-only permissions
- Create a shared access policy on the topic SampleReadOnly
with listen-only permissions
I modify my sample so that the publisher uses the key and keyName as per SamplePublishOnly
and two consumers use the key and keyName as per SampleReadOnly
On the publisher, I configure it to use the same topic for the 3 different events.
var busControl =
Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
CreateAzureServiceBusHost(cfg, serviceBusUri, serviceBusKeyName, serviceBusKey);
// Here I add the same topic name for the 3 event types I want to publish.
cfg.Message<IEventOne>(topology =>
{
topology.SetEntityName("topic-attempt-one");
});
cfg.Message<IEventTwo>(topology =>
{
topology.SetEntityName("topic-attempt-one");
});
cfg.Message<IEventThree>(topology =>
{
topology.SetEntityName("topic-attempt-one");
});
});
The consumer I configure it with a receive endpoint (with one queue name for consumer one, and a different for consumer two) for the three messages with the addition of specifying exactly the topic and the subscription to use.
var busControl =
Bus.Factory.CreateUsingAzureServiceBus(
cfg =>
{
CreateAzureServiceBusHost(cfg, serviceBusUri, serviceBusKeyName, serviceBusKey);
cfg.ReceiveEndpoint(queueName, endpoint =>
{
//I specify the topic and subscription name that is already created in ServiceBus
endpoint.Subscribe("topic-attempt-one", "subscription-attempt-one");
foreach (var eventDtoType in eventsTypes)
{
var adapterType = typeof(EventHandlerAdapter<>).MakeGenericType(eventDtoType);
var resolvedType = sp.GetService(adapterType);
endpoint.Consumer(adapterType, type => resolvedType);
}
});
});
var busControlWrapper = new BusControlWrapper(busControl);
return busControlWrapper;
The consumers cannot start now the bus. There is a permission issue I think:
Microsoft.Azure.ServiceBus.UnauthorizedException: Manage,EntityRead claims required for this operation. TrackingId:2d6953d0-c8e1-4bdc-bed5-cc6e5d2d1f9e_G27, SystemTcker:sunnyatticsoftware.servicebus.windows.net:topic-attempt-one, Timestamp:2020-03-07T20:26:38
Ok so I decide to create two queues manually in Azure Service Bus for each consumers hoping that MassTransit can create virtual queues if it needs for the different messages.
- Create queue-one
- Create shared access policy with claims to only Listen and I call it QueueReadOnly
and try to use its keyName and key.
Nothing. A different error but still unable to make it work
Microsoft.Azure.ServiceBus.UnauthorizedException: claim is empty. TrackingId:9e344a3f-d40a-475d-bf61-7aae274ed2d1_G17, SystemTracker:sunnyatticsoftware.servicebus.windows.net:topic-attempt-one, Timestamp:2020-03-07T20:40:33
which kind of makes sense, because I am telling it to use a specific topic and subscription but not using the token with read permissions on them as I've replaced it with the queue one.
QUESTIONS
- is this the right approach for my scenario?
- is it ok to try to share the same topic for publishing 3 different message types? It seems the MassTransit design leads me to use one topic per message.
- how to achieve what I need? How do others deal with permissions if I don't want MassTransit publisher and consumers to use a
Manage
full-permission token because I don't want consumers, for example, to publish on a topic?
Thanks!
PS: I found a similar issue but unfortunately it does not solve my problem. How to specify which Azure Service Bus Topic to use with MassTransit
Update 1
I found this: Is it possible to use MassTransit 3 with Azure Service Bus without Manage permission policy?
which if it's still the case for the latest 6.2 version, it may explain why I'm getting those errors.
It's a pity if I can't use any claim other than 'Manage'. So, no granular permissions with Masstransit? How would one prevent an app that has a Manage
token from reading messaged it's not supposed to read?
If creating entities such as topics, subscriptions or queues is not an option, is it possible to use Masstransit?
I'm guessing I lack a lot of knowledge, so any link would also be appreciated!