Shimon Shrem
Shimon Shrem

Reputation: 125

Getting Error while Creating SAS Token for Azure Storage Blob with MSI

I'm trying to create a SAS token for a storage blob. I use a StorageCredentials which was created with MSI (Managed Service Identity) to create the CloudBlobClient. When creating the SAS I'm getting "Cannot create Shared Access Signature unless Account Key credentials are used". Is there support to SAS with MSI?

var container = blobClient.GetContainerReference(containerName);
var blockBlob = container.GetBlockBlobReference(snapname);
var sas = string.Concat(blockBlob.Uri.ToString(), blockBlob.GetSharedAccessSignature(sasConstraints));

This is how I create the StorageCredentials:

tokenCallback = CreateMsiCallback();
var initToken = await tokenCallback(audience);
return new StorageCredentials(
  new TokenCredential(initToken, async (state, token) =>
  {
    var accessToken = await _tokenCallback(audience);

    return new NewTokenAndFrequency(accessToken, TimeSpan.FromMinutes(1));
  }, null, TimeSpan.FromMinutes(1))
);

To create the token callback I use HttpClient

public Func<string, Task<string>> CreateMsiCallback()
{
  var handler = new HttpClientHandler
  {
     ServerCertificateCustomValidationCallback =
         (httpRequestMessage, cert, certChain, policyErrors) =>
         {
             if (policyErrors == SslPolicyErrors.None)
             {
                 return true;
             }

             return 0 == string.Compare(cert.GetCertHashString(), FabricThumbprint, StringComparison.OrdinalIgnoreCase);
        }
  };

     var client = new HttpClient(handler)
     {
         DefaultRequestHeaders =
         {
            {"secret", FabricAuthenticationCode }
         }
     };

     return async (resource) =>
     {
            var requestUri = $"{FabricMsiEndpoint}?api-version={FabricApiVersion}&resource={HttpUtility.UrlEncode(resource)}";
            var requestMessage = new HttpRequestMessage(HttpMethod.Get, requestUri);
            var response = await client.SendAsync(requestMessage);
            response.EnsureSuccessStatusCode();
            var tokenResponseString = await response.Content.ReadAsStringAsync();
            var tokenResponseObject =
                JsonConvert.DeserializeObject<ManagedIdentityTokenResponse>(tokenResponseString);
            
            return tokenResponseObject.AccessToken;
        };
    }
}

Upvotes: 0

Views: 2008

Answers (1)

Gaurav Mantri
Gaurav Mantri

Reputation: 136346

Based on this Github issue, you will need to assign Storage data roles to your MSI in order to generate SAS token. From this thread:

The error is because your oauth account don't have permission to generateUserDelegationKey. To get SAS with Oauth storage context (New-AzStorageContext -UseConnectedAuth), we need first generate UserDelegationKey from server , then use the key to generate the SAS token.

Please check have you assigned correct roles to the Oauth login user (with Connect-AzAccount). like at least one of the following 4 roles on the specific storage account:

  • Storage Blob Data Owner
  • Storage Blob Data Contributor
  • Storage Blob Data Reader
  • Storage Blob Delegator

Upvotes: 1

Related Questions