Files
Cloud-Tour-to-Libo/scripts/backup_mysql_encrypted.sh
T
xuelong 3dd5731751 feat: streamline platform and secure data access
- move the relational data center to MySQL and a standalone workbench\n- add Interface Center API credentials, policies, logs, and DBeaver SSH guidance\n- harden authentication and deployment while retiring unused management surfaces
2026-08-25 02:06:28 -07:00

74 lines
2.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -Eeuo pipefail
umask 077
SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(cd -- "${SCRIPT_DIR}/.." && pwd)"
BACKUP_ROOT="${DATA_BACKUP_ROOT:-${PROJECT_DIR}/backups/mysql}"
PASSPHRASE_FILE="${DATA_BACKUP_PASSPHRASE_FILE:-}"
if [[ -z "${PASSPHRASE_FILE}" || ! -f "${PASSPHRASE_FILE}" || ! -r "${PASSPHRASE_FILE}" ]]; then
echo "DATA_BACKUP_PASSPHRASE_FILE 必须指向可读的独立密钥文件" >&2
exit 2
fi
if [[ "$(wc -c < "${PASSPHRASE_FILE}" | tr -d ' ')" -lt 32 ]]; then
echo "备份加密口令文件内容不能少于 32 个字符" >&2
exit 2
fi
if [[ -z "${BACKUP_ROOT}" || "${BACKUP_ROOT}" == "/" ]]; then
echo "拒绝使用不安全的备份目录" >&2
exit 2
fi
for command_name in docker gzip openssl; do
command -v "${command_name}" >/dev/null 2>&1 || {
echo "缺少命令:${command_name}" >&2
exit 2
}
done
mkdir -p -- "${BACKUP_ROOT}"
timestamp="$(date -u +%Y%m%dT%H%M%SZ)"
archive_name="mysql-all-${timestamp}.sql.gz.enc"
archive_path="${BACKUP_ROOT}/${archive_name}"
temporary_path="${BACKUP_ROOT}/.${archive_name}.tmp"
checksum_path="${archive_path}.sha256"
manifest_path="${archive_path}.json"
cleanup() {
rm -f -- "${temporary_path}"
}
trap cleanup EXIT INT TERM
cd -- "${PROJECT_DIR}"
docker compose exec -T mysql sh -eu -c '
MYSQL_PWD="$MYSQL_ROOT_PASSWORD" mysqldump \
--user=root \
--all-databases \
--single-transaction \
--quick \
--routines \
--events \
--triggers \
--hex-blob \
--set-gtid-purged=OFF
' | gzip -9 | openssl enc -aes-256-cbc -salt -pbkdf2 -iter 200000 \
-pass "file:${PASSPHRASE_FILE}" -out "${temporary_path}"
test -s "${temporary_path}"
mv -- "${temporary_path}" "${archive_path}"
if command -v sha256sum >/dev/null 2>&1; then
checksum="$(sha256sum "${archive_path}" | awk '{print $1}')"
else
checksum="$(shasum -a 256 "${archive_path}" | awk '{print $1}')"
fi
printf '%s %s\n' "${checksum}" "${archive_name}" > "${checksum_path}"
printf '{\n "created_at": "%s",\n "file": "%s",\n "sha256": "%s",\n "encrypted": true,\n "cipher": "AES-256-CBC/PBKDF2",\n "compression": "gzip"\n}\n' \
"${timestamp}" "${archive_name}" "${checksum}" > "${manifest_path}"
chmod 600 "${archive_path}" "${checksum_path}" "${manifest_path}"
echo "加密备份已生成:${archive_path}"
echo "请将 .enc、.sha256 和 .json 同步到独立的异地存储。"