azure-sdk-for-net icon indicating copy to clipboard operation
azure-sdk-for-net copied to clipboard

RoleAssignment creation request fails with "This request is incorrectly formatted."

Open aniruddhagore1984 opened this issue 3 years ago • 9 comments

Query/Question Context: I am doing a POC in our existing Azure App Service. We would like the app service to create a storage account (on the fly), make it Key Vault managed storage account (we have an existing Key Vault) and get SAS tokens to access it. The app service uses Managed Service Identity to authenticate with Blob Storage and Key Vault.

Problem: I am able to create a new storage account using StorageManagementClient. Adding it to KeyVault failed with 403 - I found out that Vault needs to be assigned 'Storage Account Key Operator Service Role' role for it to regenerate keys. So I started looking into programmatically creating new role right after storage account creation, but role creation fails with "This request is incorrectly formatted.".

Code: I will sincerely appreciate any help with investigating why authClient.RoleAssignments.CreateAsync fails with the aforementioned error. I copied the auto-rest generated REST client from here.

          // Create the Key Vault-managed Storage client to find the specified managed storage account.
            ManagedStorageRestClient storageClient = ManagedStorageRestClientCreater.Create(vaultUri, credential, options);

            string resId = CreateStorageAccount(storageAccountName);

            // Set-up role for KeyVault to be able to operate on Storage account

            string token = null;

            try
            {
                var msiConnectionString = $"RunAs=App;AppId={msiClientId}";
                var tokenProvider = new AzureServiceTokenProvider(msiConnectionString);
                var result = tokenProvider.GetAccessTokenAsync("https://management.core.windows.net/", tenantId);
                result.Wait();
                token = result.Result;
                Log.Info("Successfully created token = " + token);
            }
            catch (Exception ex)
            {
                Log.Error("Exception while creating token", ex);
            }

            var credentials = new TokenCredentials(token);

            try
            {
                var authClient = new AuthorizationManagementClient(credentials);

                var raParams = new RoleAssignmentCreateParameters
                {
                    // Based on an example from https://docs.microsoft.com/en-us/cli/azure/keyvault/storage?view=azure-cli-latest#az_keyvault_storage_add

                    PrincipalType = "ServicePrincipal",
                    PrincipalId = "cfa8b339-82a2-471a-a3c9-0fc0be7a4093", // Public Vault Service Principal Application ID from https://docs.microsoft.com/en-us/azure/key-vault/secrets/overview-storage-keys-powershell
                    RoleDefinitionId = "81a9662b-bebf-436f-a333-f67b29880f12" // ID for Storage Account Key Operator Service Role from https://docs.microsoft.com/en-us/azure/role-based-access-control/built-in-roles
                };

                var roleAssignmentTask = authClient.RoleAssignments.CreateAsync(resId, Guid.NewGuid().ToString(), raParams);
                roleAssignmentTask.Wait();
                var r = roleAssignmentTask.Result;

                Log.Info("Successfully assigned role");
            }
            catch (Exception ex)
            {
                Log.Error("Exception while assigning role", ex);
            }

Environment:

  • Name and version of the Library package used: Microsoft.Azure.Management.Authorization (2.0.0), Microsoft.Azure.Management.Storage (21.0.0)
  • Hosting platform or OS and .NET runtime version (dotnet --info output for .NET Core projects): .NET SDK (reflecting any global.json): Version: 5.0.203 Commit: 383637d63f

Runtime Environment: OS Name: Windows OS Version: 10.0.19042 OS Platform: Windows RID: win10-x64 Base Path: C:\Program Files\dotnet\sdk\5.0.203\

Host (useful for support): Version: 5.0.6 Commit: 478b2f8c0e

.NET SDKs installed: 3.1.402 [C:\Program Files\dotnet\sdk] 3.1.409 [C:\Program Files\dotnet\sdk] 5.0.103 [C:\Program Files\dotnet\sdk] 5.0.104 [C:\Program Files\dotnet\sdk] 5.0.203 [C:\Program Files\dotnet\sdk]

  • IDE and version : Visual Studio 16.9.5

aniruddhagore1984 avatar May 17 '21 22:05 aniruddhagore1984

Thank you for your feedback. Tagging and routing to the team member best able to assist.

jsquire avatar May 18 '21 13:05 jsquire

I have deployed my application to our test cluster and I am debugging by attaching to Visual Studio locally. I am unable to capture HTTP traffic via Fiddler. I just see regular GET subscription calls being made (by Visual Studio I suppose?), I do not see any calls to storage or key vault. I have HTTPS decrypting on in Fiddler and also have HTTPS protocols set to TLS 1.0, TLS1.1 and TLS1.2 in addition to others.

aniruddhagore1984 avatar May 18 '21 20:05 aniruddhagore1984

I would like to note that Storage and Key Vault teams recommend you use RBAC instead of SAS tokens if possible.

@allenjzhang can you look at the AuthorizationManagementClient issue here? The ManagedStorageRestClient doesn't seem to be the issue, which is a sample we published since Key Vault recommend that customers use RBAC instead and didn't want a track 2 SDK for it.

heaths avatar Jun 01 '21 20:06 heaths

Adding @markcowl

heaths avatar Jun 09 '21 21:06 heaths

Is this being looked at at all? The problem is still present 🤔

shareonline avatar Aug 05 '22 08:08 shareonline

@m-nash what track 2 management client should they be using now? Looking at the code that is failing - the lower call to create the RBAC assignment - it looks like track 1. Is general authorization just in Azure.ResourceManager?

heaths avatar Aug 05 '22 22:08 heaths

@HarveyLink please help on this issue and check if Track 2 Sdk can solve this problem

ArthurMa1978 avatar Jan 10 '23 06:01 ArthurMa1978

The role assignment collection for each resource is available directly on the resource object. To get this we first get an ArmClient, then from there get the resource we want to add the role assignment to, then get a reference to its role assignment collection and then add a new role assignment by calling CreateOrUpdate.

//pseudo code

using Azure.ResourceManager.Authorization;
using Azure.ResourceManager;
using Azure.ResourceManager.Storage;

ArmClient client = new ArmClient(new DefaultAzureCredential());
StorageAccountResource storageAccount =  client.GetStorageAccountResource(storageAccountResourceIdentifier);
RoleAssignmentCollection roleAssignments = storageAccount.GetRoleAssignments();
RoleAssignmentResource roleAssignment = roleAssignments.CreateOrUpdate(WaitUntil.Completed, "roleAssignmentName", new RoleAssignmentCreateOrUpdateContent(roleDefinitionId, principalId));

m-nash avatar Jan 10 '23 21:01 m-nash

Hi, we're sending this friendly reminder because we haven't heard back from you in 7 days. We need more information about this issue to help address it. Please be sure to give us your input. If we don't hear back from you within 14 days of this comment the issue will be automatically closed. Thank you!

ghost avatar Feb 14 '23 08:02 ghost