← back

Security
& Auth

FILE  35_security_auth
TOPIC  SCRAM · x.509 · RBAC · Built-in Roles · TLS · CSFLE · Auditing
LEVEL  Intermediate/Advanced
01
Security Overview
Authentication · Authorization · Encryption in transit and at rest
overview

MongoDB security has two distinct layers: authentication (who are you?) and authorization (what can you do?). Both are disabled by default in standalone development installations — production deployments must enable both.

DANGER
MongoDB without authentication enabled allows any client with network access to read and write all data. Many MongoDB breaches (the "MongoDB ransomware" incidents of 2017+) exploited databases left running without authentication on public networks. Always enable auth: --auth flag or security.authorization: enabled in mongod.conf.
// Enable authentication in mongod.conf:
security:
  authorization: enabled

// Or via command line flag:
mongod --auth --dbpath /data/db

// First: create admin user before enabling auth
// (Local Exception: when no users exist, localhost can connect without auth)
use admin
db.createUser({
  user: "adminUser",
  pwd:  "securePassword123!",
  roles: [{ role: "userAdminAnyDatabase", db: "admin" }, "readWriteAnyDatabase"]
})
02
SCRAM Authentication
Salted Challenge Response Authentication Mechanism — the default
SCRAM

SCRAM (Salted Challenge Response Authentication Mechanism) is MongoDB's default authentication mechanism. It is a challenge-response protocol — the password is never sent over the wire; only cryptographic proofs are exchanged.

// Create application user with specific database access
use myAppDb
db.createUser({
  user:  "appUser",
  pwd:   "appPass123!",          // or use passwordPrompt() for interactive
  roles: [
    { role: "readWrite", db: "myAppDb" },
    { role: "read",      db: "reportingDb" }
  ]
})

// Create read-only user for analytics
db.createUser({
  user:  "analyticsUser",
  pwd:   passwordPrompt(),       // prompts without echoing
  roles: [{ role: "read", db: "myAppDb" }]
})

// Update user password
db.updateUser("appUser", { pwd: "newSecurePass!" })

// View users in current database
db.getUsers()

// Drop user
db.dropUser("oldUser")

// Connection string with authentication:
// mongodb://appUser:appPass123!@mongo1:27017/myAppDb?authSource=myAppDb

SCRAM Versions

MechanismHashDefault Since
SCRAM-SHA-1SHA-1MongoDB 3.0
SCRAM-SHA-256SHA-256 (stronger)MongoDB 4.0 (preferred)
03
x.509 Certificate Auth
Mutual TLS for client and intra-cluster authentication
x.509

x.509 authentication uses TLS certificates instead of username/password. The client presents a certificate signed by a trusted CA; MongoDB extracts the subject DN as the username. Used for service-to-service auth and intra-cluster (replica set member) authentication.

// mongod.conf: require x.509 for client auth
net:
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongodb.pem
    CAFile: /etc/ssl/ca.pem
security:
  authorization: enabled
  clusterAuthMode: x509

// Create a user whose name matches the certificate's subject DN
use $external   // x.509 users live in $external database
db.createUser({
  user: "CN=appService,OU=Engineering,O=MyCompany,C=US",  // cert subject
  roles: [{ role: "readWrite", db: "myAppDb" }]
})

// Connect with x.509 certificate:
mongosh --tls \
  --tlsCertificateKeyFile /etc/ssl/client.pem \
  --tlsCAFile /etc/ssl/ca.pem \
  --authenticationMechanism MONGODB-X509 \
  --authenticationDatabase '$external' \
  "mongodb://mongo1:27017/"

Intra-Cluster Auth (Keyfile vs x.509)

MethodHow It WorksUse Case
KeyfileShared secret file on all replica set membersSimple setups; development clusters
x.509Each member has a TLS certificate; mutual authProduction; enterprise security requirements
// Keyfile: generate and distribute to all replica set members
openssl rand -base64 756 > /etc/mongodb/keyfile
chmod 400 /etc/mongodb/keyfile

// mongod.conf keyfile config:
security:
  keyFile: /etc/mongodb/keyfile
04
Role-Based Access Control (RBAC)
Grant privileges through roles — never grant more than needed
RBAC

MongoDB's authorization model is RBAC — users are granted roles, and roles contain privileges (action + resource combinations). Roles can be built-in or custom.

// Create a custom role with specific privileges
use myAppDb
db.createRole({
  role: "orderManager",
  privileges: [
    {
      resource: { db: "myAppDb", collection: "orders" },
      actions: ["find", "insert", "update"]   // NO delete
    },
    {
      resource: { db: "myAppDb", collection: "customers" },
      actions: ["find"]                        // read-only on customers
    }
  ],
  roles: []   // inherit from other roles (or empty)
})

// Grant custom role to user
db.grantRolesToUser("appUser", [{ role: "orderManager", db: "myAppDb" }])

// Revoke a role
db.revokeRolesFromUser("appUser", [{ role: "orderManager", db: "myAppDb" }])

// View a user's current roles and privileges
db.getUser("appUser", { showPrivileges: true })

