The Windows Azure AppFabric Service Bus team has been good about providing sample code for the various features it develops. There are also a fair number of blog posts (and books) showing how to use these features. Pretty much all the sample code authenticates operations on the Service Bus via a service identity/password combination where the service identity takes the special value of owner.
In this post, I am going to show how to create and configure a service identity other than owner, and specifically how to ensure that this service identity is less privileged than owner. The intent is to show that, notwithstanding the lack of examples, it is pretty easy to use an alternate service identity. As of mid-September, the Service Bus support ACS v2 – and that is what the material in this post was tested with.
Service Bus Namespace
The starting point for all work with the Service Bus is the service namespace which is created and configured on the Windows Azure Portal. In creating a namespace, a unique name must be provided as well as the location of the Windows Azure datacenter which will host the service endpoints for the namespace. The namespace name becomes the first part of the URI used for these service endpoints. For example, if the namespace name is gress then the service gateway for the gress namespace becomes:
The various services supported by the Service Bus – including relayed and brokered messaging – are hosted at service paths under the service gateway:
For example, the following are valid service paths:
Note that a service path must be specifically associated with a service for the path to have any meaning with regard to a service. For example, although the first service path above probably specifies a topic named topic/interestingtopic there is nothing to prevent it being used instead for a relayed service. The second probably specifies a subscription named somesubscription on a topic named boringtopic. The third likely specifies a relayed service named EchoService.
The paths for a namespace nominally form an infinite tree with the / indicating a branch point. For example, the following shows a namespace with two branches, one for services and the other for topics:
Service Bus Claims
The Service Bus uses the Windows Azure Access Control Service (ACS) for authentication and authorization. The ACS is a Security Token Service (STS) existing as part of claims-based infrastructure. Although it supports limited identity provider (IdP) capability, the primary function of the ACS is in transforming claims in support of federated identity.
This post assumes and requires only minimal understanding of claims-based authentication. The Microsoft Patterns and Practices Team has recently published the second edition of its excellent Guide to Claims-Based Identity and Access Control. This is a good resource for a much deeper understanding of the topic.
When a Service Bus namespace is created, it is associated with a default service identity named owner and a base64-encoded key. This service identity has absolute control of the namespace, including all service paths in it, so it is essential that the associated key be kept secure. This is made even more important by the fact that it is not possible to change the key on the Windows Azure Portal. The default service identity and key can be used to authenticate Service Bus API requests against services hosted by the namespace.
The Service Bus supports three claims which authorize specific operations on a service path. These claims are all of type net.windows.servicebus.action with values:
The different values authorize the obvious sets of operations on service paths. For example, the Send claim is required to perform the following operations:
- Send messages to a listener at a service namespace (relay)
- Get the queue description
- Send into to the queue
- Get the topic description
- Send to the topic
The complete list of operations and associated authorization requirements is provided in the MSDN documentation, which provides an official take on the material in this post.
When the default service identity, owner, authenticates against the ACS a rule is invoked that assigns all three claims to owner thereby authorizing it to perform any operation on any service path in the namespace. Note that this discussion elides a lot of claims-based identity plumbing that is, in practice, hidden from the user of the Service Bus API. Although possible, it is strongly recommended that none of the claims be removed from the authorization provided to owner. Doing so can cause significant problems with the namespace.
It is possible to create another service identity with limited privileges, e.g. without the Manage claim. Indeed, it is possible to create a service identity and associate it with only one of the claims. This allows, for example, a sending service identity to be created with only the Send claim and a listening service identity to be created with only the Listen claim. Doing so allows a sending application to be distributed without the possibility of a service identity with a Manage claim being compromised.
By default, owner has Manage, Send and Listen claims over the infinite path tree of the namespace. It is possible to restrict additional service identities to only part of the service path tree. For example, if a service identity is used only to send messages to a topic there is no need for that service identity to have any claims other than Send on the specific service path associated with the topic. The ACS supports this type of restriction, and evaluates whether a service identity has the required permission for an operation by doing a longest string match on the service path. Essentially, it works its way back along the service path seeking a portion of the path for which the service identity has the needed permission. The service identity is authorized to perform a specific operation only if somewhere on the service path it is configured with the required claim and that permission has not been removed later in the path. This permission inheritance is similar to that on a file system. Note that it can cause problems if owner has permissions removed for a service path.
Suggesting that something is a best practice is probably a fair bit above my pay grade. But here goes with some recommended practices:
- Do not use owner for an operation that does not require the full privileges and claims of owner.
- Use a service identity with the minimum set of claims needed for a service path.
- Associate a service identity with the longest service path possible.
Consider the following two full service paths representing a topic and an associated subscription:
If the topic and subscription are created out of band, distinct service identities can be created to authorize sending messages to the topic and receiving messages from the subscription. The sending service identity can be given the Send claim for the topics/interestingtopic service path. The listening service identity can be given the Listen claim for the topics/interestingtopic/subscriptions/mysubscription service path. Separating the privileges like this minimizes the possible damage from a compromised service identity.
Using an alternative service identity is a little bit more complicated than using owner. However, the Window Azure Service Bus team has provided a command-line utility, SBAzTool, that makes it very easy to add service identities and associate them with service paths.
The SBAzTool is one of the samples provided with the Windows Azure AppFabric SDK v1.5 (September 2011). It is in the ServiceBus/ExploringFeatures/Authorization/ManagingAccessControl directory of the samples. The source code is also supplied in case you want to roll your own service management utility.
The following commands create two new service identities, topicSender and subscriptionListener, and grants the topicSender the Send claim on the topic (from the previous section) and the subscriptionListener the Listen claim on the associated subscription.
sbaztool -n gress -k xkx…6o= storeoptions
sbaztool makeid topicSender
sbaztool grant Send /topics/interestingtopic topicSender
sbaztool makeid subscriptionListener
sbaztool grant Listen /topics/interestingtopic/subscriptions/mysubscription subscriptionListener
The storeoptions option is used to store the namespace and the owner key in isolated storage for the SVAzTool – and the clearoptions option removes the information from isolated storage. The SBAzTool can also be used to delete service identities and revoke permissions, as well as display information about service identities and service paths.
SBAzTool makes it really easy to configure service identities and service paths so that service identities other than owner can be used. Consequently, there is no real excuse for not doing so.
Having done all this, we can replace the following code:
TokenProvider tokenProvider =
TokenProvider tokenProvider =
Windows Azure Portal – Access Control Service
The configuration performed by SBAzTool can also be performed manually on the ACS section of the Windows Azure Portal. The UI for ACS configuration on the portal may appear overkill in terms of what has been discussed so far. However, ACS has a much broader use than authorization on the Service Bus.
Clemens Vasters recently made a video of a presentation in which he steps carefully through the process of configuring an issuer and service path. Consequently, I will not repeat the steps here, and will merely put the configuration performed by SBAzTool into the context of the portal.
The makeid option with SBAzTool creates a Service Identity (visible on the portal) that can be authenticated with either a symmetric key or a password. Clemens suggests that the values of these should be the same, and that is what SBAzTool does.
The grant option with SBAzTool creates a Relying Party Application (visible on the portal) for the full service path, e.g.
Note that the full service path is normalized to specify http rather than any other protocol. Additionally, the tool specifies a token format of SWT and sets the token lifetime to 1200s.
The tool also creates a Service Group (visible on the portal) and associates it with the relying party application configuration for the service path. It also associates the service group with each intermediate service path en route to the service path. This service group generates the appropriate Manage, Send and Listen claims configured by the grant (and revoke) option of SBAzTool. The tool also adds a default service group which generates the Manage, Send and Listen claims for owner on the service path and each intermediate service path. This is to prevent owner not having full rights on the namespace.
Note that currently there is a bug in the portal which causes a problem when following the instructions in the video. Specifically, when creating a relying party application on the portal it is not possible to save the configuration without generating a token signing key. However, doing so causes an error when accessing the service path from an application. The workaround is to go the Certificates and keys section of the ACS configuration on the portal and delete the created token-signing certificate. Everything works fine once that is done.
My intent in this post was not to give a deep explanation of how to use a claims-based identity framework to secure the Service Bus. Rather, my intent was to provide the minimum amount of information allowing the reader to replace the use of owner with that of a less-privileged service identity. Specifically, I wanted to show how easy it is to do so using the SBAzTool.