Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Hosted-services / Azure

Shared Access Policies for Azure Tables and Containers

5.00/5 (2 votes)
22 Nov 2015CPOL4 min read 11.4K   49  
Set and use Shared Access Policies with storage tables and containers to provide an extra layer of security for your Azure credentials.

Introduction

I wanted to perform Azure table and blob crud transactions in my code behind for an ASP.NET website, but I wanted an added layer of security for my Azure credentials. Then, as my Azure storage accounts grew to dozens, each with dozens of tables & containers, the need for an easy and efficient way of keeping track of Stored Access Policies became a priority. I wanted a dashboard – I wanted to make it in WPF and wanted to do it entirely in C# - no xml, no http. Thought I would share some of what I learned along the way and put everything together in one place.

Requirements

You’re going to need to add a reference to Azure Storage to your project. In Visual Studio, right click on your project and go to Manage NuGet Packages… find and install WindowsAzure.Storage

You will need to add some or all of the following, depending on what you’re doing.

C#
using Microsoft.WindowsAzure.Storage;
using Microsoft.WindowsAzure.Storage.Blob;
using Microsoft.WindowsAzure.Storage.Table;
using Microsoft.WindowsAzure.Storage.Auth;

Getting the Storage Account

C#
string storageAccountName = "yourStorageAccountName";

string key = "eitherYourPrimaryOrSecondaryKey";

string connection =
    String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", 
        storageAccountName, key);

CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connection);

Make a table policy

CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

//if you need to see a list of tables in this storage account...
IEnumerable<CloudTable> tables = tableClient.ListTables();

CloudTable table = tableClient.GetTableReference("yourTableName");

SharedAccessTablePolicies permissions = table.GetPermissions().SharedAccessPolicies;

There is a limit of 5 policies that can be set on any one table or container. If you already have 5, your attempt to set another will fail. Clear them like this:

permissions.SharedAccessPolicies.Clear();

SharedAccessTablePolicies are actually a collection of type KeyValuePair<string, SharedAccessTablePolicy>, the key being the name of the policy, the value the actual policy - you make one like this:

SharedAccessTablePolicy newPolicy = new SharedAccessTablePolicy();

You must set an expiration date/time for the policy – it’s recommended that you don’t set anything less than 15 minutes to allow for potential differences in server clocks.

newPolicy.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(1);

You can optionally set a start time - if you don’t specify a policy.SharedAccessStartTime the policy will be in effect immediately. You can either add permissions all in one shot like so:

newPolicy.Permissions = SharedAccessTablePermissions.Query | SharedAccessTablePermissions.Add | 
    SharedAccessTablePermissions.Update | SharedAccessTablePermissions.Delete;

or add them one at a time like this

newPolicy.Permissions |= SharedAccessTablePermissions.Query;
newPolicy.Permissions |= SharedAccessTablePermissions.Add;
newPolicy.Permissions |= SharedAccessTablePermissions.Update;
newPolicy.Permissions |= SharedAccessTablePermissions.Delete;

When you’re finished you’ll return a new

KeyValuePair<string, SharedAccessTablePolicy>( "yourNewPolicyName", newPolicy);

Add your new policy into the existing set of permissions (assuming there are less than 5 existing policies)

permissions.SharedAccessPolicies.Add(newPolicy.Key, newPolicy.Value);

When you’re finished making your policies, set them like so:

table.SetPermissions(permissions);

Your new policy generates a SharedAccessSignature - looks something like this:

"?sv=2015-04-05&tn= yourTableName &sig=bb%2SjxB0Q1eFnBAJ71KhU0IjzqW2YeeqvSG8cx%2BlHkpo%3D&se=2017-11-19T20%3A03%3A03Z&sp=raud";

The sv=2015-04-05 is the server version used to create the policy.

The table name this policy is written against

tn= yourTableName

The signature itself

sig=bb%2SjxB0Q1eFnBAJ71KhU0IjzqW2YeeqvSG8cx%2BlHkpo%3D

Next is the expiration date

se=2017-11-19T20%3A03%3A03Z

Followed by what permission are allowed

sp=raud

This one allows for read, add(write), update and delete

So, to put it all together, let’s say we’re going to overwrite all existing policies and make three separate policies, one read, one write and one update, all with an expiration date 2 years in the future. I’m going to name each policy with the table name appended with the permission it grants.

