Connect Azure CosmosDB using Managed Identities from Azure Function App both locally and on Azure
Asked Answered
C

3

8

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

Creeper answered 10/2, 2022 at 17:46 Comment(0)
P
13

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!

Procrastinate answered 10/2, 2022 at 20:31 Comment(5)
Thanks for this, I wonder why there is no built-in role with these permissionsTrichloromethane
Actually, CosmosDB Account Contributor does inlude this role as part of the wildcard - Microsoft.DocumentDB/databaseAccounts/*Gabble
@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/...Nieman
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... learn.microsoft.com/en-us/azure/role-based-access-control/… When creating a custom role via the portal, there isn't a readMetadata permission to selectNieman
+1 This answer is excellent. We followed the instructions and it solved our Cosmos DB access issues first time.Planetarium
K
6

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
Keitel answered 31/8, 2023 at 18:47 Comment(0)
B
2

In case you are facing the issue below when authenticating using Default Azure Credentials:

Request is blocked because principal does not have required RBAC permissions to perform action [Microsoft.DocumentDB/databaseAccounts/readMetadata] on resource [/]. Learn more: https://aka.ms/cosmos-native-rbac. This could be because the user's group memberships were not present in the AAD token."

There is an action missing in any of the roles currently provided in the Azure Portal. You need to run the command below. It will assign a readMetadata role, enabling you to authenticate successfully:

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

This works for Cosmos DocumentDB as well as for SQL DB.

Borgia answered 24/6, 2024 at 10:29 Comment(2)
PrincipalId in an e-mail format does not work. It wants an Object ID GUID.Mills
For some reason, needed the 00002 just to read metadata. learn.microsoft.com/en-us/azure/cosmos-db/…Mills

© 2022 - 2025 — McMap. All rights reserved.