From d0c876dd31450dc28b23a7eaafaf0d4a8c8b0382 Mon Sep 17 00:00:00 2001 From: Aiirondev Date: Sun, 12 Jul 2026 11:00:43 +0200 Subject: [PATCH] Slight changes to the encryption of the database to secure it from malisios actors --- .gitignore | 1 + Website/docker-compose.yml | 12 +++-- Website/launch.sh | 108 +++++++++++++++++++++++++++++++++++-- Website/mongo-init.js | 16 ++++++ Website/stop.sh | 6 +++ 5 files changed, 136 insertions(+), 7 deletions(-) create mode 100644 Website/mongo-init.js diff --git a/.gitignore b/.gitignore index aa6149c..6b615e8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +Website/.mongo-secrets.env .venv __pycache__ Inventarsystem_Lizenz_Verwaltung diff --git a/Website/docker-compose.yml b/Website/docker-compose.yml index d1f2130..21fc2a7 100644 --- a/Website/docker-compose.yml +++ b/Website/docker-compose.yml @@ -8,16 +8,20 @@ services: - "0.25" - --setParameter - diagnosticDataCollectionEnabled=false + - --auth mem_limit: 384m mem_reservation: 192m environment: MONGO_INITDB_DATABASE: Invario_Website - ports: - - "127.0.0.1:${MONGO_PUBLISHED_PORT:-27018}:27017" + MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME:-website_root} + MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD:?set MONGO_INITDB_ROOT_PASSWORD} + MONGO_APP_USER: ${MONGO_APP_USER:-website_app} + MONGO_APP_PASSWORD: ${MONGO_APP_PASSWORD:?set MONGO_APP_PASSWORD} volumes: - mongo_data:/data/db + - ./mongo-init.js:/docker-entrypoint-initdb.d/mongo-init.js:ro healthcheck: - test: ["CMD", "mongosh", "--quiet", "--eval", "db.adminCommand('ping').ok"] + test: ["CMD", "mongosh", "--quiet", "--username", "${MONGO_INITDB_ROOT_USERNAME:-website_root}", "--password", "${MONGO_INITDB_ROOT_PASSWORD:?set MONGO_INITDB_ROOT_PASSWORD}", "--authenticationDatabase", "admin", "--eval", "db.adminCommand('ping').ok"] interval: 10s timeout: 5s retries: 8 @@ -31,7 +35,7 @@ services: mongodb: condition: service_healthy environment: - MONGO_URI: mongodb://mongodb:27017 + MONGO_URI: mongodb://${MONGO_APP_USER:-website_app}:${MONGO_APP_PASSWORD:?set MONGO_APP_PASSWORD}@mongodb:27017/${MONGO_DB_NAME:-Invario_Website}?authSource=${MONGO_DB_NAME:-Invario_Website} MONGO_DB_NAME: Invario_Website MONGO_MAX_POOL_SIZE: ${MONGO_MAX_POOL_SIZE:-12} MONGO_MIN_POOL_SIZE: ${MONGO_MIN_POOL_SIZE:-0} diff --git a/Website/launch.sh b/Website/launch.sh index cf9d331..d21d966 100755 --- a/Website/launch.sh +++ b/Website/launch.sh @@ -5,6 +5,34 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" DOCKER_CMD=() +SECRETS_FILE="$SCRIPT_DIR/.mongo-secrets.env" +MONGO_VOLUME_NAME="$(basename "$SCRIPT_DIR" | tr '[:upper:]' '[:lower:]')_mongo_data" + +ensure_mongo_secrets() { + if [ -f "$SECRETS_FILE" ]; then + # shellcheck disable=SC1090 + source "$SECRETS_FILE" + fi + + if [ -z "${MONGO_INITDB_ROOT_PASSWORD:-}" ]; then + MONGO_INITDB_ROOT_PASSWORD="$(openssl rand -hex 24)" + fi + + if [ -z "${MONGO_APP_PASSWORD:-}" ]; then + MONGO_APP_PASSWORD="$(openssl rand -hex 24)" + fi + + cat > "$SECRETS_FILE" </dev/null 2>&1; then @@ -43,6 +71,8 @@ echo " INSTANCE_TLS_MODE=$INSTANCE_TLS_MODE" echo " INSTANCE_PARENT_DOMAIN=$INSTANCE_PARENT_DOMAIN" echo " DEV_HOSTS_REFRESH_INTERVAL=$DEV_HOSTS_REFRESH_INTERVAL" +ensure_mongo_secrets + # Ensure required runtime files exist before building if [ ! -f "$SCRIPT_DIR/gunicorn.conf.py" ]; then echo "[FEHLER] gunicorn.conf.py fehlt in $SCRIPT_DIR. Bitte prüfen." >&2 @@ -51,8 +81,80 @@ fi resolve_docker_cmd -"${DOCKER_CMD[@]}" compose build website -"${DOCKER_CMD[@]}" compose up -d +"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" build website + +mongo_bootstrap_needed() { + "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" exec -T mongodb mongosh --quiet --username "$MONGO_INITDB_ROOT_USERNAME" --password "$MONGO_INITDB_ROOT_PASSWORD" --authenticationDatabase admin --eval 'db.adminCommand({ ping: 1 }).ok' >/dev/null 2>&1 +} + +bootstrap_mongo_users() { + echo "MongoDB bootstrap erforderlich; starte temporären Recovery-Modus ohne Auth..." + "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" stop mongodb || true + "${DOCKER_CMD[@]}" run -d --rm \ + --name invario-mongo-recovery \ + --network host \ + -v "${MONGO_VOLUME_NAME}:/data/db" \ + mongo:7 \ + mongod --dbpath /data/db --bind_ip 127.0.0.1 --port 27017 --noauth >/dev/null + + trap '"${DOCKER_CMD[@]}" stop invario-mongo-recovery >/dev/null 2>&1 || true' EXIT + + for _ in 1 2 3 4 5 6 7 8 9 10; do + if "${DOCKER_CMD[@]}" run --rm --network host mongo:7 mongosh --quiet mongodb://127.0.0.1:27017 --eval 'db.adminCommand({ ping: 1 }).ok' >/dev/null 2>&1; then + break + fi + sleep 1 + done + + "${DOCKER_CMD[@]}" run --rm --network host --env-file "$SECRETS_FILE" mongo:7 mongosh --quiet mongodb://127.0.0.1:27017 --eval ' +const appDatabase = process.env.MONGO_DB_NAME || "Invario_Website"; +const rootUser = process.env.MONGO_INITDB_ROOT_USERNAME || "website_root"; +const rootPassword = process.env.MONGO_INITDB_ROOT_PASSWORD; +const appUser = process.env.MONGO_APP_USER || "website_app"; +const appPassword = process.env.MONGO_APP_PASSWORD; + +if (!rootPassword || !appPassword) { + throw new Error("Missing Mongo bootstrap credentials"); +} + +const adminDb = db.getSiblingDB("admin"); +try { + adminDb.createUser({ + user: rootUser, + pwd: rootPassword, + roles: [{ role: "root", db: "admin" }], + }); +} catch (error) { + if (!String(error).includes("already exists")) { + throw error; + } +} + +const appDb = db.getSiblingDB(appDatabase); +try { + appDb.createUser({ + user: appUser, + pwd: appPassword, + roles: [{ role: "readWrite", db: appDatabase }], + }); +} catch (error) { + if (!String(error).includes("already exists")) { + throw error; + } +} +' + + "${DOCKER_CMD[@]}" stop invario-mongo-recovery >/dev/null + trap - EXIT + echo "MongoDB bootstrap abgeschlossen. Starte gesicherten Dienst erneut..." +} + +if ! mongo_bootstrap_needed; then + bootstrap_mongo_users +fi + +"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" up -d mongodb +"${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" up -d --no-deps website # Wait for website to become healthy (simple HTTP check) check_url="http://localhost:4999" @@ -73,7 +175,7 @@ done if [ $elapsed -ge $timeout_seconds ]; then echo "[FEHLER] Website nicht erreichbar nach ${timeout_seconds}s. Sammle Diagnosedaten..." echo "--- docker compose ps ---" - "${DOCKER_CMD[@]}" compose ps || true + "${DOCKER_CMD[@]}" compose --env-file "$SECRETS_FILE" ps || true echo "--- docker logs website (tail 200) ---" "${DOCKER_CMD[@]}" logs --tail 200 website-website-1 || true echo "Bitte prüfe Container-Logs und nginx-Konfiguration." diff --git a/Website/mongo-init.js b/Website/mongo-init.js new file mode 100644 index 0000000..776e12d --- /dev/null +++ b/Website/mongo-init.js @@ -0,0 +1,16 @@ +const adminUser = process.env.MONGO_INITDB_ROOT_USERNAME; +const adminPassword = process.env.MONGO_INITDB_ROOT_PASSWORD; +const appUser = process.env.MONGO_APP_USER; +const appPassword = process.env.MONGO_APP_PASSWORD; +const appDatabase = process.env.MONGO_DB_NAME || "Invario_Website"; + +if (!adminUser || !adminPassword || !appUser || !appPassword) { + throw new Error("Missing MongoDB bootstrap credentials"); +} + +db = db.getSiblingDB(appDatabase); +db.createUser({ + user: appUser, + pwd: appPassword, + roles: [{ role: "readWrite", db: appDatabase }], +}); diff --git a/Website/stop.sh b/Website/stop.sh index a109e4b..bf85a64 100755 --- a/Website/stop.sh +++ b/Website/stop.sh @@ -5,6 +5,12 @@ SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" cd "$SCRIPT_DIR" DOCKER_CMD=() +SECRETS_FILE="$SCRIPT_DIR/.mongo-secrets.env" + +if [ -f "$SECRETS_FILE" ]; then + # shellcheck disable=SC1090 + source "$SECRETS_FILE" +fi resolve_docker_cmd() { if docker info >/dev/null 2>&1; then