Azure Service Bus: The connection string used for an Service Bus client must specify the Service Bus namespace host and either a Shared Access Key - azure

Why is my RootManageSharedAccessKey Connection String Invalid?
Code:
When executing the code below, I receive an error about an invalid connection string:
serviceBusClient <- new ServiceBusClient(connectionString)
Error:
System.NotImplementedException: 'The method or operation is not
implemented.'
System.ArgumentException: 'The connection string used for an Service
Bus client must specify the Service Bus namespace host and either a
Shared Access Key (both the name and value) OR a Shared Access
Signature to be valid. Parameter name: connectionString'
ConnectionString:
"Endpoint=sb://myNameSpace.servicebus.windows.net/;TransportType=AmqpWebSockets;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=*******************************************="
I also tried removing the TransportType property from the connection string:
"Endpoint=sb://myNameSpace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=*******************************************="
The connection string was derived from the Shared Access Policy of my Service Bus resource:
Context:
Xamarin.Forms (Android)
Azure.Messaging.ServiceBus
NuGet Packages:
Azure.Messaging.ServiceBus (7.11.1)
Xamarin.Forms (5.0.0.2545)

For those who may be interested, the root cause of this turned out to be that the connection string passed to ServiceBusClient was JSON-encoded, causing two quote literals to be embedded. As a result, there was no Endpoint= token present (it was "Endpoint=) which left the client unable to determine where to connect to.

Related

Azure.Messaging.ServiceBus Create a ServiceBusClient using a System Assigned Managed Identity

I'm migrating a servicebus client application from Microsoft.Azure.ServiceBus to use the current library Azure.Messaging.ServiceBus.
The application is a Worker Process running on a virtual machine in windows azure.
The VM has a system assigned managed identity which grants it access to service bus and we have been using it successfully with the old library for over a year.
On the old library we created a client using this connection string
Endpoint=sb://MyNamespace.servicebus.windows.net/;Authentication=Managed Identity
When I put that connection string into the constructor of Azure.Messaging.ServiceBus.ServiceBusClient I get the following error
The connection string used for an Service Bus client must specify the Service Bus namespace host and either a Shared Access Key (both the name and value) OR a Shared Access Signature to be valid. (Parameter 'connectionString')
I've been trawling through documents for some time now with no progress.
Is there anyway to make this work?
Ideally I would continue to use the connection string - developer machines do not have system assigned ID's so we develop with key based connection strings and let devops swap in the correct prod connection string.
UPDATE
Following on from Jesse's answer managed identity has to go trough a separate constructor which requires a namespace instead of an endpoint and an instance of ManagedIdentityCredential.
As I mentioned not all environments where we deploy have managed aged identities, some require a SharedAccessKey based connection string.
Instead introducing new "identity type" configuration parameters into our build process I've used a factory method to parse the connection string and call the correct constructor overload. Where its a managed identity It extracts the namespace from the endpoint setting.
I Hope its useful for others
private static ServiceBusClient CreateServiceBusClient(string connectionString)
{
var cs = new DbConnectionStringBuilder();
cs.ConnectionString = connectionString;
if (cs.ContainsKey("Authentication") &&
"Managed Identity".Equals(cs["Authentication"].ToString(), StringComparison.OrdinalIgnoreCase))
{
string endpoint = cs["Endpoint"].ToString() ?? String.Empty;
if (endpoint.StartsWith(#"sb://", StringComparison.OrdinalIgnoreCase)) endpoint = endpoint.Substring(5);
if (endpoint.EndsWith(#"/")) endpoint = endpoint.Substring(0, endpoint.Length - 1);
return new ServiceBusClient(endpoint, new ManagedIdentityCredential());
}
return new ServiceBusClient(connectionString);
}
it needs the Azure.Identity package and the namespace System.Data.Common for the connection string builder.
The clients in the Azure.Messaging.ServiceBus package support connection strings only in the format that the Azure portal returns them.
The ;Authentication=Managed Identity token that you've included in your connection string is not a known token and is ignored, so the client does not have the information needed to perform authorization. A managed identity cannot be specified via connection string.
To use a managed identity, you'll use one of the constructor overloads that accepts a fully qualified namespace and a TokenCredential. An example can be found in the package Overview docs. Any of the Azure.Identity credentials can be used; you may want to take take a look at the managed identity section of the Azure.Identity overview.

How to read connection string from key vault for Service Bus?

Here is how I instantiate the client in my Configure method:
services.AddSingleton<ServiceBusClient>(x => new ServiceBusClient(configuration.GetSection("ServiceBus:ConnectionString").Value, serviceBusClientOptions));
And this how my appsettings looks like:
{
"ServiceBus:ConnectionString": "#Microsoft.KeyVault(VaultName=MyVaultName;SecretName=MySecretName)"
}
However, I am getting the following exception:
The connection string used for an Service Bus client must specify the Service Bus namespace host and either a Shared Access Key (both the name and value) OR a Shared Access Signature to be valid. (Parameter 'connectionString'
What am I missing here?
Have you created a managed identity for you application and added access policies such that your app can GET this secret value from key vault?
Check out the official documentaion for this here : https://learn.microsoft.com/en-us/azure/app-service/app-service-key-vault-references
Also on a side note, have you tried directly adding the secret value as the appsetting value instead of referencing it from KV and see if that worked? (if yes then definitely its a permissions issue and NOT a problem with your C# app code.

Why am I getting connection error on calling notify on Azure SignalR

I have configured a SignalR resource on my Azure account and am sending a message to the SignalR Hub using the below snippet in an Azure Function written in C#:
await signalRMessages.AddAsync(new SignalRMessage()
{
Target = "notify",
Arguments = new object[] { requestBody }
});
However, I keep getting the below error.
A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond
I have also verified that the Azure function URL for negotiate function returns me the below information as expected.
{"endpoint":"https://xxxxxxx.service.signalr.net:5001/client/?hub=broadcast","accessKey":"yyyyyyy"}
Why am I getting the connection error and what could I change in my configuration?
This error means no server listening at specified ip/port that you are trying to connect to. It can be caused by using the wrong IP address or the wrong PORT.

User assigned managed identity with azure function - is it possible?

I was able set up System assigned managed identity for function that listens service bus: I turned on System Assigned identity in my function, changed connection string to 'Endpoint=my_endpoint;Authentication=ManagedIdentity' and assigned a role for function to use service bus.
My function code snippet is as follows:
[FunctionName("MyAwesomeFunction")]
public static async Task RunAsync([ServiceBusTrigger("myawesome-queue", Connection = "MyAwesomeConn")] string queueItem)
{
// func code
}
Now I'm trying to do the same but using User assigned identity: I created managed identity, added it to function and assigned a role for it in service bus. But looks like it doesn't work - messages don't get to my queue. Any advice? Thanks.
ManagedIdentity is not supported by service bus and Queue trigger. You have to use a complete connection string with a shared access signature.
As documented here: https://learn.microsoft.com/en-us/azure/azure-functions/functions-bindings-service-bus#add-to-your-functions-app

System.Private.CoreLib: Exception while executing function: System.Data.SqlClient: Keyword not supported: 'authentication'

I am writing a function to log information from every file uploaded to a blob storage account using entity framework core. When I try to connect to the azure sql db, I get the following error:
System.Private.CoreLib: Exception while executing function: BlobStorageLogging. System.Data.SqlClient: Keyword not supported: 'authentication'
I copied my connection string from the azure portal:
"DefaultConnection": {
"ConnectionString": "Server=tcp:dbserver.database.windows.net,1433;Initial Catalog=loggingdb;Persist Security Info=False;User ID={*****};
MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Authentication=\"Active Directory Integrated\";",
"ProviderName": "System.Data.SqlClient"
}
The code that is causing the error is:
var optionsBuilder = new DbContextOptionsBuilder<LoggingDBContext>();
var options = optionsBuilder.UseSqlServer(connectionString, providerOptions => providerOptions.CommandTimeout(60)).Options;
using (var context = new LoggingDBContext(options))
{
context.Database.ExecuteSqlCommand("TRUNCATE TABLE [dbo].[BlobInfo]");
I have tried removing the authentication but that resulted in an unauthorized error. Any help would be appreciated.
The exception is expected for now, check the thread.
SqlClient for .NET Core still does not support using the 'authentication' keyword in the connection string. That will happen when this issue is actually fixed.
In order to use AAD in the new version of SqlClient in .NET Core 2.2, customers need to obtain the access token themselves using ADAL.NET and then set the AccessToken property on the SqlConnection
It means in .NET Core, Active Directory Integrated authentication is unavailable, to use Active Directory password authentication, we have to obtain access token which seems not ideal in EF configuration.
The workaround is to use Connection string for SQL authentication.

Resources