MongoDB Mastery
MongoDB Mastery lessons / Module 27: Security

Security: authentication, RBAC, TLS and encryption

Level 4: Database Engineer28 min

Harden a self-managed deployment: enable auth, least-privilege roles, TLS everywhere, internal authentication, encryption at rest, field-level encryption and auditing.

This lesson is interactive. Run every example against an in-browser MongoDB, see explain() plans drawn as trees, and take the quiz.
Open the interactive lesson
You will learn to
  • Enable authentication and create least-privilege users
  • Use built-in and custom roles
  • Configure TLS and internal member authentication
  • Choose between encryption at rest, CSFLE and Queryable Encryption

conceptThe concept

  • Authentication: SCRAM-SHA-256 by default; x.509 certificates; LDAP, Kerberos and OIDC in Enterprise editions (Percona Server for MongoDB also supports LDAP and Kerberos).
  • Authorization (RBAC): users get roles; roles grant privileges (actions on resources). Built-ins: read, readWrite, dbAdmin, userAdmin, clusterMonitor, clusterAdmin, backup, restore, root. Custom roles narrow privileges further.
  • Network: bindIp to private interfaces, firewall/security groups, TLS with net.tls.mode: requireTLS.
  • Internal auth: replica set and cluster members authenticate each other with a keyFile or x.509 (security.clusterAuthMode).
  • Encryption at rest: storage-engine encryption (Enterprise, Percona Server for MongoDB with Vault/KMIP), or volume encryption (LUKS, EBS).
  • Client-side field level encryption (CSFLE) and Queryable Encryption (7.0 GA): the driver encrypts sensitive fields before they leave the application; the server never sees plaintext.
  • Auditing: MongoDB Enterprise and Percona Server for MongoDB (free) write an audit log of authentication attempts, user and role changes, DDL and, if you opt in, reads and writes. Community Edition has no audit log. Configure it under auditLog with a filter so you record what compliance needs without logging every query; CRUD auditing also needs auditAuthorizationSuccess and costs throughput. Ship the file off the host (syslog or a log agent) so an attacker with server access cannot quietly edit it.

whyWhy it matters

Unauthenticated MongoDB instances exposed to the internet were famously ransomed by the thousands. Today the risks are subtler: over-privileged application users, shared admin credentials, plaintext connections inside the VPC, and backups without encryption.

Use caseReal-world scenario

The shop application connects as shop_app with readWrite on shop only; reporting uses shop_ro with read pinned to analytics nodes; the backup agent uses the backup role; humans log in with LDAP accounts mapped to roles; card numbers are protected with Queryable Encryption so DBAs never see them.

Try itExamples

Run and edit these in the interactive lesson.

Least-privilege users and a custom role
use admin
// clean up from a previous run so the example can be repeated
for (const u of ["shop_app", "analyst"]) { try { db.dropUser(u) } catch (e) {} }
try { db.dropRole("ordersReadOnlyNoPII") } catch (e) {}
db.createRole({ role: "ordersReadOnlyNoPII", privileges: [{ resource: { db: "shop", collection: "orders" }, actions: ["find"] }], roles: [] })
db.createUser({ user: "shop_app", pwd: "use-a-secret-manager", roles: [{ role: "readWrite", db: "shop" }] })
db.createUser({ user: "analyst", pwd: "use-a-secret-manager", roles: ["ordersReadOnlyNoPII", { role: "clusterMonitor", db: "admin" }] })
db.getUsers().users.map(u => ({ user: u.user, roles: u.roles }))
use shop
mongod.conf security section
net:
  port: 27017
  bindIp: 10.0.1.15,localhost
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/mongo/tls/server.pem
    CAFile: /etc/mongo/tls/ca.pem
security:
  authorization: enabled
  clusterAuthMode: x509          # or keyFile: /etc/mongo/keyfile (chmod 400)
setParameter:
  authenticationMechanisms: SCRAM-SHA-256,MONGODB-X509
Audit: who can do what?
db.adminCommand({ connectionStatus: 1 })
db.getSiblingDB("admin").getRoles({ showPrivileges: false, showBuiltinRoles: false })
Audit log: record logins, user changes and DDL
# mongod.conf on Percona Server for MongoDB (same keys on MongoDB Enterprise)
auditLog:
  destination: file              # or syslog, so the trail leaves the host
  format: JSON
  path: /var/log/mongodb/audit.json
  filter: '{ atype: { $in: [
    "authenticate", "logout",
    "createUser", "dropUser", "updateUser", "grantRolesToUser", "revokeRolesFromUser",
    "createRole", "dropRole", "updateRole",
    "createCollection", "dropCollection", "dropDatabase", "renameCollection",
    "createIndex", "dropIndex", "shutdown"
  ] } }'

