#!/usr/bin/env sh # Encrypt before writing to disk; keep the private recipient key off this host. set -eu umask 077 : "${BACKUP_DIRECTORY:?Set a dedicated absolute backup directory}" : "${BACKUP_RECIPIENT_CERT:?Set the public recipient certificate path}" BACKUP_TRANSFER_MODE="${BACKUP_TRANSFER_MODE:-push}" case "$BACKUP_DIRECTORY" in /*) ;; *) echo 'Backup directory must be absolute' >&2; exit 1 ;; esac BACKUP_DIRECTORY=$(realpath -m -- "$BACKUP_DIRECTORY") case "$BACKUP_DIRECTORY" in /|/home|/tmp|/var|/usr|/etc|/opt|/srv|/root|/mnt|/media) echo 'Use a dedicated backup directory' >&2; exit 1 ;; esac case "$BACKUP_TRANSFER_MODE" in push) : "${BACKUP_REMOTE:?Set an off-host scp destination, for example backup@host:/backups/staff/}" case "$BACKUP_REMOTE" in -*|*\ *|*\;*|*\`*|*\$*) echo 'Invalid backup destination' >&2; exit 1 ;; esac case "$BACKUP_REMOTE" in *:/*/) ;; *) echo 'Off-host destination must be host:/absolute/directory/' >&2; exit 1 ;; esac ;; external-pull) ;; *) echo 'BACKUP_TRANSFER_MODE must be push or external-pull' >&2; exit 1 ;; esac test -r "$BACKUP_RECIPIENT_CERT" openssl x509 -in "$BACKUP_RECIPIENT_CERT" -noout -checkend 0 >/dev/null cd "$(dirname "$0")" mkdir -p "$BACKUP_DIRECTORY" stamp=$(date -u '+%Y%m%dT%H%M%SZ') name="krona-staff-$stamp-$$.dump.cms" output="$BACKUP_DIRECTORY/$name" scratch=$(mktemp -d "$BACKUP_DIRECTORY/.backup-XXXXXX") producer='' cleanup() { if [ -n "$producer" ]; then kill "$producer" 2>/dev/null || true; fi rm -f -- "$scratch/dump.pipe" "$scratch/encrypted.partial" rmdir -- "$scratch" } trap cleanup EXIT HUP INT TERM mkfifo "$scratch/dump.pipe" docker compose exec -T postgres sh -eu -c 'exec pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" -Fc' > "$scratch/dump.pipe" & producer=$! openssl cms -encrypt -binary -aes-256-cbc -outform DER -stream \ -in "$scratch/dump.pipe" -out "$scratch/encrypted.partial" "$BACKUP_RECIPIENT_CERT" wait "$producer" producer='' test -s "$scratch/encrypted.partial" mv -- "$scratch/encrypted.partial" "$output" (cd "$BACKUP_DIRECTORY" && sha256sum "$name" > "$name.sha256") if [ "$BACKUP_TRANSFER_MODE" = push ]; then scp -B "$output" "$output.sha256" "$BACKUP_REMOTE" copy_status=completed else copy_status=pending_pull fi printf 'backup=%s\nchecksum=%s\noff_host_copy=%s\n' "$output" "$output.sha256" "$copy_status" # This is an encrypted backup, not evidence of a successful restore drill.