Die Anleitung sagt "./scripts/update.sh" - auf Linux kam dort "Permission denied". Die drei .sh-Dateien lagen mit Modus 644 statt 755 im Index. Ursache ist der Entwicklungsrechner: Unter Windows steht core.filemode=false, git nimmt ein fehlendes Ausfuehrungsrecht dort gar nicht wahr. Gemeldet hat es der Betrieb, nicht der Bau. Wer von 1.1.0 oder aelter kommt, braucht einmalig "bash scripts/update.sh" - das alte Skript ist ja noch das nicht ausfuehrbare. Steht jetzt in README und Installationsanleitung. Zusaetzlich setzt update.sh nach dem Umschalten selbst ein chmod +x auf scripts/*.sh. Das faengt den Fall ab, dass jemand Dateien von Hand kopiert und das Recht dabei verliert - genau so kam man bisher an dieses Skript, bevor es in der laufenden Fassung existierte. Neu: tests/skripte.test.ts prueft nicht Verhalten, sondern Verpackung - Ausfuehrungsrecht im Index, Shebang, scripts/ im Docker-Abbild, die Sicherungsskripte in der Compose-Datei. Es ist der zweite Fehler dieser Art (vorher fehlte scripts/ ganz im Abbild, 1.0.1); beide Male war der Code richtig und kein Test sah hin, wie die Dateien beim Server ankommen. Gegenprobe gemacht: mit zurueckgesetztem Recht schlaegt er fehl und nennt die Datei. Nebenbei aufgefallen: scripts/version.mjs datierte in UTC. Diese Fassung waere um 00:08 deutscher Zeit auf den Vortag datiert worden. Rechnet jetzt in Europe/Berlin.
86 lines
3.0 KiB
Bash
Executable File
86 lines
3.0 KiB
Bash
Executable File
#!/bin/sh
|
|
# =============================================================================
|
|
# Taegliche Sicherung der Datenbank
|
|
# =============================================================================
|
|
#
|
|
# Laeuft im Behaelter "sicherung" per cron um 03:15 Uhr. Von Hand:
|
|
#
|
|
# docker compose exec sicherung /bin/sh /sicherung.sh
|
|
#
|
|
# Was passiert:
|
|
# 1. pg_dump im eigenen Format (-Fc), damit einzelne Tabellen
|
|
# wiederherstellbar bleiben.
|
|
# 2. Verschluesselung mit AES-256 und PBKDF2 aus SICHERUNG_PASSWORT.
|
|
# Das Backup liegt oft auf fremdem Speicher - unverschluesselt waere
|
|
# es ein Datenleck mit Ansage.
|
|
# 3. SHA-256-Pruefsumme daneben.
|
|
# 4. Staende, die aelter sind als SICHERUNG_AUFBEWAHRUNG_TAGE, entfernen.
|
|
# Der jeweils erste Stand eines Monats bleibt stehen.
|
|
#
|
|
# WICHTIG: Dieses Backup enthaelt die verschluesselten Felder, aber NICHT
|
|
# den Schluessel ENC_KEY_V1. Ohne ihn sind Diagnosen, IBANs und Notizen
|
|
# auch aus einer wiederhergestellten Datenbank nicht lesbar. Den Schluessel
|
|
# getrennt sichern - Passwortmanager oder ausgedruckt im Ordner.
|
|
# =============================================================================
|
|
|
|
set -eu
|
|
|
|
ZIEL="${SICHERUNG_ZIEL:-/backups}"
|
|
AUFBEWAHRUNG="${SICHERUNG_AUFBEWAHRUNG_TAGE:-30}"
|
|
ZEITSTEMPEL="$(date +%Y-%m-%d_%H%M)"
|
|
TAG_IM_MONAT="$(date +%d)"
|
|
DATEI="$ZIEL/cockpit_${ZEITSTEMPEL}.dump.enc"
|
|
|
|
if [ -z "${SICHERUNG_PASSWORT:-}" ]; then
|
|
echo "$(date -Iseconds) FEHLER: SICHERUNG_PASSWORT ist nicht gesetzt. Abbruch." >&2
|
|
exit 1
|
|
fi
|
|
|
|
mkdir -p "$ZIEL"
|
|
|
|
echo "$(date -Iseconds) Sicherung beginnt: $DATEI"
|
|
|
|
# pg_dump schreibt direkt in die Verschluesselung - der Klartext landet
|
|
# nie auf der Platte.
|
|
pg_dump --format=custom --compress=6 --no-owner --no-privileges \
|
|
| openssl enc -aes-256-cbc -pbkdf2 -iter 200000 -salt \
|
|
-pass env:SICHERUNG_PASSWORT \
|
|
-out "$DATEI"
|
|
|
|
GROESSE="$(du -h "$DATEI" | cut -f1)"
|
|
sha256sum "$DATEI" > "$DATEI.sha256"
|
|
|
|
# Der jeweils erste Stand eines Monats bekommt eine Markierung und bleibt
|
|
# beim Aufraeumen verschont.
|
|
if [ "$TAG_IM_MONAT" = "01" ]; then
|
|
touch "$DATEI.monatsstand"
|
|
fi
|
|
|
|
echo "$(date -Iseconds) Sicherung fertig ($GROESSE)"
|
|
|
|
# --- Aufraeumen --------------------------------------------------------------
|
|
ENTFERNT=0
|
|
for alt in "$ZIEL"/cockpit_*.dump.enc; do
|
|
[ -e "$alt" ] || continue
|
|
[ -e "$alt.monatsstand" ] && continue
|
|
|
|
if [ -n "$(find "$alt" -mtime "+$AUFBEWAHRUNG" 2>/dev/null)" ]; then
|
|
rm -f "$alt" "$alt.sha256"
|
|
ENTFERNT=$((ENTFERNT + 1))
|
|
fi
|
|
done
|
|
|
|
[ "$ENTFERNT" -gt 0 ] && echo "$(date -Iseconds) $ENTFERNT alte Staende entfernt"
|
|
|
|
# --- Selbstpruefung ----------------------------------------------------------
|
|
# Ein Backup, das sich nicht entschluesseln laesst, ist kein Backup.
|
|
# Deshalb wird sofort geprueft, ob die Datei wieder lesbar ist.
|
|
if openssl enc -d -aes-256-cbc -pbkdf2 -iter 200000 \
|
|
-pass env:SICHERUNG_PASSWORT -in "$DATEI" 2>/dev/null \
|
|
| head -c 5 | grep -q "PGDMP"; then
|
|
echo "$(date -Iseconds) Selbstpruefung bestanden."
|
|
else
|
|
echo "$(date -Iseconds) FEHLER: Die Sicherung laesst sich nicht entschluesseln!" >&2
|
|
exit 1
|
|
fi
|