diff --git a/.gitignore b/.gitignore index 5e96d29..a26f7d2 100644 --- a/.gitignore +++ b/.gitignore @@ -465,3 +465,18 @@ TELEGRAM_EMAIL_AUTH_PLAN*.md # Weird pip artifacts =* + +# ============================================================================ +# 🔒 ENCRYPTED SECRETS BACKUP (Optional) +# ============================================================================ +# Encrypted backups created by scripts/backup-secrets.sh +# Option 1: Commit encrypted .gpg files (safe, password-protected) +# Option 2: Ignore all backups (keep only local) + +# Uncomment to ignore all backups (Option 2): +# secrets-backup/ + +# Keep only encrypted files, ignore decrypted ones (Option 1): +secrets-backup/**/*.env +secrets-backup/**/.env.* +!secrets-backup/**/*.gpg diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..cbf5692 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,198 @@ +# ROA2WEB Scripts - Secrets Management + +## Backup & Restore Environment Secrets + +Aceste script-uri ajută la backup-ul securizat (criptat) al fișierelor `.env` și `.env.prod` care conțin credențiale sensibile. + +### 🔐 Backup Secrets + +**Creează backup criptat cu AES256:** + +```bash +./scripts/backup-secrets.sh +``` + +**Ce face:** +- Găsește toate fișierele `.env` și `.env.prod` +- Le criptează cu GPG (AES256) +- Le salvează în `secrets-backup/YYYY-MM-DD_HH-MM-SS/` +- Creează README cu instrucțiuni + +**Rezultat:** +``` +secrets-backup/ +└── 2025-01-15_14-30-00/ + ├── .env.gpg + ├── .env.prod.gpg + └── README.md +``` + +**Notă:** Vei fi rugat să introduci o parolă pentru criptare. **Salvează această parolă în gestionar de parole!** + +### 🔓 Restore Secrets + +**Restaurează din backup criptat:** + +```bash +# Restaurează din ultimul backup +./scripts/restore-secrets.sh + +# Restaurează din backup specific +./scripts/restore-secrets.sh 2025-01-15_14-30-00 +``` + +**Ce face:** +- Decriptează fișierele .gpg din backup +- Le plasează înapoi în locațiile originale +- reports-app/backend/.env +- reports-app/backend/.env.prod +- reports-app/telegram-bot/.env +- reports-app/telegram-bot/.env.prod + +**Notă:** Vei fi rugat să introduci parola de decriptare. + +## 🗂️ Opțiuni de Salvare a Backup-urilor + +### Opțiunea 1: Commit în Git (Recomandat) + +Fișierele `.gpg` sunt criptate și pot fi comise în siguranță: + +```bash +# Creează backup +./scripts/backup-secrets.sh + +# Adaugă în git +git add secrets-backup/ +git commit -m "Add encrypted secrets backup" +git push +``` + +**Avantaje:** +- Sincronizat automat cu remote +- Versioning complet +- Acces de pe orice mașină +- Sigur (criptat cu parolă) + +**Dezavantaje:** +- Trebuie să ții minte parola + +### Opțiunea 2: Backup Local (Doar Local) + +Păstrează backup-urile doar pe mașina locală: + +```bash +# Decomentează în .gitignore: +# secrets-backup/ + +# Copiază backup-urile pe USB/cloud manual +cp -r secrets-backup /mnt/usb/roa2web-secrets-backup +``` + +### Opțiunea 3: Gestionar de Parole + +**Pentru backup manual rapid:** + +```bash +# Copiază conținutul și salvează în Bitwarden/1Password +cat reports-app/backend/.env +cat reports-app/backend/.env.prod +cat reports-app/telegram-bot/.env +cat reports-app/telegram-bot/.env.prod +``` + +## 🔒 Best Practices + +1. **Rulează backup înaintea deployment-ului:** + ```bash + ./scripts/backup-secrets.sh + git add secrets-backup/ + git commit -m "Backup secrets before deployment" + ``` + +2. **Salvează parola de criptare în gestionar de parole:** + - Bitwarden: Secure Note "ROA2WEB GPG Backup Password" + - 1Password: Document "ROA2WEB Secrets Password" + - LastPass: Secure Note + +3. **Testează restore periodic:** + ```bash + # Backup + ./scripts/backup-secrets.sh + + # Șterge temporar + mv reports-app/backend/.env reports-app/backend/.env.backup + + # Restore + ./scripts/restore-secrets.sh + + # Verifică + diff reports-app/backend/.env reports-app/backend/.env.backup + ``` + +4. **Pentru echipă:** + - Partajează parola GPG în gestionar de parole partajat + - Sau folosește chei GPG separate pentru fiecare membru + +## 🚨 Troubleshooting + +### "gpg: decryption failed: Bad session key" +- Parola introdusă este greșită +- Verifică în gestionar de parole + +### "No such file or directory" +- Asigură-te că rulezi script-ul din root-ul proiectului: + ```bash + cd /path/to/roa2web + ./scripts/backup-secrets.sh + ``` + +### "gpg: command not found" +```bash +# Ubuntu/Debian +sudo apt-get install gnupg + +# Windows WSL +sudo apt-get install gnupg +``` + +## 📋 Alternative de Backup + +### 1. Manual GPG (un fișier): +```bash +gpg --symmetric --cipher-algo AES256 reports-app/backend/.env +# Rezultat: .env.gpg +``` + +### 2. Tar + GPG (toate odată): +```bash +tar -czf - reports-app/*/.env* | gpg --symmetric --cipher-algo AES256 > secrets-backup.tar.gz.gpg +``` + +### 3. Ansible Vault: +```bash +ansible-vault encrypt reports-app/backend/.env.prod +``` + +## 📝 Deployment pe Windows Server + +Pentru deployment pe Windows, copiază fișierele `.env.prod`: + +```bash +# Linux/WSL -> Windows Server + +# 1. Creează backup local +./scripts/backup-secrets.sh + +# 2. Copiază backup-ul pe server Windows +scp -r secrets-backup/latest/ administrator@server-ip:C:/temp/ + +# 3. Pe server Windows, decriptează: +gpg --decrypt .env.prod.gpg > C:\inetpub\wwwroot\roa2web\backend\.env.prod +gpg --decrypt .env.prod.gpg > C:\inetpub\wwwroot\roa2web\telegram-bot\.env.prod +``` + +## 🔗 Vezi și + +- `.gitignore` - Pattern-uri pentru .env files +- `DEPLOYMENT_GUIDE.md` - Deployment production +- `deployment/windows/docs/WINDOWS_DEPLOYMENT.md` - Windows deployment diff --git a/scripts/backup-secrets.sh b/scripts/backup-secrets.sh new file mode 100644 index 0000000..2b4f37a --- /dev/null +++ b/scripts/backup-secrets.sh @@ -0,0 +1,193 @@ +#!/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=( + "reports-app/backend/.env" + "reports-app/backend/.env.prod" + "reports-app/telegram-bot/.env" + "reports-app/telegram-bot/.env.prod" +) + +# 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 + +# Create README in backup directory +cat > "${BACKUP_DIR}/README.md" < /dev/null; then + echo -e "${RED}Error: openssl is not installed${NC}" + echo "Install with: sudo apt-get install openssl" + exit 1 +fi + +# Check if secrets-backup directory exists +if [ ! -d "secrets-backup" ]; then + echo -e "${RED}Error: No backups found${NC}" + echo "Run ./scripts/backup-secrets.sh first" + exit 1 +fi + +# Determine which backup to use +if [ -z "$1" ]; then + # Use latest backup + BACKUP_DATE=$(ls -t secrets-backup | head -1) + echo -e "${YELLOW}Using latest backup: ${BACKUP_DATE}${NC}" +else + BACKUP_DATE="$1" + echo -e "${YELLOW}Using specified backup: ${BACKUP_DATE}${NC}" +fi + +BACKUP_DIR="secrets-backup/${BACKUP_DATE}" + +# Check if backup exists +if [ ! -d "$BACKUP_DIR" ]; then + echo -e "${RED}Error: Backup not found: ${BACKUP_DIR}${NC}" + echo "" + echo "Available backups:" + ls -1 secrets-backup + exit 1 +fi + +echo "" +echo -e "${BLUE}Backup location: ${BACKUP_DIR}${NC}" +echo "" + +# List encrypted files in backup +ENCRYPTED_FILES=() +for file in "${BACKUP_DIR}"/*.enc; do + if [ -f "$file" ]; then + ENCRYPTED_FILES+=("$file") + fi +done + +if [ ${#ENCRYPTED_FILES[@]} -eq 0 ]; then + echo -e "${RED}Error: No encrypted files found in backup${NC}" + exit 1 +fi + +echo "Found ${#ENCRYPTED_FILES[@]} encrypted file(s):" +for file in "${ENCRYPTED_FILES[@]}"; do + echo " - $(basename "$file")" +done +echo "" + +# Ask for confirmation +echo -e "${YELLOW}⚠️ This will overwrite existing .env files!${NC}" +read -p "Continue? (y/N): " -n 1 -r +echo "" + +if [[ ! $REPLY =~ ^[Yy]$ ]]; then + echo "Restore cancelled" + exit 0 +fi + +# Get password +if [ -z "$BACKUP_PASSWORD" ]; then + echo "" + echo -e "${YELLOW}Enter decryption password:${NC}" + read -s BACKUP_PASSWORD + echo "" + + if [ -z "$BACKUP_PASSWORD" ]; then + echo -e "${RED}Error: Password cannot be empty${NC}" + exit 1 + fi +fi + +echo "" + +# Counter for restored files +RESTORED=0 +FAILED=0 + +# Restore each file +for encrypted_file in "${ENCRYPTED_FILES[@]}"; do + filename=$(basename "$encrypted_file" .enc) + + # Determine target path based on filename + if [[ "$filename" == "backend-.env" ]]; then + target="reports-app/backend/.env" + elif [[ "$filename" == "backend-.env.prod" ]]; then + target="reports-app/backend/.env.prod" + elif [[ "$filename" == "telegram-bot-.env" ]]; then + target="reports-app/telegram-bot/.env" + elif [[ "$filename" == "telegram-bot-.env.prod" ]]; then + target="reports-app/telegram-bot/.env.prod" + else + echo -e "${YELLOW}Skipping unknown file: $filename${NC}" + continue + fi + + echo -e "Decrypting: ${GREEN}$filename${NC}" + echo -e " Target: $target" + + # Create target directory if needed + mkdir -p "$(dirname "$target")" + + # Decrypt + if echo "$BACKUP_PASSWORD" | openssl enc -aes-256-cbc -d -pbkdf2 \ + -in "$encrypted_file" -out "$target" -pass stdin 2>/dev/null; then + echo -e " ✅ Restored successfully" + RESTORED=$((RESTORED + 1)) + else + echo -e " ${RED}❌ Failed to decrypt (wrong password?)${NC}" + FAILED=$((FAILED + 1)) + fi + echo "" +done + +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━" +if [ $FAILED -eq 0 ]; then + echo -e "${GREEN}✅ Restore completed successfully${NC}" +else + echo -e "${YELLOW}⚠️ Restore completed with errors${NC}" +fi +echo "" +echo "📊 Summary:" +echo " - Restored: ${RESTORED} files" +echo " - Failed: ${FAILED} files" +echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"