From cd4dd178ed7a97b3581b34ce6de549d48d50b229 Mon Sep 17 00:00:00 2001 From: Micha Date: Wed, 3 Jun 2026 07:57:57 +0200 Subject: [PATCH] fix(restore): isolate authelia runtime config mount --- ops/restore-tests/authelia-compose.test.yml | 4 +-- ops/restore-tests/authelia-plan.md | 13 +++---- ops/restore-tests/authelia-restore-test.sh | 40 ++++++++++++--------- ops/restore-tests/authelia-runbook.md | 2 +- 4 files changed, 33 insertions(+), 26 deletions(-) diff --git a/ops/restore-tests/authelia-compose.test.yml b/ops/restore-tests/authelia-compose.test.yml index 0093203..1c91243 100644 --- a/ops/restore-tests/authelia-compose.test.yml +++ b/ops/restore-tests/authelia-compose.test.yml @@ -30,7 +30,7 @@ services: condition: service_healthy command: - authelia - - --config=/config/configuration.restoretest.yml + - --config=/config/configuration.yml environment: TZ: Europe/Berlin # Wegwerf-Secrets nur fuer den isolierten Smoke. Niemals produktive @@ -47,7 +47,7 @@ services: # SMTP-Versand ausgeloest wird. AUTHELIA__SERVER__ADDRESS: tcp://0.0.0.0:9091 volumes: - - /mnt/user/backups/restore-lab/authelia/config:/config + - /mnt/user/backups/restore-lab/authelia/test-config:/config ports: # nur 127.0.0.1, keine Public-Route, keine Traefik-Labels - "127.0.0.1:19091:9091" diff --git a/ops/restore-tests/authelia-plan.md b/ops/restore-tests/authelia-plan.md index 453117c..9ffcd95 100644 --- a/ops/restore-tests/authelia-plan.md +++ b/ops/restore-tests/authelia-plan.md @@ -23,10 +23,11 @@ Bewusst **nicht** Teil dieses Tests: - Restore-Lab: `/mnt/user/backups/restore-lab/authelia` - Testdatenpfade: - - `/mnt/user/backups/restore-lab/authelia/config` (restaurierte `configuration.yml.original` + erzeugte `configuration.restoretest.yml`) + - `/mnt/user/backups/restore-lab/authelia/config` (restaurierte Originalkonfiguration + `configuration.yml.original`) + - `/mnt/user/backups/restore-lab/authelia/test-config` (Runtime-Mount mit sanitizter `configuration.yml`) - `/mnt/user/backups/restore-lab/authelia/postgres` (Test-Postgres-Datadir) - `/mnt/user/backups/restore-lab/authelia/dumps/latest/postgresql17-authelia.dump` (falls extrahiert) - - `/mnt/user/backups/restore-lab/authelia/config/notifier/notifications.txt` (Filesystem-Notifier-Ausgabe) + - `/mnt/user/backups/restore-lab/authelia/test-config/notifier/notifications.txt` (Filesystem-Notifier-Ausgabe) - Testcontainer: - `restoretest-authelia` (Image-Pin wie Produktion) - `restoretest-authelia-postgres` (postgres:18.4, gleiche Major wie shared Postgres) @@ -37,8 +38,8 @@ Bewusst **nicht** Teil dieses Tests: - produktive Pfade `/mnt/user/appdata/authelia/*` werden **nicht** beschrieben - produktive Secret-Dateien `/mnt/user/appdata/secrets/authelia_*.txt` werden **nicht** gemountet -- produktive shared PostgreSQL 18 wird **nicht** angesprochen (`configuration.restoretest.yml` zwingt `storage` auf Test-Postgres) -- echter SMTP-Versand wird **nicht** ausgeloest (`configuration.restoretest.yml` zwingt `notifier` auf Filesystem) +- produktive shared PostgreSQL 18 wird **nicht** angesprochen (`test-config/configuration.yml` zwingt `storage` auf Test-Postgres) +- echter SMTP-Versand wird **nicht** ausgeloest (`test-config/configuration.yml` zwingt `notifier` auf Filesystem) - produktive Domain `auth.kaleschke.info` wird **nicht** uebernommen - Testcontainer publishen nur auf `127.0.0.1`, keine LAN-/Tailscale-Bindung - Borg-Passphrase wird aus `/mnt/user/appdata/secrets/borg_repo_passphrase.txt` gelesen und nirgendwo geloggt @@ -48,10 +49,10 @@ Bewusst **nicht** Teil dieses Tests: 1. Restore-Lab-Pfade leer anlegen 2. `local/appdata/authelia/config` aus dem aktuellsten Borg-Archiv extrahieren 3. optional `local/borg-dumps/latest/postgresql17-authelia.dump` extrahieren; wenn nicht im Archiv vorhanden, weiter ohne DB-Restore -4. `configuration.restoretest.yml` aus der restaurierten `configuration.yml` erzeugen: produktive `storage`/`notifier`/`session`/JWT-Bloecke entfernen und Test-Werte anhaengen +4. `test-config/configuration.yml` aus der restaurierten `configuration.yml` erzeugen: produktive `storage`/`notifier`/`session`/JWT-Bloecke entfernen und Test-Werte anhaengen 5. Test-Postgres mit `ops/restore-tests/authelia-compose.test.yml` hochfahren 6. optional Dump per `pg_restore -Fc --clean --if-exists --no-owner --no-privileges` einspielen (mit transientem Retry wie im Immich-/Paperless-Test) -7. `authelia config validate` gegen `configuration.restoretest.yml` laufen lassen +7. `authelia config validate` gegen `test-config/configuration.yml` laufen lassen 8. `restoretest-authelia` starten und HTTP-Health `http://127.0.0.1:19091/api/health` pollen 9. Report unter `/mnt/user/backups/restore-reports/authelia-YYYY-MM-DD.md` schreiben 10. Testcontainer stoppen und Restore-Lab bereinigen (`--keep-data` ueberschreibt) diff --git a/ops/restore-tests/authelia-restore-test.sh b/ops/restore-tests/authelia-restore-test.sh index 36517fc..f749aff 100644 --- a/ops/restore-tests/authelia-restore-test.sh +++ b/ops/restore-tests/authelia-restore-test.sh @@ -31,6 +31,8 @@ for arg in "$@"; do done RESTORE_ROOT="/mnt/user/backups/restore-lab/authelia" +RESTORED_CONFIG_DIR="$RESTORE_ROOT/config" +TEST_CONFIG_DIR="$RESTORE_ROOT/test-config" REPORT_ROOT="/mnt/user/backups/restore-reports" EXTRACT_DIR="$BORG_RESTORE_HOST_ROOT/authelia-extract" COMPOSE_FILE="$SCRIPT_DIR/authelia-compose.test.yml" @@ -49,13 +51,13 @@ Planned isolation: - Test-Postgres: postgres:18.4 mit Wegwerf-Credentials - Test-Authelia: authelia/authelia:4.39.20 (Image-Pin wie Produktion) - Wegwerf-Secrets ausschliesslich im Test-Compose -- configuration.restoretest.yml wird im Restore-Lab erzeugt: +- test-config/configuration.yml wird im Restore-Lab erzeugt: * storage -> Test-Postgres (kein produktives Postgres erreicht) * notifier -> Filesystem (KEIN SMTP-Versand) * session -> lokaler Smoke ohne produktive Session-Secrets - Test endpoint: 127.0.0.1:19091/api/health (no Traefik, no public domain) Smoke-Test: -- authelia config validate gegen configuration.restoretest.yml +- authelia config validate gegen test-config/configuration.yml - HTTP 200 von /api/health EOF exit 0 @@ -82,7 +84,7 @@ cleanup() { trap cleanup EXIT rm -rf "$EXTRACT_DIR" "$RESTORE_ROOT" -mkdir -p "$RESTORE_ROOT/config" "$RESTORE_ROOT/postgres" "$RESTORE_ROOT/dumps/latest" "$RESTORE_ROOT/notifier" +mkdir -p "$RESTORED_CONFIG_DIR" "$TEST_CONFIG_DIR" "$RESTORE_ROOT/postgres" "$RESTORE_ROOT/dumps/latest" archive="$(latest_archive_name)" repo="$(borg_repo_url)" @@ -98,7 +100,7 @@ if [ ! -d "$EXTRACT_DIR/local/appdata/authelia/config" ]; then echo "Authelia config path missing in Borg archive" >&2 exit 1 fi -cp -a "$EXTRACT_DIR/local/appdata/authelia/config/." "$RESTORE_ROOT/config/" +cp -a "$EXTRACT_DIR/local/appdata/authelia/config/." "$RESTORED_CONFIG_DIR/" # Stufe 2: optionalen Postgres-Dump extrahieren und ggf. einspielen dump_available=0 @@ -114,15 +116,19 @@ fi # Wir entfernen produktive Top-Level-Bloecke, die im Test andere Backends # brauchen, und haengen danach Test-Definitionen an. So verlassen wir uns # nicht darauf, dass ein Overlay alte Map-Keys wie notifier.smtp loescht. -CONFIG_FILE="$RESTORE_ROOT/config/configuration.yml" -TEST_CONFIG_FILE="$RESTORE_ROOT/config/configuration.restoretest.yml" -if [ ! -f "$CONFIG_FILE" ]; then +ORIGINAL_CONFIG_FILE="$RESTORED_CONFIG_DIR/configuration.yml" +TEST_CONFIG_FILE="$TEST_CONFIG_DIR/configuration.yml" +if [ ! -f "$ORIGINAL_CONFIG_FILE" ]; then echo "configuration.yml missing in restored config dir" >&2 exit 1 fi -# Sichere Originalkopie fuer Diff/Diagnose -cp "$CONFIG_FILE" "$CONFIG_FILE.original" +# Kopiere alle Begleitdateien (z. B. users_database.yml) in einen separaten +# Runtime-Mount. Die produktive configuration.yml selbst wird dort durch die +# sanitizte Testkonfiguration ersetzt, damit Authelia keine Default-Config mit +# produktivem notifier.smtp nachladen kann. +cp -a "$RESTORED_CONFIG_DIR/." "$TEST_CONFIG_DIR/" +cp "$ORIGINAL_CONFIG_FILE" "$RESTORED_CONFIG_DIR/configuration.yml.original" # Entferne produktive Blocks, die der Restore-Smoke bewusst ersetzt. awk ' @@ -132,7 +138,7 @@ awk ' skip = (key == "storage" || key == "notifier" || key == "session" || key == "identity_validation" || key == "jwt_secret") } !skip { print } -' "$CONFIG_FILE" > "$TEST_CONFIG_FILE" +' "$ORIGINAL_CONFIG_FILE" > "$TEST_CONFIG_FILE" cat >> "$TEST_CONFIG_FILE" <<'YAML' @@ -167,8 +173,8 @@ identity_validation: jwt_algorithm: HS256 YAML -mkdir -p "$RESTORE_ROOT/config/notifier" -chmod -R a+rwX "$RESTORE_ROOT/config/notifier" +mkdir -p "$TEST_CONFIG_DIR/notifier" +chmod -R a+rwX "$TEST_CONFIG_DIR/notifier" # Stufe 4: Test-Postgres hochfahren docker compose -f "$COMPOSE_FILE" up -d restoretest-authelia-postgres >/dev/null @@ -209,17 +215,17 @@ if ! docker run --rm \ -e AUTHELIA_STORAGE_ENCRYPTION_KEY=restoretest-authelia-storage-enc-key-placeholder-32 \ -e AUTHELIA_STORAGE_POSTGRES_PASSWORD=restoretest-authelia-db \ -e AUTHELIA_NOTIFIER_SMTP_PASSWORD=restoretest-authelia-smtp-placeholder \ - -v "$RESTORE_ROOT/config:/config" \ + -v "$TEST_CONFIG_DIR:/config" \ authelia/authelia:4.39.20@sha256:1b363e9279e742397966333f364e0876ae02bf5c876de73e83af6d48c57ff51b \ - authelia config validate --config /config/configuration.restoretest.yml \ + authelia config validate --config /config/configuration.yml \ >/tmp/authelia-validate.log 2>&1; then validate_status="failed" cat /tmp/authelia-validate.log >&2 exit 1 fi -# Stufe 7: Authelia-Container starten. Das Compose nutzt die sanitizte -# configuration.restoretest.yml mit isolierten Test-Backends. +# Stufe 7: Authelia-Container starten. Das Compose nutzt test-config als +# /config-Mount mit isolierten Test-Backends. docker compose -f "$COMPOSE_FILE" up -d restoretest-authelia >/dev/null http_status="" @@ -256,7 +262,7 @@ write_report "$REPORT_FILE" <