Wednesday, 16 July 2025

Add Cosmos DB Built-in Roles to Resource Identities via Terraform to Allow Role Based Access to Data in Cosmos DB

 Azure Cosmos DB can be used with DefaultAzureCrentials in C#. However, for enabling usage of DefaultAzureCrentials  with Azure Cosmos DB requires special data roles to be added to the  Cosmos DB account. There are two built in roles data reader and data contributor. Unlike other RBAC roles in Azure these roles cannot be assigned via Azure portal and they must be added programatically. They have to added via Azure CLI, Bicep, Powershell, REST API or Terraform.

The purpose is to have the data contributor (if you only need read access to data add data reader) as shown below. The added roles can pnly viewd programatically and not visiblle in Azure portal as of the time of writing of this blob post. Below command in Azure CLI can be used to get the built in role assignements of the Cosmos DB account. Below you can see three identites are assigned with data contributor role (the identities used below are of the dev user group, ops user group and the AKS workload identity user assignd identity)

 az cosmosdb sql role assignment list -a <cosmosdbaccountname> -g <resourcegroupname>



Let's look at how to setup the role via terraform. 

We can setup Cosmos account as shown below.

resource "azurerm_cosmosdb_account" "cosmos_acc" {
  name                              = "${local.instance_name}-cdb"
  location                          = local.comosdb_location
  resource_group_name               = azurerm_resource_group.rg.name
  offer_type                        = "Standard"
  kind                              = "GlobalDocumentDB"
  automatic_failover_enabled        = false
  public_network_access_enabled     = true
  ip_range_filter                   = split(",", local.comosdb_allowed_ips)
  is_virtual_network_filter_enabled = true
  default_identity_type             = "FirstPartyIdentity"

  free_tier_enabled = local.cosmosdb_enable_free_tier

  virtual_network_rule {
    id = azurerm_subnet.aks.id
  }

  backup {
    type = "Continuous"
    tier = "Continuous7Days"
  }

  consistency_policy {
    consistency_level       = "Session"
    max_interval_in_seconds = 5
    max_staleness_prefix    = 100
  }

  lifecycle {
    prevent_destroy = true
  }

  tags = merge(tomap({
    Service = "cosmosdb account"
  }), local.tags)
}

Then we can read the groups and create a user assigned identity for AKS as shown below.

data "azuread_group" "demo_ops" {
  display_name     = "demo_ops"
  security_enabled = true
}

data "azuread_group" "demo_devs" {
  display_name     = "demo_devs"
  security_enabled = true
}

resource "azurerm_user_assigned_identity" "aks_uai" {
  name                = "${local.instance_name}-aks-uai"
  location            = azurerm_resource_group.rg.location
  resource_group_name = azurerm_resource_group.rg.name
}

Next we need tor read the "Cosmos DB Built-in Data Contributor" with its id. This cannot be reffered with the name.

# Built-in role definition for "Cosmos DB Built-in Data Contributor"
data "azurerm_cosmosdb_sql_role_definition" "cosmos_db_data_contributor" {
  resource_group_name = azurerm_cosmosdb_account.cosmos_acc.resource_group_name
  account_name        = azurerm_cosmosdb_account.cosmos_acc.name
  role_definition_id  = "00000000-0000-0000-0000-000000000002"
}

Then we can assigne the role to the required users, identities or groups as shown below.

# AKS user assigned identity as a data contributor
resource "azurerm_cosmosdb_sql_role_assignment" "cosmos_data_contributor_aks_uai" {
  resource_group_name = azurerm_cosmosdb_account.cosmos_acc.resource_group_name
  account_name        = azurerm_cosmosdb_account.cosmos_acc.name
  scope               = azurerm_cosmosdb_account.cosmos_acc.id
  role_definition_id  = data.azurerm_cosmosdb_sql_role_definition.cosmos_db_data_contributor.id
  principal_id        = azurerm_user_assigned_identity.aks_uai.principal_id
}

# Ops as a data contributor
resource "azurerm_cosmosdb_sql_role_assignment" "cosmos_data_contributor_ops" {
  resource_group_name = azurerm_cosmosdb_account.cosmos_acc.resource_group_name
  account_name        = azurerm_cosmosdb_account.cosmos_acc.name
  scope               = azurerm_cosmosdb_account.cosmos_acc.id
  role_definition_id  = data.azurerm_cosmosdb_sql_role_definition.cosmos_db_data_contributor.id
  principal_id        = data.azuread_group.demo_ops.object_id
}

# Devs as a data contributor
resource "azurerm_cosmosdb_sql_role_assignment" "cosmos_data_contributor_devs" {
  count = var.environment == local.dev_environment || var.environment == local.qa_environment ? 1 : 0

  resource_group_name = azurerm_cosmosdb_account.cosmos_acc.resource_group_name
  account_name        = azurerm_cosmosdb_account.cosmos_acc.name
  scope               = azurerm_cosmosdb_account.cosmos_acc.id
  role_definition_id  = data.azurerm_cosmosdb_sql_role_definition.cosmos_db_data_contributor.id
  principal_id        = data.azuread_group.demo_devs.object_id
}

Let's look at how to use the "Cosmos DB Built-in Data Contributor" to access Cosmos DB data with C# and use DefaultAzureCredentials in the next post.

No comments:

Popular Posts