Cosmos DB for NoSQL access and design — data-plane RBAC, keys off, network, TLS, partition keys, serverless, with Bicep

Setting up Azure Cosmos DB for NoSQL so apps reach it without keys — the Cosmos-native data-plane roles (Built-in Data Reader and Contributor), their scopes and why Azure RBAC roles don't grant data access, disableLocalAuth, network and TLS settings, choosing a partition key (immutable; 20 GB per logical partition; hierarchical keys), serverless limits, and Bicep for an account, container and role assignment.

markdownreferencev1B2NQ-W3P3stage: designtrust: officialservice: cosmos-dbinterface: iacinterface: cliinterface: sdkCosmos DB data plane RBACCosmos DB Built-in Data ContributorCosmos DB Built-in Data Reader00000000-0000-0000-0000-00000000000200000000-0000-0000-0000-000000000001sqlRoleAssignmentssqlRoleDefinitionsaz cosmosdb sql role assignment createrole assignment scope /dbs /collsCosmos DB OperatorDocumentDB Account Contributor no data accessdisableLocalAuthdisableKeyBasedMetadataWriteAccessreadMetadataexecuteQuery readChangeFeedCosmos DB publicNetworkAccessminimalTlsVersion Tls12TLS 1.0 1.1 retired Cosmos August 31 2025partition key chooselogical partition 20 GBphysical partition 10000 RU/s 50 GBhierarchical partition keyschange partition key container copyserverless EnableServerlessserverless single region 5000 RU/sMicrosoft.DocumentDB/databaseAccounts@2026-03-15privatelink.documents.azure.com

Created 21 Oct 2026 · Modified 23 Oct 2026 · 1 version

Cosmos DB for NoSQL: access and design

Two permission systems

Control plane (Azure RBAC on the account: Owner, Contributor, DocumentDB Account Contributor, Cosmos DB Operator) manages accounts, databases, containers and throughput. Data plane (Cosmos-native roles, assigned through sqlRoleAssignments) reads and writes items. Neither implies the other: an Owner without a data role gets 403 on items, and a data role can't create containers through the SDK (reference/cosmos-db/errors.md, substatus 5300).

Built-in data roleIDAllows
Cosmos DB Built-in Data Reader00000000-0000-0000-0000-000000000001readMetadata, item read, executeQuery, readChangeFeed
Cosmos DB Built-in Data Contributor00000000-0000-0000-0000-000000000002readMetadata, containers/*, containers/items/*
  • Scope: / (whole account), /dbs/<db>, /dbs/<db>/colls/<container>, or the same under the account's resource ID. Queries through the SDKs need both executeQuery and readChangeFeed. Custom roles can't use notDataActions.
  • Assign with az cosmosdb sql role assignment create -g <rg> --account-name <acct> --role-definition-id 00000000-0000-0000-0000-000000000002 --principal-id <object id> --scope "/", or Bicep below. Not with az role assignment create: these aren't Azure RBAC roles (a Microsoft Q&A answer suggests otherwise; it's wrong). The portal can't manage data-plane assignments.
  • disableLocalAuth: true turns off keys and resource tokens, so only Entra works. disableKeyBasedMetadataWriteAccess only blocks metadata writes with keys.
  • SDK token scope: <account endpoint>/.default; @azure/cosmos falls back to https://cosmos.azure.com/.default if Entra answers AADSTS500011.

Network and TLS

  • publicNetworkAccess: Enabled, Disabled or SecuredByPerimeter; IP and VNet rules otherwise; private endpoint groupId Sql, zone privatelink.documents.azure.com. Firewall changes take up to 15 minutes.
  • TLS 1.0 and 1.1 ended on August 31, 2025; new accounts default to Tls12. The REST spec still says the default is TLS 1.0: set minimalTlsVersion: 'Tls12' explicitly.

Partition keys (choose once)

  • A container's partition key can't be changed in place: moving means a new container (container copy jobs) or, for NoSQL, global secondary indexes.
  • One logical partition (one key value) holds at most 20 GB; a physical partition serves up to 10,000 RU/s and 50 GB. Exceeding the logical limit gives 403 substatus 1014.
  • Pick a property with high cardinality that most queries filter on with equality; for point-read/write workloads /id works well. Hierarchical keys (/tenantId, /userId, /id) spread large tenants; Microsoft's pages disagree on the maximum depth (three or four levels), and a unique last level rules out transactional batch and stored procedures.
  • Item size limit: 2 MB (413 above it).

Serverless or provisioned

Serverless (capabilities: [{ name: 'EnableServerless' }]): single region only, no throughput settings (passing throughput is an error), no shared-throughput databases, each physical partition up to 5,000 RU/s. Choose provisioned (manual or autoscale) for multi-region or steady load.

Bicep

// Cosmos DB for NoSQL: keys off, a database and container, and a data-plane role for an app identity
param location string = resourceGroup().location
param accountName string
param appPrincipalId string // the app's managed identity (principal ID)

resource account 'Microsoft.DocumentDB/databaseAccounts@2026-03-15' = {
  name: accountName
  location: location
  kind: 'GlobalDocumentDB'
  properties: {
    databaseAccountOfferType: 'Standard'
    disableLocalAuth: true // keys and resource tokens stop working; Entra only
    publicNetworkAccess: 'Disabled' // reach it through a private endpoint (groupId 'Sql')
    minimalTlsVersion: 'Tls12'
    consistencyPolicy: {
      defaultConsistencyLevel: 'Session'
    }
    locations: [
      {
        locationName: location
        failoverPriority: 0
        isZoneRedundant: false
      }
    ]
    capabilities: [
      {
        name: 'EnableServerless'
      }
    ]
  }
}

resource db 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases@2026-03-15' = {
  parent: account
  name: 'shop'
  properties: {
    resource: {
      id: 'shop'
    }
  }
}

resource orders 'Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers@2026-03-15' = {
  parent: db
  name: 'orders'
  properties: {
    resource: {
      id: 'orders'
      partitionKey: {
        paths: ['/customerId'] // can't be changed later
        kind: 'Hash'
        version: 2
      }
    }
  }
}

// Cosmos DB Built-in Data Contributor (a Cosmos data-plane role, not an Azure RBAC role)
resource dataContributor 'Microsoft.DocumentDB/databaseAccounts/sqlRoleDefinitions@2026-03-15' existing = {
  parent: account
  name: '00000000-0000-0000-0000-000000000002'
}

resource appData 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2026-03-15' = {
  parent: account
  name: guid(account.id, appPrincipalId, dataContributor.id)
  properties: {
    roleDefinitionId: dataContributor.id
    principalId: appPrincipalId
    scope: '${account.id}/dbs/shop'
  }
}

The app identity needs no Azure role on the account to read and write items: the sqlRoleAssignments entry is the permission. Code: reference/cosmos-db/errors.md. MongoDB, Table, Cassandra and Gremlin, and Azure DocumentDB: reference/cosmos-db/other-apis-and-documentdb.md.

Read this document as markdown — the same bytes an agent receives.