How to Access an Blob Container Using Shared Access Signatures
I posted a while ago about how to get the total size of the blobs in your Azure container, and the first step for doing that was to create a connection string that included the storage account key. But what if you’d like to give someone access to read and write from a specific blob container without giving away the storage account key, which would allow them to do anything, including reading from other containers or creating new ones?
Create a Shared Access Signature
Well, the first step is that you need to create a Shared Access Signature, and it’s probably a good idea to base it on a Stored Access Policy. To do this you will of course need your storage account access key. You start off by creating a blob client and getting a reference to the container in the usual way.
Then you create a SharedAccessBlobPolicy
object and configure it how you want. For this example we’re letting the policy expire in 10 hours and allowing clients to read, write and list blobs in the specified container. Then you need to call SetPermissions
on the blob container, which will overwrite existing stored access policies, so take care if you have multiple policies. The example below shows how to get hold of the existing container’s permissions and add a new entry.
Finally we ask the blob container for a shared access signature calling GetSharedAccessSignature
. Don’t pass in your stored policy object here – you need to use the name you gave it instead. This will allow revocation later.
// some constants
var storageAccountName = "mystorageaccount";
var accessKey = // your storage account access key here
var policyName = "testpolicy";
var containerName = "testcontainer";
// connect to our storage account and create a blob client
var connectionString = String.Format("DefaultEndpointsProtocol=https;AccountName={0};AccountKey={1}",
storageAccountName,
accessKey);
var storageAccount = CloudStorageAccount.Parse(connectionString);
var blobClient = storageAccount.CreateCloudBlobClient();
// get a reference to the container
var blobContainer = blobClient.GetContainerReference(containerName);
blobContainer.CreateIfNotExists();
// create the stored policy we will use, with the relevant permissions and expiry time
var storedPolicy = new SharedAccessBlobPolicy()
{
SharedAccessExpiryTime = DateTime.UtcNow.AddHours(10),
Permissions = SharedAccessBlobPermissions.Read |
SharedAccessBlobPermissions.Write |
SharedAccessBlobPermissions.List
};
// get the existing permissions (alternatively create new BlobContainerPermissions())
var permissions = blobContainer.GetPermissions();
// optionally clear out any existing policies on this container
permissions.SharedAccessPolicies.Clear();
// add in the new one
permissions.SharedAccessPolicies.Add(policyName, storedPolicy);
// save back to the container
blobContainer.SetPermissions(permissions);
// Now we are ready to create a shared access signature based on the stored access policy
var containerSignature = blobContainer.GetSharedAccessSignature(null, policyName);
// create the URI a client can use to get access to just this container
var uri = blobContainer.Uri + containerSignature;
The generated URI will look something like this:
https://mystorageaccount.blob.core.windows.net/testcontainer?sv=2014-02-14&sr=c&si=testpolicy&sig=2PL7HC9aovDiA714jzzW5bgdbqwKmQwftxS%2FyGixp3g%3D
Use the Shared Access Signature to Access the Container
Now we can use this URI to allow access to just this container. This is the easy part. We’ll connect with the URI generated above, list the contents of the container, and upload a new text file.
var uri = // as calculated above
var cloudBlobContainer = new CloudBlobContainer(uri);
foreach (var blob in cloudBlobContainer.ListBlobs())
{
Console.WriteLine(blob.Uri);
}
var blockBlob = cloudBlobContainer.GetBlockBlobReference("testBlob.txt");
blockBlob.UploadText("Hello world");
If there is any problem with your Shared Access Signature, you’ll get a StorageException (403 forbidden). This will happen if the string is tampered with in any way, or if the expiry date has passed, or if you try to access a different container.
Revoking a Shared Access Signature
Obviously if this URI gets into the wrong hands, anyone can use it to read and write to your container. That’s one reason to use expiry dates that are in the near future. You can revoke a SAS by regenerating your storage account key, but this is a fairly drastic measure, since all code that talks to your storage account will need to be updated.
This is where the advantage of using named Stored Access Policies comes in. We can simply remove the stored access policy with that name using the following code:
var permissions = blobContainer.GetPermissions();
var policyName = "testpolicy";
permissions.SharedAccessPolicies.Remove(policyName);
blobContainer.SetPermissions(permissions);
Note that if you later recreate a new Stored Access Policy with the same name, the SAS URI generated with the old one will start working again. So after revoking the policy, you’d want to ensure that any new ones you created had a different name.
Comments
Mark, this might be a dumb question, but if I create a SAS on an individual blob, is it only good for that blob? Can we lock down individual blobs?
alicatein blob storage a "blob" is an individual file, and blobs reside within a "container". Normally you create a SAS for an individual blob, so only that one file can be read/written to for a specific period of time. It is possible to create tokens with wider privileges, but generally its not recommended. There's a good article here: https://docs.microsoft.com/...
Mark HeathThanks Mark, it was a dumb question after all. I wasn't sure if the token or signature took the blob URL into account, obviously it does. Because that's the case, it's hard to find written confirmation of the obvious. I was just being paranoid. Cheers. I love your Pluralsight courses.
alicateIs it possible to create
Deivydas VoroneckisSignature
in Azure Portal?Azure Storage Explorer lets you do so, and there's actually a cloud version of storage explorer that you can access in the portal so you might be able to do it from there
Mark Heath