C#
void SetReadWriteUpdate(string tableName)
{
    string storageAccountName = "yourStorageAccountName";

    string key = "eitherYourPrimaryOrSecondaryKey";

    string connection = 
        String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", 
            storageAccountName, key);

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connection);

    CloudTableClient tableClient = storageAccount.CreateCloudTableClient();

    CloudTable table = tableClient.GetTableReference(tableName);

    SharedAccessTablePolicies permissions = table.GetPermissions().SharedAccessPolicies;

    permissions.SharedAccessPolicies.Clear();

    SharedAccessTablePolicy policyRead = new SharedAccessTablePolicy();
    policyRead.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(2);
    policyRead.Permissions = SharedAccessTablePermissions.Query;
    permissions.SharedAccessPolicies.Add(new KeyValuePair<string, 
        SharedAccessTablePolicy>(tableName + "Read", policyRead));


    SharedAccessTablePolicy policyWrite = new SharedAccessTablePolicy();
    policyWrite.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(2);
    policyWrite.Permissions = SharedAccessTablePermissions.Add;
    permissions.SharedAccessPolicies.Add(new KeyValuePair<string, 
        SharedAccessTablePolicy>(tableName + "Write", policyWrite));


    SharedAccessTablePolicy policyUpdate = new SharedAccessTablePolicy();
    policyUpdate.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(2);
    policyUpdate.Permissions = SharedAccessTablePermissions.Update;
    permissions.SharedAccessPolicies.Add(new KeyValuePair<string, 
        SharedAccessTablePolicy>(tableName + "Update", policyUpdate));

    table.SetPermissions(permissions);
}

Edit a Single Table Policy

If you’re just looking to update a single policy, you need to first remove it from the existing set of policies, make a new one and add it back into the collection of policies and set them back to the table.

C#
SharedAccessTablePolicies permissions = table.GetPermissions().SharedAccessPolicies;

permissions.SharedAccessPolicies.Remove("theNameOfThePolicyToRemove");

SharedAccessTablePolicy newPolicy = new SharedAccessTablePolicy();

//set new policy stuff

permissions.SharedAccessPolicies.Add(new KeyValuePair<string, 
    SharedAccessTablePolicy>("newPolicyName", newPolicy));

table.SetPermissions(permissions);

Make container policy

Setting policies on containers is essentially the same but substitute the term Blob wherever you find Table. It’s a bit confusing, however because you’re setting policies on containers and not blobs as the name would imply. Another difference is that container permissions allow for listing but not updating - it’s a container, you can’t update the container itself. Listing allows for listing of the blobs held in the container – you do it the same way you listed tables above.

C#
void SetPermissionsContainer(string yourContainerName)
{
    string storageAccountName = "yourStorageAccountName";

    string key = "eitherYourPrimaryOrSecondaryKey";

    string connection = 
       String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}", 
            storageAccountName, key);

    CloudStorageAccount storageAccount = CloudStorageAccount.Parse(connection);

    CloudBlobClient blobClient = storageAccount.CreateCloudBlobClient();

    CloudBlobContainer container = blobClient.GetContainerReference(yourContainerName);

    BlobContainerPermissions permissions = container.GetPermissions().SharedAccessPolicies;

    SharedAccessBlobPolicy policy = new SharedAccessBlobPolicy();

    policy.SharedAccessExpiryTime = DateTime.UtcNow.AddYears(2);

    policy.Permissions |= SharedAccessBlobPermissions.Read;

    policy.Permissions |= SharedAccessBlobPermissions.Write;

    policy.Permissions |= SharedAccessBlobPermissions.Delete;

    policy.Permissions |= SharedAccessBlobPermissions.List;

    permissions.SharedAccessPolicies.Add(policy.Key, policy.Value);

    table.SetPermissions(permissions);
}

Getting the signature

Now that you have a stored access policy, what do you do with it? You will need to know what table (or container) it’s written for and the policy name.

C#
string GetSignature(CloudTable table, string policyName)
{
    SharedAccessTablePolicies policies = table.GetPermissions().SharedAccessPolicies;

    SharedAccessTablePolicy policy = policies[policyName];

    return table.GetSharedAccessSignature(policy);
}

Now you can use that signature in your applications or give it to another person to use, and your Azure credentials are kept confidential. To use it, you’ll need the signature itself, the storage account name and the table name.

Using the Signature

C#
void UseMyNewPolicy(string signature, string accountName, string tableName)
{
    StorageCredentials creds = new StorageCredentials(signature);

    string endpoint = string.Format("https://{0}.table.core.windows.net", accountName);

    CloudTableClient client = new CloudTableClient(new Uri(endpoint), creds);

    CloudTable table = client.GetTableReference(tableName);
}

And now the user can perform whatever operations are allowed against the table.

Here’s a shot of the finished dashboard:

Image 1

Additional resources

Designing a Scalable Partitioning Strategy for Azure Table Storage

License

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