What it is
An Azure Cosmos DB account with key-based (local) authentication still enabled — the default on every account. The primary and secondary master keys are long-lived static secrets that grant complete data-plane access to every database and container in the account. They can't be scoped down, can't be gated by conditional access, and don't identify who is using them. Unless disableLocalAuth is set to true, everything you built on Entra ID sits next to a back door that ignores all of it.
Why it happens
Cosmos DB predates its own Entra ID data-plane RBAC, so key auth is the founding access model and the default the portal, SDK quickstarts, and a decade of sample code all reach for. disableLocalAuth defaults to false, and nothing in the create flow suggests changing it.
Keys spread the way connection strings always do: pasted into app settings, CI variables, local .env files, Slack threads, and old wiki pages. Rotating a key breaks every consumer at once, so rotation gets deferred indefinitely — which means the same secret that was shared two reorgs ago still works today. And because a key is not an identity, diagnostic logs can tell you that the account was read, but not by whom.
The fix has two halves: move callers to Entra ID auth (DefaultAzureCredential plus a Cosmos DB data-plane role assignment), then set disableLocalAuth: true so the keys stop being a parallel path. Skipping the second half leaves the back door open no matter how good the front door is.
What it costs / blast radius
One leaked key — from a committed .env file, an over-shared connection string, or a compromised CI system — is full read/write on every document in the account: customer records, session data, whatever the account holds. The attacker needs no phishing, no token, no MFA bypass; the key is the whole credential. Containment is equally blunt: you can't revoke access for one holder, only rotate the key for everyone at once. (Authored assessment of Azure behavior, not a measured statistic.)
See it
resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2024-08-15' = {
name: 'cosmos-prod'
location: location
properties: {
databaseAccountOfferType: 'Standard'
locations: [
{ locationName: location, failoverPriority: 0 }
]
// disableLocalAuth omitted — both master keys grant full access
}
}resource cosmos 'Microsoft.DocumentDB/databaseAccounts@2024-08-15' = {
name: 'cosmos-prod'
location: location
properties: {
databaseAccountOfferType: 'Standard'
locations: [
{ locationName: location, failoverPriority: 0 }
]
disableLocalAuth: true // keys no longer authenticate
}
}
// Data-plane access via Cosmos DB's built-in RBAC instead.
// App code switches to DefaultAzureCredential — no secret to leak.
resource dataAccess 'Microsoft.DocumentDB/databaseAccounts/sqlRoleAssignments@2024-08-15' = {
parent: cosmos
name: guid(cosmos.id, appPrincipalId, 'data-contributor')
properties: {
// Built-in Data Contributor role
roleDefinitionId: '${cosmos.id}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002'
principalId: appPrincipalId
scope: cosmos.id
}
}How StratoLens helps
StratoLens flags every Cosmos DB account that still accepts key auth, automatically and continuously, across all your subscriptions — inside your own tenant. Instead of hoping every team remembered disableLocalAuth, you get a standing list of the accounts where a leaked connection string is still a full-account credential.