Cosmos DB Integration (Managed Identity)
Use this recipe to connect a Node.js Container App to Azure Cosmos DB for NoSQL with managed identity first and a connection string fallback only when you cannot use RBAC yet.
Architecture
flowchart TD
C[Client] --> I[Container Apps Ingress]
I --> APP[Node.js Container App]
APP --> COSMOS[Azure Cosmos DB]
APP -.-> MI[Managed Identity]
MI -.-> ENTRA[Microsoft Entra ID]
MI -.-> COSMOS
Solid arrows show runtime data flow. Dashed arrows show identity and authentication.
Prerequisites
- Existing Container App:
$APP_NAME in resource group $RG - Existing Azure Cosmos DB account, SQL database, and container
- Azure CLI with Container Apps and Cosmos extensions
az extension add --name containerapp --upgrade
az extension add --name cosmosdb-preview --upgrade
| Command | Why it is used |
az extension add ... | Installs or updates the Container Apps Azure CLI extension. |
Step 1: Enable managed identity on the Container App
az containerapp identity assign \
--name "$APP_NAME" \
--resource-group "$RG" \
--system-assigned
export PRINCIPAL_ID=$(az containerapp show \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "identity.principalId" \
--output tsv)
| Command | Why it is used |
az containerapp identity assign ... | Assigns or inspects managed identity configuration for the Container App. |
Step 2: Grant Cosmos DB data-plane access
export COSMOS_ACCOUNT_ID=$(az cosmosdb show \
--name "$COSMOS_ACCOUNT" \
--resource-group "$RG" \
--query "id" \
--output tsv)
az role assignment create \
--assignee-object-id "$PRINCIPAL_ID" \
--assignee-principal-type ServicePrincipal \
--role "Cosmos DB Built-in Data Contributor" \
--scope "$COSMOS_ACCOUNT_ID"
| Command | Why it is used |
az cosmosdb show ... | Creates or inspects Cosmos DB resources used by the sample app. |
Azure Container Apps does not inject Cosmos DB connection settings automatically. Store non-secret values as environment variables, and store fallback secrets in secrets[] with secretref:.
az containerapp update \
--name "$APP_NAME" \
--resource-group "$RG" \
--set-env-vars COSMOS_ENDPOINT="https://$COSMOS_ACCOUNT.documents.azure.com:443/" COSMOS_DATABASE="$COSMOS_DATABASE" COSMOS_CONTAINER="$COSMOS_CONTAINER"
| Command | Why it is used |
az containerapp update ... | Updates the existing Container App configuration without recreating the app. |
Step 4: Node.js code (managed identity)
Install dependencies:
npm install @azure/cosmos @azure/identity
Use DefaultAzureCredential when COSMOS_CONNECTION_STRING is not present:
const { CosmosClient } = require("@azure/cosmos");
const { DefaultAzureCredential } = require("@azure/identity");
function createCosmosClient() {
const connectionString = process.env.COSMOS_CONNECTION_STRING;
if (connectionString) {
return new CosmosClient(connectionString);
}
return new CosmosClient({
endpoint: process.env.COSMOS_ENDPOINT,
aadCredentials: new DefaultAzureCredential(),
});
}
async function run() {
const client = createCosmosClient();
const database = client.database(process.env.COSMOS_DATABASE);
const container = database.container(process.env.COSMOS_CONTAINER);
const item = {
id: "order-1001",
partitionKey: "order-1001",
type: "order",
status: "created",
};
await container.items.upsert(item, { partitionKey: item.partitionKey });
const { resource } = await container.item(item.id, item.partitionKey).read();
console.log(resource);
}
run().catch((error) => {
console.error(error);
process.exitCode = 1;
});
Step 5: Connection string fallback
Only use this pattern when you cannot enable RBAC yet.
az containerapp secret set \
--name "$APP_NAME" \
--resource-group "$RG" \
--secrets cosmos-connection-string="AccountEndpoint=https://$COSMOS_ACCOUNT.documents.azure.com:443/;AccountKey=<cosmos-account-key>;"
az containerapp update \
--name "$APP_NAME" \
--resource-group "$RG" \
--set-env-vars COSMOS_CONNECTION_STRING=secretref:cosmos-connection-string COSMOS_DATABASE="$COSMOS_DATABASE" COSMOS_CONTAINER="$COSMOS_CONTAINER"
| Command | Why it is used |
az containerapp secret set ... | Manages Container Apps secrets without exposing secret values in plain configuration. |
Verification
- Confirm identity assignment:
az containerapp show \
--name "$APP_NAME" \
--resource-group "$RG" \
--query "identity" \
--output json
| Command | Why it is used |
az containerapp show ... | Reads the Container App configuration so the documented setting can be verified. |
- Confirm role assignment exists:
az role assignment list \
--assignee "$PRINCIPAL_ID" \
--scope "$COSMOS_ACCOUNT_ID" \
--output table
| Command | Why it is used |
az role assignment list ... | Lists Azure RBAC assignments to verify access or diagnose conflicts. |
- Check app logs for successful upsert and read operations:
az containerapp logs show \
--name "$APP_NAME" \
--resource-group "$RG" \
--follow false
| Command | Why it is used |
az containerapp logs show ... | Runs the Azure CLI operation required by the documented step. |
See Also
Sources