Configure RBAC for Cosmos DB with Managed Identity instead of Service Principal

Akihiro Nishikawa
Microsoft Azure
Published in
5 min readDec 20, 2021

[As of December 20, 2021]
The original Japanese edition is here.

Objectives

As the document below mentioned, we can access Cosmos DB with Managed Identity.

Recently, a new feature, RBAC for Cosmos DB, is added and it allows us to configure fine-grain control to data operations for Cosmos DB with Azure Active Directory accounts.

We don’t have to use any keys when using this feature to connect to Cosmos DB. Therefore, we can keep Cosmos DB more secure than ordinal style in connecting the DB.

The document mentioned above describes RBAC configuration with Service Principal, but Managed Identity also works. In this article, I elaborate how to configure RBAC for Cosmos DB with Managed Identity.

Topology and service components

In this article, I use the following configuration.

  • Function App (Read Only and Read/Write)
    - Runtime: Java 11
    - HTTP binding/trigger
  • Cosmos DB Java SDK v4
    - The SDK is used in each Function App to interact with Cosmos DB.

Preparation

Function app

As I mentioned before, each Function App uses HTTP binding (trigger, output) and contains logic to interact with Cosmos DB. After creating a scaffold, we will add Cosmos DB interaction logic.

When accessing RBAC configured Cosmos DB with SDK, we have to get TokenCredential and use this credential to initialize CosmosClient or CosmosAsyncClient. TokenCredential is an interface and there are lots of implementation classes of the interface, including ManagedIdentityCredential. So, we can also use Managed Identity to configure RBAC for Cosmos DB.

We can get a TokenCredential instance with the following code. DefaultAzureCredentialBuilder() is used in this example, but , ManagedIdentityCredentialBuilder() is also applicable.

Next, we pass the TokenCredential instance to CosmosClientBuilder() to initialize CosmosClient or CosmosAsyncClient. As you can see, we don’t have to use any keys to create a client instance. We can create CosmosClient with the following code. As CosmosClient and CosmosAsyncClient is auto-closable, we should create the client instance surrounded with try-with-resources clause.

After that, codes corresponding to GET method and POST method are added.

  • GET : retrieve data from Cosmos DB.
  • POST: update or insert data passed in HTTP request body.

To check the response code from Cosmos DB, this response code is used in the “upsert” code as a HTTP status returned by Function App.

When the implementation is completed, build Function Apps and deploy them to Azure.

Next, we create Managed Identity of each Function App. Navigate “Settings” > “Identity” in Azure Portal, and enable system assigned managed identity. As “Object (principal) ID” is used afterwards, I recommend you take a note of this ID. This operation is required in both Function Apps.

Cosmos DB

As usual, create Cosmos DB account, database, and container. In this article, database is named “Inventories”, and container is “Tracks”. Data listed below are populated in the container.

Next, two custom roles should be created for RBAC; one is “read only” role (MyReadOnlyRole), and the other is “read write” role (MyReadWriteRole). This operation is the same one in the document.

  • JSON file for read-only role configuration : role-definition-ro.json
  • JSON file for read-write role configuration : role-definition-rw.json

Create custom roles MyReadOnlyRole and MyReadWriteRole with both JSON files. The following example describes how to create custom roles with Azure CLI.

To assign Managed Identity to each role, we have to acquire roleDefinitionIdof each role with the following command.

roleDefinitionId is corresponding to the attribute “name” in output JSON document.

Finally, each roleDefinitionId is used to assign Function Apps to either MyReadOnlyRole role or MyReadWriteRole role. As you can see in the sample code below, Principal ID is object ID of each managed identity, which you would have taken notes in the previous section.

That’s it. Now let’s do test!

Test

At first, check behaviors by a Function App in MyReadOnlyRole. GET method works fine and get data stored in Cosmos DB.

However, POST method raises exception due to RBAC and returned 403. This is an expected behavior. Masked principal is equal to Principal ID of Managed Identity for read-only Function App.

We can see error messages via Log Streams in Azure Portal.

On the other hand, both GET and POST methods work fine in case of another Function App in MyReadWriteRole.

Use POST method to modify document...

And use GET method again to retrieve all data, we can see id:4321 modified.

Conclusion

We confirmed that RBAC configuration provided safe access to Cosmos DB for applications. Even if “upsert” or “delete” method is called from an application in read-only role, no data is modified and we can keep data safe and exception arises.

Demo code used in this article is available in the following GitHub repository.

--

--

Akihiro Nishikawa
Microsoft Azure

Cloud Solution Architect @ Microsoft, and JJUG (Japan Java Users Group) board member. ♥Java (JVM/GraalVM) and open-source technologies. All views are my own.