Configure RBAC for Cosmos DB with Managed Identity instead of Service Principal
[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 roleDefinitionId
of 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.