4

I create a Managed Identity for a Function app and assigned it to DocumentDB Account Contributor by following the two sections below

https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#assign-a-system-assigned-managed-identity-to-a-function-app

https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#grant-access-to-your-azure-cosmos-account

Microsoft.Azure.Services.AppAuthentication

I got an exception when I tried to run the code from the section below:

https://learn.microsoft.com/en-us/azure/cosmos-db/managed-identity-based-authentication#programmatically-access-the-azure-cosmos-db-keys

Could not load file or assembly 'System.Text.Encodings.Web, Version=6.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. The system cannot find the file specified. at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.DeterminePropertyName() at System.Text.Json.Serialization.Metadata.JsonPropertyInfo.GetPolicies(Nullable1 ignoreCondition, Nullable1 declaringTypeNumberHandling) at ... System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() at Cosmos.Samples.AzureFunctions.AzureFunctionsCosmosClientMI.d__7.MoveNext() in C:.ME\MyLab.Code\AzureCode\CosmosDB\azure-cosmos-dotnet-v3-usage\AzureFunctions\AzureFunctionsCosmosClientMI.cs:line 85

Azure.Identity

Since AppAuthentication is not recommended by MS, then I switched to using Azure.Identity by following the links below: https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet

https://joonasaijala.com/2021/07/01/how-to-using-managed-identities-to-access-cosmos-db-data-via-rbac-and-disabling-authentication-via-keys/

and the code below

 static string cosmosUrl = "https://xxx.documents.azure.com:443/";
    private static CosmosClient client = new CosmosClient(cosmosUrl, new DefaultAzureCredential());
   var container = client.GetContainer("FamilyDatabase", "FamilyContainer");
        try
        {
            var result = await container.CreateItemAsync<Item>(data, new PartitionKey(data.LastName));
            return new OkObjectResult(result.Resource.Id);
        }
        catch (CosmosException cosmosException)
        {
            log.LogError("Creating item failed with error {0}", cosmosException.ToString());
            return new BadRequestObjectResult($"Failed to create item. Cosmos Status Code {cosmosException.StatusCode}, Sub Status Code {cosmosException.SubStatusCode}: {cosmosException.Message}.");
        }

However, I got the exception below both locally and running it in Azure.

Failed to create item. Cosmos Status Code Forbidden, Sub Status Code 5301: Response status code does not indicate success: Forbidden (403); Substatus: 5301; ActivityId: xxxx-bf03-4355-8642-5d316f9d3373; Reason: (Request blocked by Auth xxxx : Request is blocked because principal [xxx-2bff-44e9-97be-9ffeb3aae3ee] does not have required RBAC permissions to perform action [Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/]. Learn more: https://aka.ms/cosmos-native-rbac. ActivityId: xxx-bf03-4355-8642-5d316f9d3373, Microsoft.Azure.Documents.Common/2.14.0, Windows/10.0.14393 cosmos-netstandard-sdk/3.24.1);.

Locally, I logged into VS following the link https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet#authenticating-via-visual-studio

Any idea for resolving issues with Azure.Identity?

Ref:

Connect Function App to CosmosDB with Managed Identity

https://github.com/Azure/azure-sdk-for-net/tree/Azure.Identity_1.5.0/sdk/identity/Azure.Identity/samples

Pingpong
  • 7,681
  • 21
  • 83
  • 209

2 Answers2

8

I ran into this same error this morning while setting up CosmosDB to use the Managed Identity of my Azure VM. The error message states that your principal does not have the RBAC permission Microsoft.DocumentDB/databaseAccounts/readMetadata. Once you give the principal you are using that permission authentication using Azure.Identity should work.

The DocumentDB Account Contributor doesn't have the role Microsoft.DocumentDB/databaseAccounts/readMetadata, and I couldn't find a built in Azure role that contained that permission so I created my own custom CosmosDBReadWrite role by following the example in this article.

To create the custom role definitions and assignments, you will need to have the Azure CLI installed.

Configuring Custom Role Definitions

Prepare JSON Role Definition File

First you will need to create a json file with the role definition. Here are 2 different custom role configuration json files, one for read-only access to the CosmosDB and the other has read-write role access.

Json file for read-only custom role
{
    "RoleName": "CosmosDBReadOnlyRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/read",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/executeQuery",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/readChangeFeed"
        ]
    }]
}
Json file for read-write custom role
{
    "RoleName": "CosmosDBReadWriteRole",
    "Type": "CustomRole",
    "AssignableScopes": ["/"],
    "Permissions": [{
        "DataActions": [
            "Microsoft.DocumentDB/databaseAccounts/readMetadata",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*",
            "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*"
        ]
    }]
}

Create and Assign Role Definition

After you have your json file saved with your custom role definition, we can create the custom role with the Azure CLI and then assign it to the correct principal.

Create your custom role using the JSON file you created above

resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
az cosmosdb sql role definition create -a $accountName -g $resourceGroupName -b @role-definition.json

After you create the role, the definition of the created role should be returned. If not, use the following command to find the roleDefinitionId which can be found in the name property.

az cosmosdb sql role definition list --account-name $accountName -g $resourceGroupName

Finally, apply the custom role to your principal that needs permission to access CosmosDB.

resourceGroupName='<myResourceGroup>'
accountName='<myCosmosAccount>'
roleDefinitionId = '<roleDefinitionId>'
principalId = '<ID for the Object that needs access to the CosmosDB>'
az cosmosdb sql role assignment create -a $accountName -g $resourceGroupName -s "/" -p $principalId -d $roleDefinitionId

Hope this solves the error you are running into as well!

  • 1
    Thanks for this, I wonder why there is no built-in role with these permissions – ENDEESA Aug 15 '22 at 04:29
  • Actually, CosmosDB Account Contributor does inlude this role as part of the wildcard - Microsoft.DocumentDB/databaseAccounts/* – Kruti Joshi Feb 01 '23 at 10:31
  • @KrutiJoshi I can't see the wildcard in the built in role DocumentDB Account Contributor. All the permissions in the built in role has specifics under Microsoft.DocumentDB/databaseAccounts/... – Douglas Young Jul 28 '23 at 01:38
  • Update(wasn't allow to edit my previous comment) - I tried to clone the built in role and add `readMetadata` and in their I can see the wildcard. It also appears the `readMetadata` role doesn't exists... https://learn.microsoft.com/en-us/azure/role-based-access-control/resource-provider-operations When creating a custom role via the portal, there isn't a `readMetadata` permission to select – Douglas Young Jul 28 '23 at 02:21
0

Azure Cosmos DB actually has built-in roles for that.

For read only, roleDefinitionId is 00000000-0000-0000-0000-000000000001. For read and write, roleDefinitionId is 00000000-0000-0000-0000-000000000002. More details at Configure role-based access control with Azure AD - Azure Cosmos Db | Microsoft Learn

So all you need to do is give your principal the adequate permission.

az cosmosdb sql role assignment create -a <cosmosdbName> -g <resourceGroupName> -s "/" -p <principalId> -d 00000000-0000-0000-0000-000000000002
drifit
  • 1