feat(ops): verschlüsselter Backup-Container (age) + TimescaleDB-korrektes Restore (Wave 16 PR-B)#171
Merged
Conversation
…ktes Restore Neuer backup-Service im Stack (backup/: postgres:16-alpine + age + rclone, non-root postgres-User). Verbindet sich übers interne Netz mit db (KEIN Docker-Socket, keine zusätzliche Angriffsfläche) und sichert täglich: pg_dump -Fc → age-Verschlüsselung (streamed) → Retention → optional rclone. Scheduler: schlanker non-root Shell-Loop statt cron-Binary (vermeidet per-arch supercronic-Download = Supply-Chain-Risiko; busybox-crond ist nicht sauber non-root). entrypoint.sh exect Args (One-Off via `make backup`) oder läuft den Tages-Loop (Service-Modus). Restore ist TimescaleDB-korrekt (Recherche-Fund, im alten restore-test fehlend): CREATE EXTENSION → timescaledb_pre_restore() → pg_restore OHNE -j → post_restore. Paralleles -j würde die TSDB-Kataloge korrumpieren. Lokal verifiziert: Hypertable überlebt den Restore. age statt GPG: X25519/ChaCha20-Poly1305, asymmetrisch — Public-Key am Server, Private-Key offsite → kompromittierter Server kann eigene Backups nicht lesen. Alles über make: `make up` rollt den Container aus (Daten/Volumes bleiben), `make backup` (One-Off), `make restore-test` (Key-Pfad aus env/.env.backup). - Makefile: backup-Target, restore-test auf age+pre/post_restore umgebaut, gen-secrets um DB_APP_PASSWORD + age-keygen-Hinweis, secure-env für .env.backup - env/.env.backup.example (AGE_RECIPIENT, BACKUP_*, RCLONE_REMOTE, AGE_IDENTITY) - CI backup-smoke (Required, in ci-ok needs): baut Image, beweist pg_dump→age→decrypt→pre/post_restore→pg_restore gegen seed-Test-DB - Doku-Konsolidierung: deployment-public + production-hardening hatten zwei divergierende Inline-Backup-Skripte → beide verweisen jetzt auf backup/. security.md §9.6 (age- vs FERNET-Key-Rotation), configuration/setup/development/CLAUDE DB-Zugriff via Admin-Rolle (pg_dump braucht Voll-Read); dedizierte pg_read_all_data-Rolle als Least-Privilege-Härtung dokumentiert vertagt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rdown
Zwei Fehler im neuen backup-smoke-Job behoben:
- `up --wait db-test flyway-test` wartete nicht auf den Abschluss des
Migrations-Containers → Seed lief vor den Migrationen ("relation users does
not exist"). Jetzt: db-test mit --wait hoch, dann `run --rm flyway-test`
(blockiert bis migrate fertig).
- `down -v` parst die ganze docker-compose.test.yml inkl. api-test, das
env/.env.api braucht → fehlte. Jetzt alle env-Beispiele kopiert.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
gerfru
added a commit
that referenced
this pull request
Jun 12, 2026
…ktes Restore (Wave 16 PR-B) (#171) * feat(ops): verschlüsselter Backup-Container (age) + TimescaleDB-korrektes Restore Neuer backup-Service im Stack (backup/: postgres:16-alpine + age + rclone, non-root postgres-User). Verbindet sich übers interne Netz mit db (KEIN Docker-Socket, keine zusätzliche Angriffsfläche) und sichert täglich: pg_dump -Fc → age-Verschlüsselung (streamed) → Retention → optional rclone. Scheduler: schlanker non-root Shell-Loop statt cron-Binary (vermeidet per-arch supercronic-Download = Supply-Chain-Risiko; busybox-crond ist nicht sauber non-root). entrypoint.sh exect Args (One-Off via `make backup`) oder läuft den Tages-Loop (Service-Modus). Restore ist TimescaleDB-korrekt (Recherche-Fund, im alten restore-test fehlend): CREATE EXTENSION → timescaledb_pre_restore() → pg_restore OHNE -j → post_restore. Paralleles -j würde die TSDB-Kataloge korrumpieren. Lokal verifiziert: Hypertable überlebt den Restore. age statt GPG: X25519/ChaCha20-Poly1305, asymmetrisch — Public-Key am Server, Private-Key offsite → kompromittierter Server kann eigene Backups nicht lesen. Alles über make: `make up` rollt den Container aus (Daten/Volumes bleiben), `make backup` (One-Off), `make restore-test` (Key-Pfad aus env/.env.backup). - Makefile: backup-Target, restore-test auf age+pre/post_restore umgebaut, gen-secrets um DB_APP_PASSWORD + age-keygen-Hinweis, secure-env für .env.backup - env/.env.backup.example (AGE_RECIPIENT, BACKUP_*, RCLONE_REMOTE, AGE_IDENTITY) - CI backup-smoke (Required, in ci-ok needs): baut Image, beweist pg_dump→age→decrypt→pre/post_restore→pg_restore gegen seed-Test-DB - Doku-Konsolidierung: deployment-public + production-hardening hatten zwei divergierende Inline-Backup-Skripte → beide verweisen jetzt auf backup/. security.md §9.6 (age- vs FERNET-Key-Rotation), configuration/setup/development/CLAUDE DB-Zugriff via Admin-Rolle (pg_dump braucht Voll-Read); dedizierte pg_read_all_data-Rolle als Least-Privilege-Härtung dokumentiert vertagt. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * fix(ci): backup-smoke — Migrationen synchron + alle env-Files für teardown Zwei Fehler im neuen backup-smoke-Job behoben: - `up --wait db-test flyway-test` wartete nicht auf den Abschluss des Migrations-Containers → Seed lief vor den Migrationen ("relation users does not exist"). Jetzt: db-test mit --wait hoch, dann `run --rm flyway-test` (blockiert bis migrate fertig). - `down -v` parst die ganze docker-compose.test.yml inkl. api-test, das env/.env.api braucht → fehlte. Jetzt alle env-Beispiele kopiert. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This was referenced Jun 13, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Was
Wave 16 PR-B — macht das DB-Backup real und self-contained: ein Backup-Container im Stack (
backup/) sichert die DB täglich verschlüsselt. Reine Ops/Security-Härtung, kein App-Code.db— kein Docker-Socket, keine zusätzliche Angriffsfläche. Non-rootpostgres-User.pg_dump -Fc→ age-Verschlüsselung (streamed, kein Klartext auf Platte) → Retention → optionalrclone-Offsite.Recherche-Funde (state-of-the-art verifiziert)
timescaledb_pre_restore()→pg_restoreohne-j→timescaledb_post_restore(). Der alterestore-testmachte nur nacktespg_restore→ für die 6 Hypertables unvollständig. Lokal verifiziert: Hypertable überlebt den Restore.Alles über make
make uprollt den Container aus (Daten/Volumes bleiben — keindown).make backup(One-Off).make restore-test(Key-Pfad ausenv/.env.backup).Tests
backup-smoke(Required, inci-okneeds): baut das Image und beweistpg_dump → age → decrypt → pre/post_restore → pg_restoregegen eine seed-Test-DB.Doku (WS-E)
NEU-3-Konsolidierung:
deployment-public.md+production-hardening.mdhatten zwei divergierende Inline-Backup-Skripte (-Fc+rclone vs.gzip+b2) → beide verweisen jetzt aufbackup/(Single Source).security.md§9.6 (age- vs FERNET-Key-Rotation), plus configuration/setup/development/CLAUDE.Bewusst vertagt
DB-Zugriff via Admin-Rolle (pg_dump braucht Voll-Read); dedizierte
pg_read_all_data-Backup-Rolle (V27) als Least-Privilege-Härtung dokumentiert vertagt.🤖 Generated with Claude Code