I discovered many interesting Azure features while studying for the AZ-204 certification. One of these features is User Delegation SAS tokens, a way to provide access to Azure Blob Storage. In this blog post, I’ll share what I learned about these tokens and how to use them in C#/.NtET.
Accessing Azure Storage Accounts
Azure offers various methods to secure, manage, and grant access to storage accounts, from anonymous access to more advanced approaches like Azure Role-Based Access Control (RBAC). Each method has its use case, security level, and limitations.
SAS (Shared Access Signature tokens)
With Shared Access Signatures (SAS), you can securely delegate access to resources within your Azure Storage accounts. They allow you to specify which resources can be accessed, what actions can be taken, and how long the permissions should be valid.
For example, if you have a blob in storage named Myblob.txt and want to grant access to users outside of Azure, you can use SAS tokens.
To do this, you select the blob and specify the desired access level and expiration date, as shown in the image below:
As a result, Azure will generate an SAS token that might look something like this:
sp=r&st=2024-08-21T17:17:21Z&se=2024-08-22T01:17:21Z&spr=https&sv=2022-11-02&sr=b&sig=T7mWwTfZnvtU%2FuoR1vDAjKX1B7OLl0b6YcHgiJ0SFBw%3D
This token is signed using one of the two access keys associated with the storage account.
Then, you can append this token to the blob resource URL, like this:
https://clouddebuggerstorage.blob.core.windows.net/Data/Myblob.txt?sp=r&st=2024-08-21T17:17:21Z&se=2024-08-22T01:17:21Z&spr=https&sv=2022-11-02&sr=b&sig=T7mWwTfZnvtU%2FuoR1vDAjKX1B7OLl0b6YcHgiJ0SFBw%3D
Anyone with this URL can now read the blob from anywhere in the world until the token expires.
Awesome!
The issue with using access keys
Azure provides two access keys for each storage account, often named key1 and key2. These keys provide full access to all services enabled in the storage account, including Blob Storage, File Storage, Queue Storage, and Table Storage. The reason for having two keys is to facilitate key rotation.
These two highly sensitive keys should never be used outside your storage account because they provide full admin access to the entire storage account. You will find these two keys in the Azure Portal under the Access keys blade:
You can create an SAS token by signing the desired access request with one of these keys.
With this concept, you can issue any number of SAS keys with different access levels using the same access key:
What is the problem with SAS tokens?
Although SAS tokens provide essential access controls for Azure storage, they come with certain challenges:
- Because SAS tokens are signed with the storage account’s access keys, all issued SAS tokens are jeopardized if these keys are exposed or compromised.
- Furthermore, managing SAS tokens can become complex in dynamic environments, especially when customizing access for a growing number of users and applications.
- If someone loses or leaks a SAS token, anyone who obtains it can access the storage resources it governs until the token expires or you manually revoke it.
These limitations underscore the need for a more flexible solution, such as User Delegation SAS tokens, which integrate with Azure Active Directory for enhanced security and manageability.
User Delegation SAS tokens
What is the main difference compared to the SAS tokens described above?
The key advantage of User Delegation SAS tokens is that they allow applications to issue their own SAS tokens, offering more granular and secure access controls. This enables applications to define permissions tailored to each user or scenario without relying on the storage account’s access keys.
How does the application obtain the user delegation key?
To start, the application uses its managed identity to authenticate with Entra ID and acquire an access token. Once authenticated, the BlobServiceClient utilizes this access token to request a user delegation key from Entra ID.
var blobStorageUri = $"https://{model.StorageAccountName}.blob.core.windows.net";
// Step #1, get an authentication token from Entra ID
var credentials = new DefaultAzureCredential();
// Step #2, Create a BlobServiceClient with these credentials
var client = new BlobServiceClient(new Uri(blobStorageUri), credentials);
// Step #3, get a user delegation key from Entra ID
var startsOn = DateTimeOffset.UtcNow.AddMinutes(-1); // To avoid clock skew issues
var expiresOn = startsOn.AddDays(1); // Max is 7 days
var userDelegationKey = client.GetUserDelegationKey(startsOn, expiresOn);
The image below illustrates how the application acquires the user delegation key:
What is the purpose of the user delegation key?
our application can generate and sign new SAS tokens with the User Delegation Key, without relying on the storage account access keys. This provides an additional layer of security by granting granular permissions. The key is tied to the application and the Azure Active Directory (AAD) identity requesting it. Each time you request a User Delegation Key, a new key is issued, ensuring that permissions are limited to the specific context of the request.
What is inside the delegation key?
The GetUserDelegationKey method provides a UserDelegationType object and the following table shows an example of what is inside this object:
Creating A User Delegation SAS token
With the user delegation key in place, the application can create a new user delegation SAS token using the following code:
// Step #4, Define the permissions for the SAS token
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
BlobContainerName = containerName,
BlobName = blobName,
Resource = "b",
StartsOn = DateTimeOffset.UtcNow,
ExpiresOn = DateTimeOffset.UtcNow.AddHours(1)
};
// Step #5, Specify the necessary permissions
sasBuilder.SetPermissions(BlobSasPermissions.Read);
//// Alternatively, you can combine multiple permissions
//sasBuilder.SetPermissions(BlobContainerSasPermissions.Read |
// BlobContainerSasPermissions.Write |
// BlobContainerSasPermissions.List |
// BlobContainerSasPermissions.Delete);
// Step #6, Build the SAS token
Var SASToken = sasBuilder.ToSasQueryParameters(userDelegationKey,
storageAccountName).ToString();
The SAS token that you generate might look like this:
skoid=1dc7a951-446c-4572-8275-30561ef281f7&sktid=567d82a1-7f61-4da2-b955-d3244ea6e976&skt=2024-08-22T08%3A01%3A16Z&ske=2024-08-23T08%3A01%3A16Z&sks=b&skv=2024-08-04&sv=2024-08-04&st=2024-08-22T08%3A02%3A16Z&se=2024-08-22T09%3A02%3A16Z&sr=b&sp=r&sig=zajbqclywkZvs56T0RIMqcgWa24FHXpFdogV%2F9KMDIQ%3D
If we reformat it, we see the following details
skoid=1dc7a951-446c-4572-8275-30561ef281f7
&sktid=567d82a1-7f61-4da2-b955-d3244ea6e976
&skt=2024-08-22T08%3A01%3A16Z
&ske=2024-08-23T08%3A01%3A16Z
&sks=b
&skv=2024-08-04
&sv=2024-08-04
&st=2024-08-22T08%3A02%3A16Z
&se=2024-08-22T09%3A02%3A16Z
&sr=b
&sp=r
&sig=zajbqclywkZvs56T0RIMqcgWa24FHXpFdogV%2F9KMDIQ%3D
The details for what each parameter represents can be found here.
Using the user-delegated SAS token
With the token in place, you can now, for example, append it to blog storage URLs like this:
https://[MyStorage].blob.core.windows.net/clouddebugger/MyBlob.txt?[SASToken]
The alternative is to pass it as credentials to the BlobServiceClient, like this:
var client = new BlobServiceClient(SASToken);
User Delegation SAS Token permissions
For an application to be able to issue a User Delegation SAS token, it must be granted specific permissions:
- To get the delegation key, the application needs one of the following roles assigned against the target storage account:
- Contributor
- Storage Account Contributor
- Storage Blob Data Contributor
- Storage Blob Data Owner
- Storage Blob Data Reader
- Storage Blob Delegator
These roles should be scoped to the storage account, resource group, or subscription level. For more detailed information, visit the official documentation here.
- Additionally, the application must possess RBAC permissions to interact with specific resources within the storage account, such as containers or blobs.
What are the Benefits of Using User Delegation SAS Tokens?
- Key Management
The key used to sign the SAS tokens is obtained from Entra ID using the application’s managed identity, eliminating the need to manage the signing key manually. - Limited Lifetime:
You can configure the tokens to be short-lived, which reduces the window of opportunity for unauthorized access. - Enhanced Auditing:
User Delegation SAS tokens appear in Azure Storage access logs, improving the traceability of access and recorded actions. - Principle of Least Privilege:
Applications issuing these tokens can operate with lower privileges, adhering to the principle of least privilege, which reduces their risk profile. - Access Limitation:
A SAS token cannot grant more access to the storage account than the permissions allocated to the application that issued it, ensuring that privileges are appropriately contained. - Security Against Key Leakage:
By not depending on account keys, User Delegation SAS tokens significantly reduce the risk associated with key leakage. Exposure of account keys can jeopardize the security of the entire storage account; this risk is mitigated with User Delegation SAS tokens.
Summary
When I first encountered the User Delegation SAS tokens concept, I found the technical documentation overwhelming and lacking in clear use-case descriptions. The initial confusion led to some experimentation and, admittedly, a struggle. However, as I delved deeper and started to apply what I learned practically, the pieces began to fall into place.
Writing this blog post has deepened my understanding of the purpose and applications of User Delegation SAS tokens. I’ve come to appreciate their significance and utility. It’s important to note that User Delegation SAS tokens are limited to Azure Blob Storage.
How Can I Explore Delegation Tokens?
The Cloud Debugger, an exploration tool for Azure cloud developers, includes a feature that allows you to experiment with delegation tokens. The image below shows an example of what it might look like when using this tool:
Feedback, comments, found any bugs?
Let me know if you have any feedback, If I missed anything or any bugs/typos. You can find my contact details here.
About the author
Hi, I’m Tore! I have been fascinated by computers since I unpacked my first Commodore VIC-20. Today, I enjoy providing freelance development and developer training services, focusing on ASP.NET Core, IdentityServer, OpenID Connect, Architecture, and Web Security. You can connect with me on LinkedIn and Twitter, and you can find out more about me and my services here, as well as my courses for developers, including my course, Introduction to IdentityServer and OpenID-Connect.
Resources
- Create a user delegation SAS for a blob with .NET
- Create a user delegation SAS
- Delegate access by using a shared access signature
- Secure your Azure Storage account
- Grant limited access to Azure Storage resources using shared access signatures (SAS)
- Announcing user delegation SAS tokens preview for Azure Storage Blobs
Tore’s Newsletter
Be the First to Know! Get notified about my latest blog posts, upcoming presentations, webinars, and more — subscribe today!