diff --git a/changemaker-control-panel/api/src/services/secret-generator.ts b/changemaker-control-panel/api/src/services/secret-generator.ts index 36e8f908..4433afc0 100644 --- a/changemaker-control-panel/api/src/services/secret-generator.ts +++ b/changemaker-control-panel/api/src/services/secret-generator.ts @@ -58,6 +58,7 @@ export interface InstanceSecrets { jitsiJicofoAuthPassword: string; jitsiJvbAuthPassword: string; rocketchatAdminPassword: string; + mongoRootPassword: string; } export function generateSecrets(adminEmail: string): InstanceSecrets & { adminEmail: string } { @@ -82,5 +83,6 @@ export function generateSecrets(adminEmail: string): InstanceSecrets & { adminEm jitsiJicofoAuthPassword: randomHex(16), jitsiJvbAuthPassword: randomHex(16), rocketchatAdminPassword: randomPassword(16), + mongoRootPassword: randomHex(16), }; } diff --git a/changemaker-control-panel/templates/docker-compose.yml.hbs b/changemaker-control-panel/templates/docker-compose.yml.hbs index 8711bd75..1687f042 100644 --- a/changemaker-control-panel/templates/docker-compose.yml.hbs +++ b/changemaker-control-panel/templates/docker-compose.yml.hbs @@ -510,13 +510,16 @@ services: image: {{registryUrl}}/mongo:6.0 container_name: {{containerPrefix}}-mongodb restart: unless-stopped - command: ["mongod", "--replSet", "rs0", "--bind_ip_all"] + command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--auth", "--keyFile", "/data/replica.key"] + environment: + MONGO_INITDB_ROOT_USERNAME: "${MONGO_ROOT_USER:-rocketchat}" + MONGO_INITDB_ROOT_PASSWORD: "${MONGO_ROOT_PASSWORD}" volumes: - {{containerPrefix}}-mongodb-data:/data/db networks: - {{networkName}} healthcheck: - test: ["CMD", "mongosh", "--quiet", "--eval", "try { rs.status().ok } catch(e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'{{containerPrefix}}-mongodb:27017'}]}).ok }"] + test: ["CMD", "mongosh", "-u", "${MONGO_ROOT_USER:-rocketchat}", "-p", "${MONGO_ROOT_PASSWORD}", "--authenticationDatabase", "admin", "--quiet", "--eval", "try { rs.status().ok } catch(e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'{{containerPrefix}}-mongodb:27017'}]}).ok }"] interval: 10s timeout: 10s retries: 10 @@ -533,8 +536,8 @@ services: condition: service_started environment: ROOT_URL: http://chat.{{domain}} - MONGO_URL: mongodb://{{containerPrefix}}-mongodb:27017/rocketchat?replicaSet=rs0 - MONGO_OPLOG_URL: mongodb://{{containerPrefix}}-mongodb:27017/local?replicaSet=rs0 + MONGO_URL: mongodb://${MONGO_ROOT_USER:-rocketchat}:${MONGO_ROOT_PASSWORD}@{{containerPrefix}}-mongodb:27017/rocketchat?replicaSet=rs0&authSource=admin + MONGO_OPLOG_URL: mongodb://${MONGO_ROOT_USER:-rocketchat}:${MONGO_ROOT_PASSWORD}@{{containerPrefix}}-mongodb:27017/local?replicaSet=rs0&authSource=admin TRANSPORTER: monolith+nats://{{containerPrefix}}-nats:4222 PORT: "3000" ADMIN_USERNAME: rcadmin diff --git a/changemaker-control-panel/templates/env.hbs b/changemaker-control-panel/templates/env.hbs index e463de61..f8996c95 100644 --- a/changemaker-control-panel/templates/env.hbs +++ b/changemaker-control-panel/templates/env.hbs @@ -190,11 +190,15 @@ ENABLE_CHAT=true ROCKETCHAT_URL=http://{{containerPrefix}}-rocketchat:3000 ROCKETCHAT_ADMIN_USER=rcadmin ROCKETCHAT_ADMIN_PASSWORD={{secrets.rocketchatAdminPassword}} +MONGO_ROOT_USER=rocketchat +MONGO_ROOT_PASSWORD={{secrets.mongoRootPassword}} {{else}} ENABLE_CHAT=false ROCKETCHAT_URL= ROCKETCHAT_ADMIN_USER= ROCKETCHAT_ADMIN_PASSWORD= +MONGO_ROOT_USER= +MONGO_ROOT_PASSWORD= {{/if}} # Jitsi Meet (Video Conferencing) diff --git a/config.sh b/config.sh index 73c163e5..f5062aeb 100755 --- a/config.sh +++ b/config.sh @@ -472,6 +472,17 @@ generate_all_secrets() { ((kept++)) fi + # MongoDB (required for Rocket.Chat — runs with --auth) + local mongo_pass + mongo_pass=$(generate_password 24) + if update_env_var_if_empty "MONGO_ROOT_PASSWORD" "$mongo_pass"; then + success "MongoDB root password" + ((generated++)) + else + info "MongoDB root password (kept existing)" + ((kept++)) + fi + # Gancio local gancio_pass gancio_pass=$(generate_password 20) diff --git a/docker-compose.prod.yml b/docker-compose.prod.yml index 66e2a8e5..1a25db61 100644 --- a/docker-compose.prod.yml +++ b/docker-compose.prod.yml @@ -841,8 +841,8 @@ services: condition: service_started environment: - ROOT_URL=http://chat.${DOMAIN:-cmlite.org} - - MONGO_URL=mongodb://mongodb-rocketchat:27017/rocketchat?replicaSet=rs0 - - MONGO_OPLOG_URL=mongodb://mongodb-rocketchat:27017/local?replicaSet=rs0 + - MONGO_URL=mongodb://${MONGO_ROOT_USER:-rocketchat}:${MONGO_ROOT_PASSWORD}@mongodb-rocketchat:27017/rocketchat?replicaSet=rs0&authSource=admin + - MONGO_OPLOG_URL=mongodb://${MONGO_ROOT_USER:-rocketchat}:${MONGO_ROOT_PASSWORD}@mongodb-rocketchat:27017/local?replicaSet=rs0&authSource=admin - TRANSPORTER=monolith+nats://nats-rocketchat:4222 - PORT=3000 - ADMIN_USERNAME=${ROCKETCHAT_ADMIN_USER:-rcadmin} @@ -891,14 +891,17 @@ services: image: ${GITEA_REGISTRY:-gitea.bnkops.com/admin}/mongo:6.0 container_name: mongodb-rocketchat restart: unless-stopped - command: ["mongod", "--replSet", "rs0", "--bind_ip_all"] + command: ["mongod", "--replSet", "rs0", "--bind_ip_all", "--auth", "--keyFile", "/data/replica.key"] + environment: + MONGO_INITDB_ROOT_USERNAME: ${MONGO_ROOT_USER:-rocketchat} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_ROOT_PASSWORD:?MONGO_ROOT_PASSWORD must be set in .env} volumes: - mongodb-rocketchat-data:/data/db logging: *default-logging networks: - changemaker-lite healthcheck: - test: ["CMD", "mongosh", "--quiet", "--eval", "try { rs.status().ok } catch(e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongodb-rocketchat:27017'}]}).ok }"] + test: ["CMD", "mongosh", "-u", "${MONGO_ROOT_USER:-rocketchat}", "-p", "${MONGO_ROOT_PASSWORD}", "--authenticationDatabase", "admin", "--quiet", "--eval", "try { rs.status().ok } catch(e) { rs.initiate({_id:'rs0',members:[{_id:0,host:'mongodb-rocketchat:27017'}]}).ok }"] interval: 10s timeout: 10s retries: 10 diff --git a/mkdocs/docs/docs/getting-started/environment-variables.md b/mkdocs/docs/docs/getting-started/environment-variables.md index d9679d9c..0bebc7ad 100644 --- a/mkdocs/docs/docs/getting-started/environment-variables.md +++ b/mkdocs/docs/docs/getting-started/environment-variables.md @@ -83,7 +83,7 @@ The primary database for both the Express API and the Fastify Media API (shared) | Variable | Default | Description | |----------|---------|-------------| -| `ENCRYPTION_KEY` | — | :material-alert-circle:{ .text-red } AES key for encrypting secrets stored in the database (SMTP passwords, API keys, etc.). Generate with `openssl rand -hex 32`. **Must not** reuse a JWT secret. Required in production (`NODE_ENV=production`). | +| `ENCRYPTION_KEY` | — | :material-alert-circle:{ .text-red } AES key for encrypting secrets stored in the database (SMTP passwords, API keys, etc.). Generate with `openssl rand -hex 32`. **Must not** reuse a JWT secret. **Required in all environments** (no longer falls back to JWT secret in development). | --- @@ -381,6 +381,8 @@ Self-hosted team chat for volunteer coordination. Requires MongoDB (auto-configu | `ROCKETCHAT_ADMIN_PASSWORD` | — | :material-alert-circle:{ .text-red } Rocket.Chat admin password. | | `ROCKETCHAT_URL` | `http://rocketchat-changemaker:3000` | Internal container URL. | | `ROCKETCHAT_EMBED_PORT` | `8891` | Port for iframe embedding in admin. | +| `MONGO_ROOT_USER` | `rocketchat` | MongoDB admin username. | +| `MONGO_ROOT_PASSWORD` | — | :material-alert-circle:{ .text-red } MongoDB admin password. MongoDB runs with `--auth` enabled. | --- @@ -585,8 +587,9 @@ echo "INITIAL_ADMIN_PASSWORD=$(openssl rand -base64 18)" # Vaultwarden echo "VAULTWARDEN_ADMIN_TOKEN=$(openssl rand -hex 32)" -# Rocket.Chat +# Rocket.Chat + MongoDB echo "ROCKETCHAT_ADMIN_PASSWORD=$(openssl rand -hex 16)" +echo "MONGO_ROOT_PASSWORD=$(openssl rand -hex 24)" # Gancio echo "GANCIO_ADMIN_PASSWORD=$(openssl rand -hex 16)" @@ -644,6 +647,7 @@ echo "JITSI_JVB_AUTH_PASSWORD=$(openssl rand -hex 16)" N8N_USER_PASSWORD=... VAULTWARDEN_ADMIN_TOKEN=... ROCKETCHAT_ADMIN_PASSWORD=... + MONGO_ROOT_PASSWORD=... GANCIO_ADMIN_PASSWORD=... JITSI_APP_SECRET=... JITSI_JICOFO_AUTH_PASSWORD=...