问题
I have an exiting functions app that has the functionality to download a file from sftp, process the file and upload file to blob storage. This functions app is already deployed in azure and working properly. However, when I run the same thing from visual studio (local) I get error at uploading file to blob storage.
Microsoft.Azure.Storage.StorageException: This request is not authorized to perform this operation using this permission.
I made sure this app has the necessary contributor role assigned in a storage account (thats why its working from azure). Are there any other settings I need to configure in local settings or project settings for these functions to work same like when they are deployed to azure? Or could there be any settings in storage account that is overriding to perform upload operation when run from dev but run only from azure?
I made sure I use local settings have all are copied from app configuration which has storage account names, connection string of blob storage, sftp url, and key vault name which has credetails of sft site etc.,
Update: Forgot to mention that az storage container upload command from command-line from my machine uploaded file successfully.
update2: As per suggested by I have followed the tutorial and I was successfully able to create the container, upload blob and do cleanup without errors. Then I consolidated code to simulate simple download blob into memory stream which is also throwing error
This request is not authorized to perform this operation using this permission (see full log in the bottom)
Code to download blob:
static async Task TokenCredentialsSample()
{
var tenantId = "xxxxx-xxxx-xxxx-xxxx-xxxxxxxx";
var tokenProvider = new AzureServiceTokenProvider().GetAccessTokenAsync("https://storage.azure.com/",tenantId);
var tokenCredential = new TokenCredential(tokenProvider.Result);
var storageCredentials = new StorageCredentials(tokenCredential);
var uri = new Uri("https://mystorageaccount.blob.core.windows.net/mycontainer/inbound/myfile.csv");
var cloudBlockBlob = new CloudBlockBlob(uri, storageCredentials);
var memoryStream = new MemoryStream();
cloudBlockBlob.DownloadToStream(memoryStream); // Error here
memoryStream.Position = 0;
memoryStream.Close();
}
I have also made sure I typed az login from command-line to switch to select correct subscription and also the account is selected in visual studio options.
Error log:
Microsoft.Azure.Storage.StorageException
HResult=0x80131500
Message=This request is not authorized to perform this operation using this permission.
Source=Microsoft.Azure.Storage.Common
StackTrace:
at Microsoft.Azure.Storage.Core.Executor.Executor.d__11.MoveNext()
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter
1.GetResult()
at Microsoft.Azure.Storage.Core.Executor.Executor.<>c__DisplayClass0_01.<ExecuteSync>b__0()
at Microsoft.Azure.Storage.Core.Util.CommonUtility.RunWithoutSynchronizationContext[T](Func
1 actionToRun)
at Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteSync[T](RESTCommand1 cmd, IRetryPolicy policy, OperationContext operationContext)
at Microsoft.Azure.Storage.Blob.CloudBlob.DownloadRangeToStream(Stream target, Nullable
1 offset, Nullable`1 length, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
at Microsoft.Azure.Storage.Blob.CloudBlob.DownloadToStream(Stream target, AccessCondition accessCondition, BlobRequestOptions options, OperationContext operationContext)
at BlobStorage.Program.d__2.MoveNext() in c:...\source\repos\BlobStorage\Program.cs:line 111
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
at BlobStorage.Program.d__0.MoveNext() in c:...\source\repos\BlobStorage\Program.cs:line 19
This exception was originally thrown at this call stack: Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteAsync(Microsoft.Azure.Storage.Core.Executor.RESTCommand, Microsoft.Azure.Storage.RetryPolicies.IRetryPolicy, Microsoft.Azure.Storage.OperationContext, System.Threading.CancellationToken) System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw() System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(System.Threading.Tasks.Task) System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(System.Threading.Tasks.Task) System.Runtime.CompilerServices.TaskAwaiter.GetResult() Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteSync.AnonymousMethod__0() Microsoft.Azure.Storage.Core.Util.CommonUtility.RunWithoutSynchronizationContext(System.Func) Microsoft.Azure.Storage.Core.Executor.Executor.ExecuteSync(Microsoft.Azure.Storage.Core.Executor.RESTCommand, Microsoft.Azure.Storage.RetryPolicies.IRetryPolicy, Microsoft.Azure.Storage.OperationContext) Microsoft.Azure.Storage.Blob.CloudBlob.DownloadRangeToStream(System.IO.Stream, long?, long?, Microsoft.Azure.Storage.AccessCondition, Microsoft.Azure.Storage.Blob.BlobRequestOptions, Microsoft.Azure.Storage.OperationContext) Microsoft.Azure.Storage.Blob.CloudBlob.DownloadToStream(System.IO.Stream, Microsoft.Azure.Storage.AccessCondition, Microsoft.Azure.Storage.Blob.BlobRequestOptions, Microsoft.Azure.Storage.OperationContext) ... [Call Stack Truncated]
回答1:
1)
I see your returning a Task
from your method, yet not await
ing anything.
Its a good practice to add the 'async` keyword to the method signature and change the following code:
var tokenProvider = new AzureServiceTokenProvider().GetAccessTokenAsync("https://storage.azure.com/",tenantId);
to something like:
var tokenProvider = new AzureServiceTokenProvider();
var token = await tokenProvider.GetAccessTokenAsync("https://storage.azure.com/",tenantId);
var tokenCredential = new TokenCredential(token );
Now, get your access token your can use a tool like http://jwt.io and crack it open and inspect the claims.
2) Trying changing the access token from:
GetAccessTokenAsync("https://storage.azure.com/",tenantId);
to:
GetAccessTokenAsync("https://[youraccount].blob.core.windows.net",tenantId);
3)
The AzureServiceTokenProvider
will look for credentials in a set of predefined places.
The AzureServiceTokenProvider documentation is worth reading through, to help trouble shoot.
Have you tried using the first option of passing RunAs=Developer; DeveloperTool=AzureCli
as the connection string, so it explicitly knows where to look?
So, from the same command window where you executed the azure cli and did something like azure login
, have you tried to run the console program from there?
Which subscription are you logged into? az account list
Do you have many subscriptions?
Your default subscription may not be the one where you are trying to access the blob from.
回答2:
OK. I found the solution.
I found this article which clearly stated in the note that Data Reader or Data Contributor role is a must! None of the MS documents such as this did not highlight the importance of additional role (Data Reader/Data Contributor) like the article did.
Note that it is not enough that your user is an Owner/Contributor on the subscription/resource group/Storage account. The user must be assigned to a Data Reader or Data Contributor role to get access to the data using Azure AD authentication.
We assumed contributor was enough but it is not.
回答3:
In addition, the Data Reader/Contributor role must be on the storage account resource itself... it won't work at the Subscription resource level.
This feels like a bug honestly. A user/service principle with Owner or Contributor role at the Subscription level should be allowed to upload via the cli without the supplementary role. If I can do it from the UI, I should be able to do it via the cli too.
来源:https://stackoverflow.com/questions/59784133/unable-to-upload-download-blob-storage-to-container-from-local-environment