Secrets & Encryption¶
This page covers how the database password (and other secrets) can be encrypted at rest for native/PM2 installs — the mechanism a security-conscious on-prem customer will want to know about before going to production.
Docker Compose
This mechanism applies to native/PM2 installs. In the Docker deployment, secrets are passed as container environment variables via .env and are not written to a file inside any container; standard Docker secrets-management practices (host-level .env permissions, or swapping in Docker secrets/a vault if your platform requires it) apply instead.
What's encrypted, and where¶
By default, a fresh native install keeps DB_PASSWORD (and DB_ADMIN_PASSWORD, if set) as plaintext in backend/.env, so the app works out of the box. Running one script converts it to ciphertext at rest:
cd backend && npm run build && cd .. # only if backend/dist isn't already built
sudo ./scripts/setup-env-encryption.sh
What this does:
- Generates a 256-bit master key at
/etc/itsm/env-master.key(or a path you pass as an argument), owned by root,chmod 400— outside the application directory and outside.envitself. If a key already exists there, it's left untouched (regenerating it would make existing encrypted values permanently undecryptable). - Encrypts
DB_PASSWORD(andDB_ADMIN_PASSWORD) with AES-256-GCM, verifies the encrypt→decrypt round-trip in memory, and only then writesDB_PASSWORD_ENC=<ciphertext>andENV_MASTER_KEY_FILE=<key path>intobackend/.env, removing the plaintext line. - Drops any leftover literal
DATABASE_URL=line from.envif it's exactly reproducible fromDB_USER/DB_PASSWORD/DB_NAME(so the password doesn't also sit unencrypted inside a connection string). - Scrubs the same plaintext
DB_PASSWORD/DB_ADMIN_PASSWORDout of the root.envtoo —install-onprem.shcopies root.envintobackend/.envon every run, so a second plaintext copy there would otherwise persist even after step 2. - Runs a final live check: loads the rewritten
.envexactly as the compiled backend would at startup, and confirms it resolves to the same connection details as before. If anything doesn't match, it automatically restores the pre-scriptbackend/.envfrom a timestamped backup — no partial state is left behind.
Safe to re-run: if DB_PASSWORD is already encrypted, the script does nothing.
How decryption works at runtime¶
loadEncryptedEnvSecrets() in backend/src/common/config/env-secrets.ts runs as the very first statement in the backend's entrypoints (main.ts, data-source.ts). It:
- Loads
backend/.env. - Finds every
*_ENCvariable (e.g.DB_PASSWORD_ENC), decrypts it using the key atENV_MASTER_KEY_FILE, and sets the plainDB_PASSWORDinprocess.envfor the rest of the app to use as normal. - If
DATABASE_URLstill isn't set after that, builds it fromDB_USER/DB_PASSWORD/DB_NAME/DB_HOST/DB_PORT.
The master key is derived from the raw file contents via SHA-256 — it's deliberately kept out of .env entirely (not reused from JWT_SECRET or APP_ENCRYPTION_KEY, which already live in the file this mechanism protects).
If ENV_MASTER_KEY_FILE is unset and no *_ENC variable is present, this is a complete no-op — a plaintext DB_PASSWORD install behaves exactly as before.
Cipher details¶
- Algorithm: AES-256-GCM
- Format:
iv:authTag:ciphertext, all hex — the same format used elsewhere in the app'sCryptoService, so a.envfile reads consistently - Key derivation: SHA-256 of the master key file's contents
Manually encrypting/decrypting a value¶
Useful for support, verification, or rotating a value by hand. The CLI must be run against the compiled dist/ output, never via ts-node — production installs run npm ci --omit=dev, which strips ts-node/typescript entirely, so anything invoking npx ts-node for this will work in a dev checkout and silently fail on the real server.
cd backend
node dist/scripts/encrypt-env-value.js encrypt /etc/itsm/env-master.key 'MyNewPassword!'
node dist/scripts/encrypt-env-value.js decrypt /etc/itsm/env-master.key '<iv>:<authTag>:<ciphertext>'
Backing up the master key¶
The master key is not included in a normal .tar.gz release package or backup archive by default location — it lives outside the app directory on purpose. If you lose it, every *_ENC value in backend/.env becomes permanently unrecoverable and the backend will refuse to start.
scripts/backup-onprem.sh and scripts/restore-onprem.sh carry ENV_MASTER_KEY_FILE and backend/.env together as part of the standard backup bundle — see Backups & Disaster Recovery. If you back up manually, always back up the key file alongside backend/.env.
Next steps¶
- Changing the Database Password — the procedure differs slightly once encryption is active