Particular / NServiceBus.AzureFunctions.InProcess.ServiceBus

Process messages in AzureFunctions using the Azure Service Bus trigger and the NServiceBus message pipeline.
Other
10 stars 5 forks source link

Support Microsoft Entra ID authentication #390

Closed andreasohlund closed 3 months ago

andreasohlund commented 2 years ago

Description

Microsoft Entra ID authentication is now supported for In-Process Azure functions.

Documentation

https://docs.particular.net/nservicebus/hosting/azure-functions-service-bus/in-process/#configuration-servicebus-connection

Once [we update to the latest SDK](https://github.com/Particular/NServiceBus.AzureFunctions.InProcess.ServiceBus/issues/340) we should also make sure that we support https://docs.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus-trigger?tabs=csharp#identity-based-connections ## Workaround ```c# public override void Configure(IFunctionsHostBuilder builder) { builder.UseNServiceBus(hostConfig => { var epConfig = new ServiceBusTriggeredEndpointConfiguration(EndpointName); var serviceBusFullyQualifiedName = hostConfig[$"AzureWebJobsServiceBus:fullyQualifiedNamespace"] ?? throw new Exception( $"Azure Service Bus connection string namespace has not been configured. " + $"Specify a connection string through an IConfiguration property named {{AzureWebJobsServiceBus__fullyQualifiedNamespace}}."); epConfig.Transport.ConnectionString(serviceBusFullyQualifiedName); epConfig.Transport.CustomTokenCredential(new DefaultAzureCredential()); return epConfig; }); ``` Thanks to @benagain https://github.com/benagain/FunctionAppWithAsbAndMI/blob/master/NServiceBusInProcess_2x/Startup.cs
andreasohlund commented 2 years ago

Talking to @mauroservienti (and also @danielmarbach ) we think the best way for this to work is to make the azure servicebus transport be able to accept an already existing ServiceBusClient and then modify our generated function endpoint to inject accept the client that is provided by the function host and use that one.

This means that we don't have to add any code to support identity-based connections

madhugilla commented 2 years ago

@andreasohlund , i tried the same thing but with "User Managed Identity" rather than system assigned, the message just sits in the service bus queue and is not picked up by the azure function, there are no error logs in appinsights.

i have checked that the user assigned identity has the appropriate roles in the azure service bus (Data owner). any pointers ?

the code is below

` var userAssignedClientId = "xxxxxxxxxxxxx"; var credential = new DefaultAzureCredential(new DefaultAzureCredentialOptions { ManagedIdentityClientId = userAssignedClientId });

        config.Transport.ConnectionString("xxxxxxxxxxxxxxxxxx.servicebus.windows.net");
        config.Transport.CustomTokenCredential(credential);`
andreasohlund commented 2 years ago

Have you also set the connection string in the settings to make sure the trigger also uses the same setting?

see https://github.com/benagain/FunctionAppWithAsbAndMI/blob/master/NServiceBusInProcess_2x/local.settings.json

madhugilla commented 2 years ago

yes, we have the same settings. System Assigned MI works without an issue, but UserAssinged MI does not work.

andreasohlund commented 2 years ago

@SzymonPobiega wasn’t there some quirk with user assigned ids and asb?(I remember something about having to grant extra permissions for it to work when we tested with ServiceControl)

SzymonPobiega commented 2 years ago

@andreasohlund I don't remember :(

madhugilla commented 2 years ago

one more thing i noticed is that there are no "Exceptions" or errors logged, for us to debug this further, the message just sits in the queue.

andreasohlund commented 2 years ago

Does the message get consumed if you remove nservicebus and just create a plain vanilla servicebustrigger for the queue?

andreasohlund commented 2 years ago

@madhugilla did you get a plain vanilla trigger working?

madhugilla commented 2 years ago

Hey the vanilla trigger is not working as well, the message just sits in the queue

SeanFeldman commented 2 years ago

@madhugilla, in that case, it's not the issue with the NSB package. If this is a lower environment and not production, try recreating the queue and security settings to see if that fixes the plain Functions trigger. If it does, then try NSB wrapper.

shawnz88 commented 2 years ago

I am having the same issue for NServiceBus.AzureFunctions.Worker.ServiceBus (isolated process). Is there a similar workaround as the in-process hosting model?

andreasohlund commented 2 years ago

The workaround mentioned in the description should work for the isolated worker model as well, can you confirm?

shawnz88 commented 2 years ago

Yeah it worked.

var host = new HostBuilder()
    .ConfigureFunctionsWorkerDefaults((context, builder) =>
    {
        builder.UseMiddleware<AuthenticationMiddleware>();
    })
    .UseNServiceBus(configuration =>
    {
        var endpointConfiguration = configuration.AdvancedConfiguration;
        // Change the error queue name:
        endpointConfiguration.SendFailedMessagesTo("my-custom-error-queue");
        var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
        transport.ConnectionString(serviceBusNameSpaceFQDN);
        transport.CustomTokenCredential(new DefaultAzureCredential());
        endpointConfiguration.Pipeline.Register(typeof(ThrottlingBehavior), "API throttling");

        // Or disable the error queue to let ASB native dead-lettering handle repeated failures:
        configuration.DoNotSendMessagesToErrorQueue();
    })
    .Build();
shawnz88 commented 1 year ago

Even though the managed identity seems to work with the mentioned workaround with config above and the following packages:

Microsoft.Azure.Functions.Worker.Sdk Version="1.7.0" 
NServiceBus.AzureFunctions.Worker.ServiceBus Version="4.0.0-beta.2" 

The message handler keeps throws the following error so the messages just sit on the Azure service bus queue:

 {"Object reference not set to an instance of an object."}
 at NServiceBus.FunctionEndpoint.<Process>d__2.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at NServiceBus.FunctionEndpoint.<Process>d__1.MoveNext()
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at FunctionEndpointTrigger.<Run>d__2.MoveNext() in C:\source\ECS\InternalEmail\InternalEmailService\NServiceBus.AzureFunctions.Worker.SourceGenerator\NServiceBus.AzureFunctions.SourceGenerator.TriggerFunctionGenerator\NServiceBus__FunctionEndpointTrigger.cs:line 27

Any ideas on how to resolve it?

bakes82 commented 1 year ago

Does anyone have a working solution for this using azure functions? V4.1 has different ctor and what Im using doesnt work:

builder.UseNServiceBus(configuration =>
                               {
                                   var endpointConfiguration = configuration.AdvancedConfiguration;

                                   var transport = endpointConfiguration.UseTransport<AzureServiceBusTransport>();
                                   //transport.ConnectionString("mycoolbus.servicebus.windows.net");
                                   transport.CustomTokenCredential("mycoolbus.servicebus.windows.net", new DefaultAzureCredential());
                               });
mennolaan commented 9 months ago

Can someone from particular shine a light how to implement managed identity with v4.1 with azure functions in isolated mode? The documentation on the website doesn't explain it at all. We are running into obsolete methods like ServiceBusTriggeredEndpointConfiguration. Visual Studio tells us it expects AzureWebJobsServiceBus, wich we have done, it only has the fqdm.

kbaley commented 7 months ago

Hi @mennolaan Sorry for the late reply. We got our wires crossed internally with the feedback you provided about the sample. I'll reiterate what Adam mentioned there for anyone else following the issue. There's some working coming up about Managed Identity and we'll make sure to include updated documentation on isolated mode in Azure Functions.

mennolaan commented 3 months ago

Hi @mennolaan Sorry for the late reply. We got our wires crossed internally with the feedback you provided about the sample. I'll reiterate what Adam mentioned there for anyone else following the issue. There's some working coming up about Managed Identity and we'll make sure to include updated documentation on isolated mode in Azure Functions.

Hi there, curious what's the status on this feature is? Imho it should be incorporated into nservicebus as more and more companies are applying best practices and thus disallowing key based access.

andreasohlund commented 3 months ago

@mennolaan we are about to release identity-based support to our worker package https://github.com/Particular/NServiceBus.AzureFunctions.Worker.ServiceBus/pull/514

do you have any plans to migrate to it? (MS is deprecating the InProcess model, https://github.com/Particular/NServiceBus.AzureFunctions.InProcess.ServiceBus/issues/798)

We will look into this as well but has a lower priority at the moment

andreasohlund commented 3 months ago

This will be shipped in 4.4.0