# Failed logins only, for a brute-force alert:
#   filter: '{ atype: "authenticate", result: { $ne: 0 } }'     # 18 = AuthenticationFailed

internalsUnder the hood

Users are stored in admin.system.users with salted SCRAM credentials; the authentication database is where the user is defined (authSource). The localhost exception lets you create the first user on a fresh instance with auth enabled, then closes. With CSFLE the driver fetches data keys from a key vault collection, encrypted by a customer master key in a KMS (AWS KMS, Azure, GCP, KMIP); deterministic encryption allows equality queries, random encryption does not, and Queryable Encryption supports equality and range on randomly encrypted data.

Avoid / preferDo this, not that

Avoid
db.createUser({ user: "app", pwd: "app123", roles: ["root"] })
Prefer
db.createUser({ user: "app", pwd: passwordPrompt(),
  roles: [{ role: "readWrite", db: "shop" }] })

An application needs read and write on its own database, nothing more. root turns any SQL-injection-style bug into a full cluster compromise.

Avoid
net:
  bindIp: 0.0.0.0
Prefer
net:
  bindIp: 10.0.1.5
  tls:
    mode: requireTLS
    certificateKeyFile: /etc/ssl/mongod.pem
security:
  authorization: enabled

Bind to the private interface only, require TLS, and turn on authorization. Exposed, unauthenticated instances are found and wiped within hours.

PitfallsCommon mistakes

  • Binding to 0.0.0.0 with auth disabled, even "temporarily".
  • One root user shared by the application, scripts and humans.
  • TLS only at the load balancer while member-to-member traffic is plaintext.
  • Passwords in connection strings committed to git; use a secret manager and rotate.
  • Keyfiles with permissive file permissions, or the same keyfile across environments.

LimitsWhen not to use it

Do not build your own authentication proxy or encryption layer in front of MongoDB when built-in SCRAM, x.509, TLS and roles cover the need. Do not give applications dbOwner or dbAdmin "to be safe"; those roles can drop collections and change validation.

SecuritySecurity notes

SCRAM-SHA-256 is the default mechanism. For audit trails, MongoDB Enterprise and Percona Server for MongoDB provide an audit log; enable it for authentication events and privileged commands, and ship it off the host.

ChallengeTry it yourself

Create a custom role reviewWriter that can only read orders and insert into reviews, create a user with only that role, and show the user's roles.

Show one solution
One solution
db.createRole({ role: "reviewWriter", privileges: [
  { resource: { db: "shop", collection: "orders" }, actions: ["find"] },
  { resource: { db: "shop", collection: "reviews" }, actions: ["insert"] }
], roles: [] })
db.createUser({ user: "review_svc", pwd: "use-passwordPrompt-in-real-shells", roles: ["reviewWriter"] })
db.getUser("review_svc").roles
In a real shell, replace the literal password with passwordPrompt(). Running this twice fails because the role already exists.

InterviewQuestions you should be able to answer

How would you secure a new self-managed MongoDB deployment?

Private network only (bindIp, security groups), TLS required for clients and members, internal auth via x.509 or keyFile, authorization: enabled, admin user created via the localhost exception, per-application least-privilege users and custom roles, human access via LDAP/OIDC with MFA where available, encryption at rest (engine or volume), CSFLE/Queryable Encryption for PII, auditing enabled, secrets in a vault with rotation, encrypted backups in a separate account, and regular patching.

CSFLE vs encryption at rest?

Encryption at rest protects data files and backups from someone with disk access; the server and DBAs still see plaintext. CSFLE and Queryable Encryption encrypt specific fields in the driver, so the server, logs, backups and DBAs only see ciphertext; only applications with access to the keys can decrypt. They complement each other.

An auditor asks who changed a user's roles last month. How do you answer on self-managed MongoDB?

From the audit log, if it was enabled: Percona Server for MongoDB or Enterprise record grantRolesToUser, updateUser and similar events with the user, client address and time. Community Edition has no audit log, so the honest answer there is "we cannot prove it"; that is a reason to run Percona Server or Enterprise where compliance matters. Going forward: a filter covering authentication, user and role changes and DDL, the log shipped off the host to append-only storage, retention matching the policy, and alerts on failed logins and privilege changes.

QuizCheck your understanding

5 questions with instant feedback in the interactive lesson; a wrong answer goes into your review deck.