Click here to Skip to main content
15,867,330 members
Articles / Hosted Services / Azure
Tip/Trick

Securing Azure Service Bus Queues with Shared Access Signatures

Rate me:
Please Sign up or sign in to vote.
5.00/5 (3 votes)
21 Jan 2016CPOL3 min read 12.2K   3   1
How to generate and use Shared Access Signatures for Azure Service Bus Queues

Introduction

In this tip, I show how you can secure access to a Microsoft Azure Service Bus queue by generating a Shared Access Signature.

Why Shared Access Signatures?

Whenever you’re working with resources in the cloud, whether you’re reading and writing data in blob storage or publishing and subscribing to messages on a queue, it’s always best to work with the “principle of least privilege”. In Microsoft Azure, this is achieved by using “Shared Access Signatures”.

A Shared Access Signature gives the holder of that signature access to a particular resource (like a blob or a queue), for a limited time, and with limited permissions (e.g. read only). The advantage is that you don’t need to give someone the full “connection string” just to allow them write to a specific blob, or post to a particular queue.

I have an article on my blog about how you can control access to an Azure Blob container with Shared Access Signatures, and it is relatively straightforward. However, when I tried to do the same for a Service Bus namespace, it turned out to be a bit trickier than I hoped, as the MSDN documentation omits certain key details.

So in this tip, I’ll demonstrate how we can create a Shared Access Signature that we can give someone to allow them to read messages off a specific queue.

Creating a Shared Access Signature

First of all, we need to create an authorization rule for our queue. You don’t need to create one for every SAS token you want to generate, just one for each set of permissions you want to grant.

Typically, you’d create one with “Listen” rights, and one with “Send” rights. The following code snippet shows us checking if the queue exists, and creating it if needed, and then checking if the shared access authorization rule exists, and creating it if needed. (Obviously, this rule is created by a process that does have the privileges to create shared access authorization rules).

C#
// service bus connection string
var connectionString = "Endpoint=sb://mynamespace.servicebus.windows.net/;
SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=sgjasdhgjkasdhgawe3857238212";
const string queueName = "MyTestQueue";

// first ensure the queue exists
var namespaceManager = NamespaceManager.CreateFromConnectionString(connectionString);
if (!namespaceManager.QueueExists(queueName))
{
    namespaceManager.CreateQueue(queueName);
}

// make a shared authorization rule which will have listen privileges
var sharedAccessAuthorizationRuleKeyName = "MyQueue_Listen"; 

// find out if the authorization rule already exists:
var queueDescription = namespaceManager.GetQueue(queueName);
var authRule = queueDescription.Authorization
    .OfType<SharedAccessAuthorizationRule>()
    .FirstOrDefault(a => a.KeyName == sharedAccessAuthorizationRuleKeyName);
    
// if it doesn't:
if (authRule == null)
{
    // create a new authorization rule, with listen rights 
    authRule = new SharedAccessAuthorizationRule(
        sharedAccessAuthorizationRuleKeyName,
        SharedAccessAuthorizationRule.GenerateRandomKey(), // generate a primary key for this rule
        new[] { AccessRights.Listen }); // this rule only allows listening
        
    // add this to the list of authorization rules
    queueDescription.Authorization.Add(authRule);
    // actually update the queue with the new list of rules
    namespaceManager.UpdateQueue(queueDescription);
}

Now we’re ready to create the shared access signature itself (with thanks to Brent for pointing me in the right direction here). We can choose an expiry time for the signature, which ideally would be fairly short. And we generate the Shared Access Signature like this:

C#
var expiry = TimeSpan.FromMinutes(30);
var serviceUri = ServiceBusEnvironment.CreateServiceUri
("https", "mynamespace", queueName).ToString().Trim('/');
string generatedSaS = SharedAccessSignatureTokenProvider
          .GetSharedAccessSignature(sharedAccessAuthorizationRuleKeyName,
?                                    authRule.PrimaryKey, serviceUri, expiry);

Now we have a signature which will look something like this:

SharedAccessSignature sr=https%3a%2f%2fmynamespace.servicebus.windows.net%2fMyTestQueue&
sig=fFWmdMmWjsdTqPyhyvRS9LQqLjJNPc87xhInhYai9OM%3d&se=1453286209&skn=MyQueue_Listen

This is the string we can give to the client we want to grant access to. Obviously it’s still a secret, but if it does leak, the potential damage is limited to only listening on this one queue, and only for the specified duration.

Using the Shared Access Signature

Now we’re ready to actually use the Shared Access Signature, and we do that with the TokenProvider and MessagingFactory. These will allow us to create a QueueClient which we can use to receive a message (since our Shared Access Authorization Rule specified listen permissions).

C#
var tp = TokenProvider.CreateSharedAccessSignatureTokenProvider(generatedSaS);
var mf = MessagingFactory.Create("sb://mynamespace.servicebus.windows.net", tp);
var listenClient = mf.CreateQueueClient(queueName);

// receive a message
var rxMessage = listenClient.Receive(TimeSpan.FromSeconds(10));

And for completeness, let’s check that our permissions really worked. We’ll try to send a message on this listen client. And we’ll try to create a new listen client for another queue that we weren’t granted access to:

C#
try
{
    listenClient.Send(new BrokeredMessage("should not be sent"));
    throw new InvalidOperationException("SHOULD HAVE BEEN BLOCKED");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Very good - can't send");
}

try
{
    var listenClient2 = mf.CreateQueueClient("AnotherQueue");
    var m = listenClient2.Receive();
    throw new InvalidOperationException("SHOULD HAVE BEEN BLOCKED");
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("Very good - can't listen on another queue");
}

Anyway, that’s it for creating Shared Access Signatures with Azure Service Bus queues. For topics, it’s a little more involved as you’ll want to grant manage rights to allow the holder of the SAS token to create a subscription, but otherwise the process is roughly the same.

History

  • 21 Jan 2016 - Initial version
This article was originally posted at http://markheath.net/post/azure-service-bus-sas

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer (Senior)
United Kingdom United Kingdom
Mark Heath is a software architect working for NICE Systems and also creates courses for Pluralsight. He is the author of several open source projects, including NAudio, an audio library for the .NET platform.

Comments and Discussions

 
QuestionMicrosoft.ServiceBus.dll Version? Pin
granadaCoder8-Sep-16 10:41
granadaCoder8-Sep-16 10:41 
Can you list the version of
C#
Microsoft.ServiceBus.dll

that you used?

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.