#!/bin/bash # ============================================================================ # ROA2WEB - Backup Environment Secrets (Encrypted) # ============================================================================ # This script creates encrypted backups of all .env files containing secrets # Usage: # ./scripts/backup-secrets.sh # Interactive (prompts for password) # BACKUP_PASSWORD="your-pass" ./scripts/backup-secrets.sh # Non-interactive # # Requirements: openssl (usually pre-installed) # Output: secrets-backup/YYYY-MM-DD/*.env.enc set -e # Colors for output GREEN='\033[0;32m' YELLOW='\033[1;33m' RED='\033[0;31m' NC='\033[0m' # No Color echo -e "${GREEN}=== ROA2WEB Secrets Backup Tool ===${NC}" echo "" # Check if openssl is installed if ! command -v openssl &> /dev/null; then echo -e "${RED}Error: openssl is not installed${NC}" echo "Install with: sudo apt-get install openssl" exit 1 fi # Get password if [ -z "$BACKUP_PASSWORD" ]; then echo -e "${YELLOW}Enter encryption password (will be hidden):${NC}" read -s BACKUP_PASSWORD echo "" if [ -z "$BACKUP_PASSWORD" ]; then echo -e "${RED}Error: Password cannot be empty${NC}" exit 1 fi echo -e "${YELLOW}Confirm password:${NC}" read -s BACKUP_PASSWORD_CONFIRM echo "" if [ "$BACKUP_PASSWORD" != "$BACKUP_PASSWORD_CONFIRM" ]; then echo -e "${RED}Error: Passwords do not match${NC}" exit 1 fi fi # Create backup directory with timestamp BACKUP_DATE=$(date +%Y-%m-%d_%H-%M-%S) BACKUP_DIR="secrets-backup/${BACKUP_DATE}" mkdir -p "${BACKUP_DIR}" echo -e "${YELLOW}Backup directory: ${BACKUP_DIR}${NC}" echo "" # List of secret files to backup SECRET_FILES=( "backend/.env" "backend/.env.prod" "backend/modules/telegram/.env" "backend/modules/telegram/.env.prod" ) # List of secret directories to backup (will backup all files inside) SECRET_DIRS=( "secrets" ) # Counter for backed up files BACKED_UP=0 SKIPPED=0 # Backup each file for file in "${SECRET_FILES[@]}"; do if [ -f "$file" ]; then echo -e "Encrypting: ${GREEN}$file${NC}" # Extract filename filename=$(basename "$file") # Determine component for unique naming if [[ "$file" == *"backend"* ]]; then component="backend" else component="telegram-bot" fi output_file="${BACKUP_DIR}/${component}-${filename}.enc" # Encrypt with AES-256-CBC using openssl if echo "$BACKUP_PASSWORD" | openssl enc -aes-256-cbc -salt -pbkdf2 \ -in "$file" -out "$output_file" -pass stdin 2>/dev/null; then echo -e " ✅ Saved to: ${output_file}" BACKED_UP=$((BACKED_UP + 1)) else echo -e " ${RED}❌ Failed to encrypt${NC}" fi else echo -e "Skipping: ${YELLOW}$file${NC} (not found)" SKIPPED=$((SKIPPED + 1)) fi echo "" done # Backup directories for dir in "${SECRET_DIRS[@]}"; do if [ -d "$dir" ]; then echo -e "Encrypting directory: ${GREEN}$dir${NC}" # Create tar archive of the directory dir_name=$(basename "$dir") output_file="${BACKUP_DIR}/${dir_name}.tar.enc" # Create tar and encrypt (pipe tar directly to openssl) if tar -cf - "$dir" 2>/dev/null | \ openssl enc -aes-256-cbc -salt -pbkdf2 \ -out "$output_file" -pass pass:"$BACKUP_PASSWORD" 2>/dev/null; then echo -e " ✅ Saved to: ${output_file}" BACKED_UP=$((BACKED_UP + 1)) # Count files in directory file_count=$(find "$dir" -type f | wc -l) echo -e " 📁 Included ${file_count} file(s) from directory" else echo -e " ${RED}❌ Failed to encrypt directory${NC}" fi else echo -e "Skipping: ${YELLOW}$dir${NC} (not found)" SKIPPED=$((SKIPPED + 1)) fi echo "" done # Create README in backup directory cat > "${BACKUP_DIR}/README.md" </dev/null | wc -l) echo "- ${dir_name}.tar.enc (encrypted tar archive, ${file_count} files)" fi done) ## How to restore: \`\`\`bash # Restore all files automatically: ./scripts/restore-secrets.sh ${BACKUP_DATE} # Or manually decrypt a single file: openssl enc -aes-256-cbc -d -pbkdf2 -in backend-.env.enc -out .env # When prompted, enter the encryption password \`\`\` ## Manual restore to specific location: \`\`\`bash # Backend .env openssl enc -aes-256-cbc -d -pbkdf2 \\ -in backend-.env.enc \\ -out ../../../backend/.env # Backend .env.prod openssl enc -aes-256-cbc -d -pbkdf2 \\ -in backend-.env.prod.enc \\ -out ../../../backend/.env.prod # Telegram Bot .env openssl enc -aes-256-cbc -d -pbkdf2 \\ -in telegram-bot-.env.enc \\ -out ../../../backend/modules/telegram/.env # Telegram Bot .env.prod openssl enc -aes-256-cbc -d -pbkdf2 \\ -in telegram-bot-.env.prod.enc \\ -out ../../../backend/modules/telegram/.env.prod # Decrypt and extract secrets directory openssl enc -aes-256-cbc -d -pbkdf2 -in secrets.tar.enc | \\ tar -xf - -C ../../.. \`\`\` ## Security Notes: - Files encrypted with AES-256-CBC using OpenSSL - Password-based encryption with PBKDF2 key derivation - Keep the encryption password safe in your password manager - Never commit decrypted .env files to git ## Password Storage Recommendation: Store in password manager as: - **Title:** ROA2WEB Secrets Backup Password - **Type:** Secure Note or Password - **Notes:** Encryption password for secrets-backup/${BACKUP_DATE} EOF echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" echo -e "${GREEN}✅ Backup completed successfully${NC}" echo "" echo "📊 Summary:" echo " - Backed up: ${BACKED_UP} files" echo " - Skipped: ${SKIPPED} files" echo " - Location: ${BACKUP_DIR}" echo "" echo "📝 To restore all files:" echo " ./scripts/restore-secrets.sh ${BACKUP_DATE}" echo "" echo "📝 To restore a single file:" echo " cd ${BACKUP_DIR}" echo " openssl enc -aes-256-cbc -d -pbkdf2 -in backend-.env.enc -out .env" echo "" echo -e "${YELLOW}⚠️ IMPORTANT: Save encryption password in password manager!${NC}" echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"