Skip to main content

MongoDB Passwordless Authentication on Azure AKS using Workload Identity

· 9 min read
Abdulmalik
AppSec Engineer

best bet, you are still not rotating your DB passwords and tokens across your infra, but if the software integrations you use, has a stable passwordless option, i think you shouldnt keep a static credentials option then?

I already wrote the AWS EKS version of this: IRSA + MONGODB-AWS. This is the Azure sibling.

Same idea, different plumbing. On AKS you use Workload Identity + Atlas Workload Identity Federation (MONGODB-OIDC). No long-lived DB password. Your pod gets a short-lived Entra token, Atlas trusts that IdP, done.

One big gotcha up front: this only works on Atlas dedicated clusters (M10+). Free / Flex / shared tiers do not support MONGODB-OIDC. If you try this on an M0 and wonder why Federated Auth never shows up the way you expect, that's why.

Prerequisites

  • AKS with OIDC issuer and Workload Identity enabled
  • Atlas dedicated cluster (M10+, MongoDB 7.0.11+)
  • Microsoft Entra tenant (you need Org Owner on Atlas for Federation)
  • Node.js MongoDB driver 6.7+ (or another driver that supports Workload Identity Federation)
  • Terraform / OpenTofu if you want the snippets below as-is

Step 1: Entra app registration (the Atlas audience)

Atlas Workload IdP needs an Entra app whose Application ID URI becomes the OIDC audience. Keep that URI boring and stable, e.g. api://atlas-wif.

entra-app.tf
resource "azuread_application" "atlas_wif" {
display_name = "atlas-wif"
sign_in_audience = "AzureADMyOrg"

identifier_uris = ["api://atlas-wif"]

api {
requested_access_token_version = 2
}
}

resource "azuread_service_principal" "atlas_wif" {
client_id = azuread_application.atlas_wif.client_id
}

From the tenant you also need the issuer:

https://login.microsoftonline.com/<TENANT_ID>/v2.0

That's the Atlas Issuer URI (no /.well-known/openid-configuration suffix).

Step 2: User-assigned managed identity + federated credential

Create a UAMI for the workload, then federate it to the Kubernetes service account.

aks-wif.tf
resource "azurerm_user_assigned_identity" "app" {
name = "aks-mongo-wif"
resource_group_name = var.resource_group_name
location = var.location
}

resource "azurerm_federated_identity_credential" "app" {
name = "aks-mongo-wif"
resource_group_name = var.resource_group_name
parent_id = azurerm_user_assigned_identity.app.id
audience = ["api://AzureADTokenExchange"]
issuer = azurerm_kubernetes_cluster.this.oidc_issuer_url
subject = "system:serviceaccount:${var.app_namespace}:${var.app_service_account}"
}

Note the two different audiences:

  • api://AzureADTokenExchange: Entra ↔ AKS Workload Identity token exchange
  • api://atlas-wif: what Atlas validates on the access token

Don't mix them up.

Also grab the UAMI Object (principal) ID. That is what you put in Atlas as the federated database user identifier, not the client ID.

FieldUse
UAMI Object ID / principal IDAtlas Database Access user identifier
UAMI Client IDK8s SA annotation + Azure Identity client config

Step 3: Atlas Federation → Workload IdP → OIDC

In Atlas: Identity & Access → Federation (org owner).

Atlas sidebar with Federation under Identity and Access

Open Federation Management → Identity Providers → configure a new IdP.

Pick Workload, not Workforce. Workforce is for humans (SSO into Atlas UI). Workload is for apps.

Atlas choose Workload Identity Federation

Fill OIDC protocol settings:

SettingExample
Configuration Nameazure-wif
Issuer URIhttps://login.microsoftonline.com/<TENANT_ID>/v2.0
Audienceapi://atlas-wif (must match Entra Application ID URI)
AuthorizationUser ID
User Claimsub (default)
Atlas OIDC protocol settings issuer audience User ID

Save. You should get the success banner and the IdP card with issuer / audience / sub.

Atlas Workload IdP configured successfully

Step 4: Connect the IdP to your organization

An IdP that isn't connected to an org does nothing useful for database access. Under Federation → Organizations → your org → Connect Identity Provider, select the Workload IdP (Data Access), connect.

Connect Workload Identity Provider modal

When it sticks, you get the green "successfully connected" banner. All projects in that org can use it.

Workload IdP connected to Atlas organization

Step 5: Database user = UAMI Object ID

Project → Security → Database Access → Add New Database User.

  • Authentication Method: Federated Auth
  • Identity Provider: your azure-wif Workload IdP
  • User Identifier: UAMI Object ID (principal ID)

Not the client ID. Not the display name. Object ID.

Then roles + (optionally) restrict to a specific cluster.

Add database user with Federated Auth

Assign a built-in role (or tighter custom roles), and if you want blast-radius control, turn on Restrict Access to Specific Clusters and pick the cluster.

