Chapter 01 · MongoDB Foundations, Editions, Deployment Models, mongosh, and Lab Setup
Build a Reproducible Lab with Sample Data, Configuration, Logging, and Safe Administrative Accounts
Assemble a safe, reproducible AtlasMart lab with explicit configuration, logs, authorization bootstrap, scoped users, deterministic sample data, and a complete reset path.
Learning outcomes
The chapter ends by replacing ad-hoc startup commands with a repeatable AtlasMart learning environment. The lab deliberately keeps the blast radius small: one Docker container, one named data volume, one configuration file, a host port bound to loopback, MongoDB authorization enabled, one administrative identity, one scoped application identity, synthetic data, inspectable logs, and a complete reset procedure.
Write a minimal self-managed mongod configuration with explicit storage, logging, port, bind, and authorization settings.
Use the localhost exception correctly to create the first administrative identity after access control is enabled.
Create a separate least-privilege application user instead of giving application code administrative credentials.
Load deterministic AtlasMart sample data and verify both authorized and unauthorized behavior.
Collect config, log, server-build, collection, and authentication evidence and reset the lab completely.
Inside the container, mongod binds to
0.0.0.0 so Docker port forwarding can reach it.
The host publication is restricted to
127.0.0.1:27018, and MongoDB authorization is
enabled. This is a local learning design, not a production
network architecture.
MongoDB’s localhost exception applies only while no users or roles exist and access control is enabled. It permits creating the first user or role from localhost, then ends. In this container lab, the first user is created by running mongosh inside the container so the connection is truly local to mongod.
1. Create an explicit configuration file
Create a new empty working directory—for example
mongodb-ch01-lab—and save the following file as
atlasmart-mongod.conf. The configuration chooses a
predictable container data path, writes logs into the same
disposable named volume, listens on MongoDB's default internal
port, accepts container-network traffic, and enables
authorization.
storage: dbPath: /data/dbsystemLog: destination: file path: /data/db/mongod.log logAppend: truenet: port: 27017 bindIp: 0.0.0.0security: authorization: enabled
bindIp: 0.0.0.0 would be unsafe if the host
published the container to an untrusted network without
additional controls. Here the host mapping is explicitly
loopback-only. The configuration is teaching two independent
boundaries: server listener scope inside its network namespace
and host exposure outside it.
2. Start the pinned server with persistent disposable data
# Bash / Git Bash / macOS / Linuxdocker run --name atlasmart-mongo-auth \ -p 127.0.0.1:27018:27017 \ -v "$PWD/atlasmart-mongod.conf:/etc/mongod.conf:ro" \ -v atlasmart-mongo-data:/data/db \ -d mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim \ --config /etc/mongod.confdocker ps --filter name=atlasmart-mongo-auth
# Windows PowerShell$cfg = (Resolve-Path .\atlasmart-mongod.conf).Pathdocker run --name atlasmart-mongo-auth ` -p 127.0.0.1:27018:27017 ` -v "${cfg}:/etc/mongod.conf:ro" ` -v atlasmart-mongo-data:/data/db ` -d mongodb/mongodb-community-server:8.3.8-ubuntu2204-slim ` --config /etc/mongod.confdocker ps --filter name=atlasmart-mongo-auth
If the container exits, do not add random flags. Read the log/exit state first:
docker ps -a --filter name=atlasmart-mongo-authdocker logs atlasmart-mongo-auth
3. Bootstrap the first administrative identity safely
Because authorization is enabled and there are no users yet,
MongoDB's localhost exception allows creation of the first user
from localhost. Execute mongosh inside the
container. The following local-only password is intentionally
marked as a disposable course secret; choose a different strong
secret if the lab is shared.
docker exec atlasmart-mongo-auth mongosh --host 127.0.0.1 --quiet --eval 'const admin = db.getSiblingDB("admin");admin.createUser({ user: "atlasUserAdmin", pwd: "LocalLab-ChangeMe-Admin-01!", roles: [ { role: "userAdminAnyDatabase", db: "admin" }, { role: "clusterAdmin", db: "admin" } ]});print("first user created");'
After that user exists, the localhost exception no longer grants unauthenticated creation privileges. Verify that a host connection without credentials cannot perform normal database operations:
# Expected to fail with an authorization error for protected operationsmongosh "mongodb://127.0.0.1:27018/atlasmart?directConnection=true" --quiet --eval 'db.products.findOne()'
4. Create a scoped application user, not another administrator
Authenticate as the administrative identity, then create an
AtlasMart application user inside the
atlasmart database. The readWrite role
is intentionally scoped to one database. Real production
services may need even narrower custom roles; that is taught in
Chapter 22.
mongosh "mongodb://atlasUserAdmin@127.0.0.1:27018/admin?authSource=admin&directConnection=true" --password --quiet --eval 'const appdb = db.getSiblingDB("atlasmart");appdb.createUser({ user: "atlasApp", pwd: "LocalLab-ChangeMe-App-01!", roles: [{ role: "readWrite", db: "atlasmart" }]});printjson(appdb.getUser("atlasApp"));'
mongosh prompts interactively instead of placing the administrative password directly in the command line. The application password is still visible in the JavaScript example because this is a disposable local lab; in real automation use a protected secret source and never commit real credentials.
5. Load deterministic AtlasMart sample data as the application identity
mongosh "mongodb://atlasApp@127.0.0.1:27018/atlasmart?authSource=atlasmart&directConnection=true" --password --quiet --eval 'db.products.deleteMany({ lab: "ch01" });db.products.insertMany([ { lab:"ch01", sku:"sku-laptop-13", name:"AtlasBook 13", category:"laptops", price:{amount:899,currency:"USD"}, tags:["portable","usb-c"] }, { lab:"ch01", sku:"sku-mug-blue", name:"Atlas Mug", category:"kitchen", price:{amount:18,currency:"USD"}, tags:["ceramic","blue"] }, { lab:"ch01", sku:"sku-sensor-a1", name:"Warehouse Sensor A1", category:"iot", attributes:{protocol:"BLE", battery:"CR2477"}, tags:["telemetry"] }]);printjson(db.products.find({lab:"ch01"},{_id:0,sku:1,category:1,tags:1}).sort({sku:1}).toArray());'
The delete-before-insert makes the seed rerunnable for this
lesson's documents. It is intentionally scoped by
lab: "ch01"; never turn a tutorial reset into an
unqualified deleteMany({}) against an unknown
database.
6. Collect configuration, build, metadata, authorization, and log evidence
A reproducible lab is not complete until you can prove how it is configured and who can do what.
# Server/config evidence (admin prompt)mongosh "mongodb://atlasUserAdmin@127.0.0.1:27018/admin?authSource=admin&directConnection=true" --password --quiet --eval 'printjson({build: db.serverBuildInfo().version});printjson(db.adminCommand({getParameter:1,featureCompatibilityVersion:1}));printjson(db.adminCommand({getCmdLineOpts:1}));printjson(db.runCommand({connectionStatus:1}));printjson(db.getSiblingDB("atlasmart").runCommand({listCollections:1,nameOnly:true}));'
# Container and log evidencedocker port atlasmart-mongo-auth 27017docker inspect atlasmart-mongo-auth --format "{{json .Mounts}}"docker exec atlasmart-mongo-auth sh -lc 'tail -n 40 /data/db/mongod.log'
Log text varies by exact patch and environment. Search for startup completion, listener address/port, authentication events, and errors rather than expecting identical line numbers. Protect logs because they can contain operational metadata and, depending on configuration/workload, potentially sensitive context.
7. Deliberately wrong approach: one admin account for the application
A common “it works” shortcut is to give the web service the same administrative identity used for user management and cluster operations. That turns one application compromise into a database-control-plane compromise. Another shortcut is to leave authorization disabled because the port is “internal,” ignoring lateral movement and accidental network exposure.
The repair is layered: bind/publish only where required, enable authentication, separate administrative and service identities, grant the least privilege needed, rotate secrets, add TLS for non-local traffic, and keep application-level tenant authorization separate from database roles. Chapter 22 expands each control.
8. Reset path, verification checklist, and production judgment
This lab must be disposable. Stopping the container without deleting the named volume intentionally preserves data. Full reset removes both.
docker rm -f atlasmart-mongo-authdocker volume rm atlasmart-mongo-data# Then delete atlasmart-mongod.conf from the disposable lab directory if desired.
Verification checklist
- The container uses the pinned 8.3.8 Community image and host port 27018 is bound only to 127.0.0.1.
-
getCmdLineOptsshows the mounted configuration was parsed, including authorization. - The first user was created from inside the container through the localhost exception, then unauthenticated protected operations fail.
-
The application identity is scoped to
atlasmartand is not used for cluster/user administration. -
Sample data can be reseeded deterministically and is tagged
lab: "ch01". - You can inspect the server log and named volume without editing WiredTiger files directly.
-
docker rmplusdocker volume rmreturns the lab to a clean state.
In production, replace disposable passwords with managed secrets, local-only networking with an explicit private/TLS architecture, a single standalone with a replica set or sharded topology as required, ad-hoc backup assumptions with tested recovery, and broad built-in roles with reviewed least privilege. Keep this Chapter 01 configuration as a learning artifact, not a production template.
Chapter 02 now has a stable environment in which to study BSON,
_id/ObjectId, exact type fidelity,
arrays/embedded documents, flexible-schema contracts, and
document limits.
Check your understanding
- When does the localhost exception apply on mongod?
- Why create atlasApp separately from atlasUserAdmin?
- Why does the lab bind mongod to 0.0.0.0 inside the container but still call the host exposure local-only?
- Why is deleteMany({lab:"ch01"}) safer than deleteMany({}) in a tutorial reset?
- What makes a backup or security control production-ready?
Review the answers
Only when access control is enabled and there are no users or roles in the instance. It exists to bootstrap the first user or role (and certain replica-set setup actions), then ends.
Applications should not inherit user-management or cluster-administration power. Separating identities limits blast radius and makes authorization evidence clearer.
The container listener must accept traffic arriving through Docker networking, while Docker publishes that port only on host loopback 127.0.0.1. These are different network namespaces/boundaries.
It scopes cleanup to deterministic lesson-owned documents rather than deleting every document in a collection that might contain unrelated data.
Not merely enabling a feature: it needs defined ownership, least privilege/threat model, monitoring, tested failure/recovery behavior, and evidence that it meets the application’s requirements.
Authoritative references
- MongoDB release notes — Official source for the current stable server series and patch notes.
- MongoDB 8.3 release notes — Official 8.3 behavior, patch, compatibility, and security/reliability change log.
- mongosh release notes — Official shell release history; 2.10.0 was released 13 August 2026.
- Role-Based Access Control — Official RBAC model and statement that self-managed access control is not enabled by default.
- Localhost exception — Official bootstrap conditions, capabilities, and end of the exception.
- Runtime configuration — Official configuration-file guidance for bind and authorization settings.
- IP binding — Official localhost default and bind-all warning.
- Security hardening — Official trusted-network and configuration-hardening guidance.