MongoDB
Overview
In abcdesktop, MongoDB serves as the primary database for the control plane (pyos). It stores all persistent application data: user profiles, login history, application inventory, desktop session states, and fail2ban data.
MongoDB is deployed as a ReplicaSet (name: rs0), with authentication enabled and inter-member communication secured by a keyfile.
Kubernetes Resource Architecture
The following diagram shows all Kubernetes resources involved in the MongoDB deployment:
MongoDB-related Kubernetes Resources
This Opaque secret holds all credentials required for MongoDB initialization and access.
| Key | Value (from manifest) | Purpose |
|---|---|---|
MONGO_ROOT_USERNAME |
root |
MongoDB superuser |
MONGO_ROOT_PASSWORD |
Oge5iQw9dGBvRDd |
Root password |
MONGO_USERNAME |
pyos |
Application user |
MONGO_PASSWORD |
Az4MeYWUjZDg4Zjhk |
Application user password |
MONGO_USERS_LIST |
pyos:readWrite:Az4MeYWUjZDg4Zjhk |
user:role:password list |
MONGO_DBS_LIST |
image,fail2ban,loginHistory,applications,profiles,desktop |
Databases to initialize |
MONGODB_URL |
mongodb://pyos:...@mongodb |
Connection URL for pyos |
⚠️ Security note: passwords are stored in plaintext in the manifest (
stringData). In production, a secrets manager (Vault, Sealed Secrets, External Secrets Operator, etc.) is strongly recommended.
The secret is mounted inside the MongoDB pod with the following path mapping:
This ConfigMap contains 4 key files injected into the pod:
mongod.conf — MongoDB daemon configuration
net:
bindIp: 0.0.0.0
port: 27017
replication:
replSetName: rs0
security:
authorization: enabled
keyFile: /etc/mongodb/mongod.keyfile
storage:
dbPath: /data/db
Notable settings:
- Listens on all interfaces (
0.0.0.0:27017) - ReplicaSet named
rs0 - Authentication enabled, keyfile required
init-container.sh — Configuration file preparation
Script executed by the InitContainer before MongoDB starts:
- Copies
mongod.confandmongod.keyfileto/work/config - Applies required permissions (
chmod 400on the keyfile) - Creates and prepares
/data/dband/var/log/mongodb - Ensures the
mongodbOS user owns all relevant directories
init.js — Database and user initialization
JavaScript script executed automatically by MongoDB on first startup (via /docker-entrypoint-initdb.d/):
- Reads the database list (
MONGO_DBS_LIST) and user list (MONGO_USERS_LIST) from mounted secret files - Authenticates as root against the
admindatabase - For each listed database, creates the corresponding users with their defined roles
- Handles duplicates gracefully (idempotent: does not fail if the user already exists)
init-replica.sh — ReplicaSet initialization
Bash script executed by the replica-manager sidecar, only on pod mongodb-od-0:
- Builds the member list dynamically based on the configured replica count
- Waits until all members respond to ping
- Checks whether the ReplicaSet is already initialized
- If not: calls
rs.initiate()with the dynamically built configuration - Waits for a PRIMARY to be elected
- Displays the final ReplicaSet state
The StatefulSet is the core of the deployment, configured with 1 replica (scalable).
sequenceDiagram
participant K8s as Kubernetes Scheduler
participant IC as InitContainer<br/>prepare-config
participant MDB as Container<br/>mongodb
participant RM as Sidecar<br/>replica-manager
K8s->>IC: Start InitContainer
IC->>IC: Copy mongod.conf + keyfile
IC->>IC: chmod 400 keyfile
IC->>IC: Prepare /data/db
IC-->>K8s: Done (exit 0)
K8s->>MDB: Start mongodb container
MDB->>MDB: Launch mongod --config=/etc/mongodb/mongod.conf
MDB->>MDB: Execute /docker-entrypoint-initdb.d/init.js
Note over MDB: Creates users & databases
K8s->>RM: Start replica-manager sidecar
RM->>RM: Check hostname == mongodb-od-0
RM->>MDB: Ping (wait for availability)
RM->>MDB: rs.status() — check RS state
RM->>MDB: rs.initiate({_id:'rs0', members:[...]})
RM->>MDB: Wait for PRIMARY election
RM-->>RM: sleep infinity (stay alive)
Note
ghcr.io/abcdesktopio/mongo:safe8.0
Custom image based on MongoDB 8.0, hosted on GitHub Container Registry. The safe tag indicates a hardened image.
The manifest uses a headless Service (implicit for a StatefulSet with serviceName: mongodb), making each pod individually addressable via DNS:
mongodb-od-0.mongodb.abcdesktop.svc.cluster.local:27017
pyos connects using the simplified URL defined in the secret:
mongodb://pyos:Az4MeYWUjZDg4Zjhk@mongodb
MongoDB Startup Sequence
Security and Authentication
Security model summary:
- Root: used only during initialization (
init.js,init-replica.sh). Credentials are read from files (via*_FILEenv vars), never passed as plaintext environment variables to the main container. - pyos: application user with
readWriterole on all business databases. - Keyfile: separate Kubernetes secret (
abcdesktop-mongod-keyfile), mounted read-only withchmod 400. Required for intra-ReplicaSet communication.
Databases and Users
At initialization, init.js creates the following structure:
| Database | Likely role in abcdesktop |
|---|---|
image |
Catalogue of available application images |
fail2ban |
IP blocking after failed authentication attempts |
loginHistory |
User login history |
applications |
Published application metadata |
profiles |
User profiles and preferences |
desktop |
Active desktop session states |
Connection Flow from pyos
sequenceDiagram
participant PyOS as pyos-od
participant SVC as Service mongodb<br/>(ClusterIP)
participant MDB0 as mongodb-od-0<br/>(PRIMARY)
PyOS->>SVC: Connect via MONGODB_URL\nmongodb://pyos:...@mongodb
SVC->>MDB0: Forward port 27017
MDB0->>MDB0: Authenticate pyos on each DB
MDB0-->>PyOS: Connection established (readWrite)
PyOS->>MDB0: Read/write on image, profiles, desktop...
The connection URL is injected into pyos via the secret-mongodb secret, key MONGODB_URL.
Volumes and Data Persistence
Warning
⚠️ Critical point: the data volume (mounting /data/db) is an emptyDir. This means MongoDB data is not persisted across pod restarts. In production, this volume must be replaced with a PersistentVolumeClaim (PVC) backed by an appropriate StorageClass.
Allocated Resources
| Resource | Request | Limit |
|---|---|---|
| CPU | 100m | 500m |
| Memory | 128Mi | 512Mi |
| Resource | Request | Limit |
|---|---|---|
| CPU | 100m | 500m |
| Memory | 128Mi | 512Mi |
Observations and Recommendations
- Non-persistent data:
/data/dbis anemptyDir. Any pod loss causes a total loss of all MongoDB data. Replace with a PVC backed by a suitable StorageClass. - Plaintext passwords in the manifest: credentials are defined in
stringData. Use Sealed Secrets, Vault, or the External Secrets Operator in production.
- Single replica:
replicas: 1with a single-member ReplicaSet provides no high availability. Scale to 3 members for production environments. imagePullPolicy: Always: forces an image pull on every pod start, which can slow restarts and requires permanent network access toghcr.io.
- Credentials are read from files (via
*_FILEenv vars), never passed as plaintext env vars to the main container. init-replica.shis idempotent: can be safely re-executed.init.jsis idempotent: handles duplicate user errors gracefully.- Clear role separation: root for initialization,
pyosfor the application layer. - Keyfile used to secure intra-ReplicaSet communication.
- ReadinessProbe configured on port 27017.