Assigning Cosmos Data Plane Roles via RBAC w/ Bicep
Introduction
If one wasn’t already aware, CosmosDB has the ability to assign built in RBAC roles scoped to the account, database, and the container. When trying to achieve this via Bicep I quickly discovered there really wasn’t much content on this topic. In fact the majority of the content on this topic revolved around leveraging the creation of customer Cosmos role definitions. Hopefully this article will help provide some clarity. For this post I designed this as a module in a bicep registry. Full code can be found on my bicep_registry repository.
Background
If you weren’t aware CosmosDB currently provides two built in RBAC roles. Cosmos DB Built-in Data Reader
and Cosmos DB Built-in Data Contributor
. Just as described one is read only and one is for data operations.
These roles are beneficial as we don’t have to create a custom definition and then worry about maintaining it. Using a built in role is typically the preferred approach as they are viewed as more secure and can configured in any Azure subscription.
These data plane RBAC roles differ significantly in terms of resource configuration than from normal Azure build-in roles. The main reason being, the traditional RBAC roles, are stored behind the Microsoft.Authorization
resource provider. For example here is the resource ID for the built in contributor role: /providers/Microsoft.Authorization/roleDefinitions/b24988ac-6180-42a0-ab88-20f7382dd24c
Cosmos RBAC roles use a different provider for the role definition id. These role definitions are a sub resource of the actual database account. Thus they are formated as: /subscriptions/<mySubscriptionId>/resourceGroups/<myResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<myCosmosAccount>/sqlRoleDefinitions/<roleDefinitionId>
This means to retrieve or use the built in RBAC roles for Cosmos we will need to know the subscriptionid, resource group name, account name, and the role definition id.
Role Assignment
Since the built in RBAC roles for Cosmos are technically a sub resource of the cosmos account this means we will need to ensure that the assignment is either nested in the cosmos account creation or has the account listed as the resource parent.
I prefer the parent approach as this will provide us the ability to leverage the RBAC assignment as a module and thus can call it infinite amount of times.
The other tricky part was finding the above roleDefinitionId. The 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments
requires the resource id of the build in role definition id. This wasn’t straight forward in the documentation I have since updated it.
Here is my entire Cosmos SQL Role Assignment Module:
@description('CosmosDB Account to apply the role assignment to')
param databaseAccountName string
@description('Resource group of the CosmosDB Account')
param databaseAccountResourceGroup string
@description('Role definition id to assign to the principal')
@allowed([
'00000000-0000-0000-0000-000000000001'// Built-in role 'Azure Cosmos DB Built-in Data Reader'
'00000000-0000-0000-0000-000000000002' // Built-in role 'Azure Cosmos DB Built-in Data Contributor'
])
param roleDefinitionId string = '00000000-0000-0000-0000-000000000002'
@description('Principal id to assign the role to')
param principalId string
var roleAssignmentId = guid(roleDefinitionId, principalId, databaseAccount.id)
resource databaseAccount 'Microsoft.DocumentDB/databaseAccounts@2023-04-15' existing = {
name: databaseAccountName
}
resource sqlRoleAssignment 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-04-15' = {
name: roleAssignmentId
parent: databaseAccount
properties:{
principalId: principalId
roleDefinitionId: '/${subscription().id}/resourceGroups/${databaseAccountResourceGroup}/providers/Microsoft.DocumentDB/databaseAccounts/${databaseAccount.name}/sqlRoleDefinitions/${roleDefinitionId}'
scope: databaseAccount.id
}
}
The complete module can be found here.
I did discover/realized during this process that at this time only User Assigned Identities can be provisioned the RBAC role. When I attempted this with a System Managed Identity access was not granted.
Conclusion
Cosmos RBAC data plane access has traditionally be configured either via PowerShell role assignment or applications leverage the full Cosmos connection strings. This article hopefully walked through and provided you with a way to leverage Bicep to keep these RBAC role assignments in your infrastructure as code. If you are interested more Cosmos feel free to check out my post on the DP – 420 Cosmos Specialty exam.
Hi John, very useful post. Thanks!
But it seems this role assignment is not idempotent as other Azure RBAC role assignment, have you encountered the same issue?
resource sqlRoleAssignment ‘Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-04-15’ = {
name: guid(cosmosDataPlaneContributorRoleID, principalId, cosmosAccount.id)
parent: cosmosAccount
properties: {
principalId: principalId
roleDefinitionId: ‘/${subscription().id}/resourceGroups/${resourceGroup().name}/providers/Microsoft.DocumentDB/databaseAccounts/${cosmosAccount.name}/sqlRoleDefinitions/${cosmosDataPlaneContributorRoleID}’
scope: cosmosAccount.id
}
}
Hey Howard,
Appreciate the feedback! No I have not run into any idempotency issues as of yet and have run my deployment multiple times with no change to the assignment. When originally developing this I do remember that this was an issue in addition to configuring the scope of the assignment. Though I am foggy on remembering what ended up being the fix. If you have more details happy to look further into it.
Thanks John, this article helped me solve my problem.
The roledefinition still gave me a warning, which failed my pipeline so i added an existing resource to refer as the roledefinitionid.
resource sqlRoledefinition ‘Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2023-04-15’ existing = {
parent: account
name: ‘00000000-0000-0000-0000-000000000002’
}
resource sqlRoleAssignment ‘Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2023-04-15’ = {
name: guid(‘00000000-0000-0000-0000-000000000002’, functionAppIdentity, account.id)
parent: account
properties:{
principalId: functionAppIdentity
roleDefinitionId: sqlRoledefinition.id
scope: account.id
}
}
Glad to hear it helped! Do you mind sharing what the warning was?
Hey John , thanks a lot for the insightful post.
I’ve got a quick question though. After assigning roles to Managed Identities, is there a method to check their assignments in the Azure Portal? Although I managed to execute and deploy the arm template without issues, I’m not seeing the roles linked to the Managed Identities.
Or I don’t even see those roles showing up in my subscription.
Unfortunately there is nothing that I am aware of to do this…..since Azure RBAC is being done on the Management Plane and the CosmosDB roles are being performed at the data plane. Asked another way could you see SQL Role Assignments in the portal? Unfortunately the answer to this is no as far as I am aware.