Search code examples
azureasp.net-coreazure-storageazure-blob-storageazure-managed-identity

Generate user delegation SAS token running locally


I'm creating solution based on this [documentation][1]. I have it almost working as I want to but it works only when deployed to Azure. App Service has Managed Identity configured and it is assigned Storage Blob Data Contributor role. Is there any way to make it run on my local machine? Currently I need to publish code from VS to Azure and then use Remote debugging to verify how it works. This is the problematic line:

userDelegationKey key = await blobClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow,
   DateTimeOffset.UtcNow.AddDays(7));

I get exception:

Status: 400 (The value for one of the XML nodes is not in the correct format.)
ErrorCode: InvalidXmlNodeValue

I use DefaultAzureCredentials and in debug I see it has 3 different sources. First of them is EnvironmentCredential (then ManagedIdentityCredential and SharedTokenCacheCredential). So I tried registering application in Azure AD and configured those 3 env variables but it didn't help. Maybe I need to add some specific permissions to this app?

"AZURE_CLIENT_ID": "",
"AZURE_CLIENT_SECRET": "",
"AZURE_TENANT_ID": ""

Or maybe this could somehow work with my account in Azure? If I'm also assigned Storage Blob Data Contributor role?

EDIT: I captured request and response with Fiddler

Request:

POST https://myaccount.blob.core.windows.net/?restype=service&comp=userdelegationkey HTTP/1.1
Host: myaccount.blob.core.windows.net
x-ms-version: 2019-07-07
x-ms-client-request-id: 23071825-dcf0-4803-a8a9-c44ec38695d5
x-ms-return-client-request-id: true
User-Agent: azsdk-net-Storage.Blobs/12.4.4 (.NET Core 3.1.2; Microsoft Windows 10.0.16299)
Authorization: Bearer Hidden
traceparent: 00-7e23f80250325742853c846211a83d02-6739d4cbc8ef0a46-00
Content-Type: application/xml
Content-Length: 91

<KeyInfo><Start>2020-07-08T06:02:35Z</Start><Expiry>2020-07-15T06:17:35Z</Expiry></KeyInfo>

Response:

HTTP/1.1 400 The value for one of the XML nodes is not in the correct format.
Content-Length: 348
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: ba2fe641-f01e-0065-3eef-54acae000000
x-ms-client-request-id: 23071825-dcf0-4803-a8a9-c44ec38695d5
x-ms-version: 2019-07-07
x-ms-error-code: InvalidXmlNodeValue
Date: Wed, 08 Jul 2020 06:16:14 GMT

<?xml version="1.0" encoding="utf-8"?><Error><Code>InvalidXmlNodeValue</Code><Message>The value for one of the XML nodes is not in the correct format.
RequestId:ba2fe641-f01e-0065-3eef-54acae000000
Time:2020-07-08T06:16:15.7553428Z</Message><XmlNodeName>2020-07-15T06:17:35Z</XmlNodeName><XmlNodeValue>2020-07-15T06:17:35Z</XmlNodeValue></Error>

EDIT 2: It works with help from @JimXu. In addition I was able to make it work with Azure account configured in Visual Studio so I could remove application registration that I created just for this purpose in Azure AD. [1]: https://learn.microsoft.com/en-us/azure/storage/blobs/storage-blob-user-delegation-sas-create-dotnet#example-get-a-user-delegation-sas


Solution

  • If you want to get Azure storage account User Delegation Key, you need to assign Storage Blob Data Contributor, Storage Blob Data Owner or Storage Blob Delegator to the AD application or account. For more details, please refer to the document

    Besides, please note that when we get Azure storage account User Delegation Key, we need to provide the expire time. Its value must be a valid date and time within 7 days of the current time. For more details, please refer to here.

    For example

    string accountName = "jimtestdiag417";
    
                string blobEndpoint = $"https://{accountName}.blob.core.windows.net/";
                
    
                // Create a new Blob service client with Azure AD credentials.  
                BlobServiceClient blobClient = new BlobServiceClient(new Uri(blobEndpoint),
                                                                        new DefaultAzureCredential();
    
                // Get a user delegation key for the Blob service that's valid for seven days.
                // to avoid clock skew between the requesting pc and azure servers, please set expire time in future six days
                UserDelegationKey key = await blobClient.GetUserDelegationKeyAsync(DateTimeOffset.UtcNow,
                                                                                    DateTimeOffset.UtcNow.AddDays(6));
    
                // Read the key's properties.
                Console.WriteLine("User delegation key properties:");
                Console.WriteLine("Key signed start: {0}", key.SignedStartsOn);
                Console.WriteLine("Key signed expiry: {0}", key.SignedExpiresOn);
                Console.WriteLine("Key signed object ID: {0}", key.SignedObjectId);
                Console.WriteLine("Key signed tenant ID: {0}", key.SignedTenantId);
                Console.WriteLine("Key signed service: {0}", key.SignedService);
                Console.WriteLine("Key signed version: {0}", key.SignedVersion);
                Console.WriteLine();
    

    enter image description here