Privilege Actions Reference

Action GroupActions
Readfind, listCollections, listIndexes
Writeinsert, update, remove
AdmincreateIndex, dropCollection, createCollection
Database AdmindbStats, collStats, indexStats
05
Built-in Roles
Standard roles for common access patterns
roles

Database-Level Roles

RoleScopeGrants
readSpecific DBQuery all collections in the DB
readWriteSpecific DBRead + write (insert/update/delete) all collections
dbAdminSpecific DBAdmin tasks: stats, indexes, validation — no data read/write
dbOwnerSpecific DBFull control of the database (readWrite + dbAdmin + userAdmin)
userAdminSpecific DBCreate and modify users and roles on the DB

Cluster-Level Roles (admin DB)

RoleGrants
readAnyDatabaseRead access across all databases
readWriteAnyDatabaseRead+write across all databases
userAdminAnyDatabaseManage users across all databases
dbAdminAnyDatabaseAdmin tasks across all databases
clusterAdminFull cluster management (replication, sharding, server)
clusterMonitorRead-only cluster monitoring access
backupPermissions needed for backup operations
restorePermissions needed for restore operations
rootSuperuser — all privileges on all resources
WARN
Grant root or userAdminAnyDatabase only to dedicated admin accounts used for maintenance — never to application users. Application users should have the minimum privileges needed: typically readWrite on their specific database only.
06
TLS / Network Security
Encrypt all data in transit — mandatory for production
TLS

TLS (Transport Layer Security) encrypts all data transmitted between clients and MongoDB, and between replica set members. Without TLS, credentials and data are transmitted in plaintext.

// mongod.conf TLS configuration:
net:
  port: 27017
  tls:
    mode: requireTLS               # allowTLS | preferTLS | requireTLS
    certificateKeyFile: /etc/ssl/mongod.pem     # server cert + private key
    CAFile: /etc/ssl/ca.pem                     # CA to validate client certs
    allowConnectionsWithoutCertificates: true   # allow clients without cert (one-way TLS)

// Connect with TLS (client):
mongosh --tls --tlsCAFile /etc/ssl/ca.pem "mongodb://user:pass@host:27017/db"

// Connection string:
// mongodb://host:27017/?tls=true&tlsCAFile=/etc/ssl/ca.pem

Network Hardening

// Bind to specific IP only (not 0.0.0.0)
net:
  bindIp: 127.0.0.1,10.0.1.5   # localhost + private network only

// Disable server-side JavaScript (if not needed)
security:
  javascriptEnabled: false

// IP allowlist (restrict connection source IPs)
// Handled at network/firewall level — not MongoDB config
// MongoDB Atlas: network access IP allowlist in project settings
07
CSFLE & Auditing
Client-Side Field Level Encryption and operation logging
encrypt

Encryption at Rest

WiredTiger supports encrypted storage engine (MongoDB Enterprise) — all data files encrypted at rest using AES-256. Data is decrypted only in memory during queries, never written to disk in plaintext.

// mongod.conf: enable WiredTiger encryption at rest (Enterprise only)
security:
  enableEncryption: true
  encryptionKeyFile: /etc/mongodb/encryption.key

Client-Side Field Level Encryption (CSFLE)

CSFLE (available in MongoDB 4.2+ Community; automatic mode in Enterprise/Atlas) encrypts specific document fields in the client driver before writing to MongoDB. The server stores and queries only ciphertext — even a compromised server cannot read the original values.

// CSFLE encrypts fields in the application layer (Node.js example)
const clientEncryption = new ClientEncryption(mongoClient, {
  keyVaultNamespace: "encryption.__keyVault",
  kmsProviders: { local: { key: localMasterKey } }
})

// Create encrypted field schema
const encryptedFields = {
  fields: [
    {
      path:     "ssn",             // encrypt this field
      bsonType: "string",
      queries:  [{ queryType: "equality" }]   // allow equality search on encrypted value
    }
  ]
}
// Key stored in key vault; server only sees encrypted bytes
// Useful for: SSNs, credit card numbers, PII that must be queryable

Auditing

MongoDB Enterprise/Atlas supports auditing — logging authentication events, authorization failures, and CRUD operations to a log file or syslog for compliance requirements (SOC2, HIPAA, PCI-DSS).

// mongod.conf: enable audit log (Enterprise only)
auditLog:
  destination: file
  format:      JSON
  path:        /var/log/mongodb/audit.json
  filter: '{ atype: { $in: ["authenticate", "authCheck", "dropCollection"] } }'
// atype options: authenticate, authCheck, logout, createCollection,
//   dropCollection, createIndex, find, insert, update, remove, etc.

// Security checklist summary:
// ✓ Authentication enabled (--auth)
// ✓ Users follow least-privilege (no root for app users)
// ✓ TLS enabled (requireTLS mode)
// ✓ bindIp restricted (not 0.0.0.0)
// ✓ Intra-cluster using keyfile or x.509
// ✓ Encryption at rest enabled (Enterprise)
// ✓ Audit logging configured (Enterprise)
// ✓ Separate admin vs application accounts