Database user roles and cluster restriction

Step 6: Kubernetes service account + pod label

Workload Identity needs both the SA annotations and the pod label. Forget the label and you will waste an afternoon.

serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
name: invoicing-app
namespace: default
annotations:
azure.workload.identity/client-id: "<UAMI_CLIENT_ID>"
labels:
azure.workload.identity/use: "true"
deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: invoicing
spec:
template:
metadata:
labels:
app: invoicing
azure.workload.identity/use: "true"
spec:
serviceAccountName: invoicing-app
containers:
- name: invoicing
image: your-registry/invoicing:latest
env:
- name: MONGODB_URI
value: "mongodb+srv://cluster0.example.mongodb.net/?authMechanism=MONGODB-OIDC"
- name: ATLAS_TOKEN_RESOURCE
value: "api://atlas-wif"

With Workload Identity wired correctly, the webhook injects things like:

  • AZURE_CLIENT_ID
  • AZURE_TENANT_ID
  • AZURE_FEDERATED_TOKEN_FILE

That last one is the projected SA token path Entra will exchange.

Step 7: App connection (MONGODB-OIDC)

The IMDS trap on AKS

The Node driver's built-in Azure path looks like this:

authMechanism=MONGODB-OIDC
authMechanismProperties=ENVIRONMENT:azure,TOKEN_RESOURCE=api://atlas-wif

That path talks to Azure IMDS. On a normal Azure VM with a managed identity attached, fine.

On AKS Workload Identity, IMDS often answers with something like Identity not found. Your UAMI lives behind the federated token file, not classic IMDS association. So don't cargo-cult the VM snippet into AKS and expect miracles.

What works: callback + Entra token for the Atlas audience

Use @azure/identity (it understands Workload Identity env vars) and hand Atlas a real Entra access token whose audience is api://atlas-wif.

mongo.js
import { DefaultAzureCredential } from "@azure/identity";
import { MongoClient } from "mongodb";

const tokenResource = process.env.ATLAS_TOKEN_RESOURCE; // api://atlas-wif
const clusterUrl = process.env.MONGODB_CLUSTER_URL; // cluster0.xxxxx.mongodb.net

if (!tokenResource) throw new Error("ATLAS_TOKEN_RESOURCE must be defined");
if (!clusterUrl) throw new Error("MONGODB_CLUSTER_URL must be defined");

const credential = new DefaultAzureCredential();

async function oidcCallback() {
// audience must match Atlas Workload IdP + Entra Application ID URI
const token = await credential.getToken(`${tokenResource}/.default`);
if (!token?.token) {
throw new Error("failed to acquire Entra access token for Atlas");
}
return {
accessToken: token.token,
expiresInSeconds: Math.max(
60,
Math.floor((token.expiresOnTimestamp - Date.now()) / 1000)
),
};
}

const uri = `mongodb+srv://${clusterUrl}/?authMechanism=MONGODB-OIDC`;

const client = new MongoClient(uri, {
authMechanismProperties: {
OIDC_CALLBACK: oidcCallback,
},
});

await client.connect();
console.log("Connected to MongoDB with Workload Identity");

Install what you need:

yarn add mongodb @azure/identity

Driver version matters: Node / TypeScript 6.7+ for Workload Identity Federation support.

Optional: ENVIRONMENT:k8s

The driver also has ENVIRONMENT:k8s, which reads AZURE_FEDERATED_TOKEN_FILE directly. That file is the Kubernetes projected token used for Entra exchange, not necessarily an Atlas-ready access token with audience api://atlas-wif. For Atlas Workload IdP against Entra, prefer the callback that requests a token for your Application ID URI.

Gotchas (read these before you open a ticket)

  1. M10+ dedicated only. Free / Flex / shared do not support this auth mechanism. Upgrade first.
  2. Object ID ≠ Client ID. Atlas user identifier = UAMI Object ID. SA annotation / Azure Identity = Client ID.
  3. Audience must match everywhere it matters. Entra Application ID URI ↔ Atlas IdP Audience ↔ TOKEN_RESOURCE / getToken(...) scope. One typo and auth fails in the least helpful way.
  4. Don't use ENVIRONMENT:azure on AKS WI unless you know IMDS can see that identity. Expect Identity not found otherwise; use OIDC_CALLBACK + federated token / @azure/identity.
  5. Pod label required: azure.workload.identity/use: "true" on the pod template, not only the SA.
  6. Workforce ≠ Workload. Wrong IdP type = wrong product surface. Apps need Workload.
  7. Issuer format: https://login.microsoftonline.com/<TENANT_ID>/v2.0 (drop the well-known suffix).

Conclusion

EKS was IAM role → MONGODB-AWS. AKS is UAMI + Workload Identity → Entra token → Atlas Workload IdP → MONGODB-OIDC. Same destination: no static Mongo password sitting in your cluster forever.

Till next time, Peace be on you 🤞🏽

References


Comments