feat(scripts): add upload to S3 scripts
Some checks failed
Deployment CI/CD / validate (push) Has been cancelled
Deployment CI/CD / deploy (push) Has been cancelled

This commit is contained in:
2026-06-05 16:32:22 +03:30
parent 52ef680771
commit 09952319e8
4 changed files with 335 additions and 3 deletions

128
scripts/backup-upload-s3.sh Normal file
View File

@@ -0,0 +1,128 @@
#!/usr/bin/env bash
set -Eeuo pipefail
usage() {
cat <<'EOF'
Usage:
backup-upload-s3.sh
Environment:
DEPLOY_ROOT Deployment directory. Defaults to ~/qlockify-deployment.
S3_BACKUP_BUCKET S3 bucket name.
S3_BACKUP_PREFIX S3 object prefix. Defaults to qlockify.
S3_BACKUP_REGION S3 region. Defaults to us-east-1.
S3_BACKUP_ENDPOINT_URL Optional S3-compatible endpoint URL.
S3_BACKUP_ACCESS_KEY_ID S3 access key.
S3_BACKUP_SECRET_ACCESS_KEY S3 secret key.
BACKUP_ENCRYPTION_PASSPHRASE Passphrase used to encrypt backup archives.
BACKUP_LOCAL_KEEP_LATEST Set to 1 to keep latest encrypted archive locally.
EOF
}
log() {
printf '[backup-s3] %s\n' "$*"
}
fail() {
printf '[backup-s3] %s\n' "$*" >&2
exit 1
}
require_var() {
local name="$1"
[[ -n "${!name:-}" ]] || fail "$name is required"
}
load_env() {
local env_path="$1"
[[ -f "$env_path" ]] || fail "Deployment env file not found: $env_path"
set -a
# shellcheck disable=SC1090
. "$env_path"
set +a
}
aws_s3() {
if [[ -n "${S3_BACKUP_ENDPOINT_URL:-}" ]]; then
aws --endpoint-url "$S3_BACKUP_ENDPOINT_URL" s3 "$@"
else
aws s3 "$@"
fi
}
normalize_prefix() {
local value="${1:-qlockify}"
value="${value#/}"
value="${value%/}"
printf '%s' "$value"
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
usage
exit 0
fi
command -v aws >/dev/null 2>&1 || fail "aws CLI is required"
command -v openssl >/dev/null 2>&1 || fail "openssl is required"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
DEPLOY_ROOT="${DEPLOY_ROOT:-$(cd "$SCRIPT_DIR/.." && pwd)}"
DEPLOY_ENV="$DEPLOY_ROOT/.env"
BACKUP_SCRIPT="$SCRIPT_DIR/backup.sh"
[[ -x "$BACKUP_SCRIPT" ]] || fail "Backup script is not executable: $BACKUP_SCRIPT"
load_env "$DEPLOY_ENV"
S3_BACKUP_PREFIX="$(normalize_prefix "${S3_BACKUP_PREFIX:-qlockify}")"
S3_BACKUP_REGION="${S3_BACKUP_REGION:-us-east-1}"
require_var S3_BACKUP_BUCKET
require_var S3_BACKUP_ACCESS_KEY_ID
require_var S3_BACKUP_SECRET_ACCESS_KEY
require_var BACKUP_ENCRYPTION_PASSPHRASE
export AWS_ACCESS_KEY_ID="$S3_BACKUP_ACCESS_KEY_ID"
export AWS_SECRET_ACCESS_KEY="$S3_BACKUP_SECRET_ACCESS_KEY"
export AWS_DEFAULT_REGION="$S3_BACKUP_REGION"
export AWS_EC2_METADATA_DISABLED=true
WORK_DIR="$(mktemp -d)"
trap 'rm -rf "$WORK_DIR"' EXIT
PLAIN_DIR="$WORK_DIR/plain"
mkdir -p "$PLAIN_DIR"
log "Creating local backup archive"
DEPLOY_ROOT="$DEPLOY_ROOT" "$BACKUP_SCRIPT" "$PLAIN_DIR"
shopt -s nullglob
archives=("$PLAIN_DIR"/*.tar.gz)
shopt -u nullglob
[[ "${#archives[@]}" -eq 1 ]] || fail "Expected exactly one backup archive, found ${#archives[@]}"
ARCHIVE_PATH="${archives[0]}"
ARCHIVE_NAME="$(basename "$ARCHIVE_PATH")"
ENCRYPTED_NAME="$ARCHIVE_NAME.enc"
ENCRYPTED_PATH="$WORK_DIR/$ENCRYPTED_NAME"
S3_URI="s3://$S3_BACKUP_BUCKET/$S3_BACKUP_PREFIX/$ENCRYPTED_NAME"
log "Encrypting backup archive"
openssl enc -aes-256-cbc -salt -pbkdf2 -iter 200000 \
-in "$ARCHIVE_PATH" \
-out "$ENCRYPTED_PATH" \
-pass env:BACKUP_ENCRYPTION_PASSPHRASE
rm -f "$ARCHIVE_PATH"
log "Uploading encrypted backup to $S3_URI"
aws_s3 cp "$ENCRYPTED_PATH" "$S3_URI" --only-show-errors
if [[ "${BACKUP_LOCAL_KEEP_LATEST:-1}" == "1" ]]; then
LATEST_DIR="$DEPLOY_ROOT/backups/latest"
mkdir -p "$LATEST_DIR"
find "$LATEST_DIR" -type f -name '*.tar.gz.enc' -delete
cp "$ENCRYPTED_PATH" "$LATEST_DIR/$ENCRYPTED_NAME"
log "Kept latest encrypted backup locally: $LATEST_DIR/$ENCRYPTED_NAME"
fi
log "S3 backup upload completed: $S3_URI"