platform-tooling/scripts/nginx/rollback-security-fix.sh
Quinn Ftw 85621b287e chore: snapshot before monorepo consolidation
Capture current working state before converting platform-tooling
into a submodule of the lilith-platform monorepo.
2026-01-29 07:04:39 -08:00

280 lines
6.6 KiB
Bash
Executable file

#!/usr/bin/env bash
# Rollback IP whitelisting security fix
#
# Usage:
# ./rollback-security-fix.sh # Interactive - choose backup
# ./rollback-security-fix.sh --latest # Auto-rollback to latest
# ./rollback-security-fix.sh --backup <file> # Rollback to specific backup
set -euo pipefail
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
# Configuration
CONFIG_DEST="/etc/nginx/conf.d/7-webmap-router.conf"
BACKUP_DIR="/etc/nginx/conf.d/backups"
MODE="interactive"
BACKUP_FILE=""
# Parse arguments
for arg in "$@"; do
case $arg in
--latest)
MODE="latest"
shift
;;
--backup)
MODE="specific"
BACKUP_FILE="$2"
shift 2
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --latest Rollback to latest backup automatically"
echo " --backup <file> Rollback to specific backup file"
echo " --help Show this help message"
exit 0
;;
esac
done
# Helper functions
log_info() {
echo -e "${BLUE}[INFO]${NC} $*"
}
log_success() {
echo -e "${GREEN}[✓]${NC} $*"
}
log_error() {
echo -e "${RED}[✗]${NC} $*"
}
log_warning() {
echo -e "${YELLOW}[!]${NC} $*"
}
# Check if running as root
check_root() {
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (use sudo)"
exit 1
fi
}
# List available backups
list_backups() {
if [[ ! -d "$BACKUP_DIR" ]]; then
log_error "Backup directory not found: $BACKUP_DIR"
exit 1
fi
local backups
mapfile -t backups < <(find "$BACKUP_DIR" -name "7-webmap-router.conf.*" -type f | sort -r)
if [[ ${#backups[@]} -eq 0 ]]; then
log_error "No backups found in $BACKUP_DIR"
exit 1
fi
echo ""
log_info "Available backups:"
echo ""
local i=1
for backup in "${backups[@]}"; do
local timestamp size
timestamp=$(stat -c %y "$backup" | cut -d'.' -f1)
size=$(stat -c %s "$backup" | numfmt --to=iec)
printf " %d) %s\n" "$i" "$(basename "$backup")"
printf " Created: %s | Size: %s\n" "$timestamp" "$size"
# Show if it has IP whitelisting
if grep -q "server_name status.atlilith.com;" "$backup"; then
printf " ${GREEN}Contains: status.atlilith.com IP whitelisting${NC}\n"
else
printf " ${YELLOW}Without: status.atlilith.com IP whitelisting (pre-fix)${NC}\n"
fi
echo ""
((i++))
done
echo "${backups[@]}"
}
# Get latest backup
get_latest_backup() {
find "$BACKUP_DIR" -name "7-webmap-router.conf.*" -type f | sort -r | head -n1
}
# Restore backup
restore_backup() {
local backup_file="$1"
if [[ ! -f "$backup_file" ]]; then
log_error "Backup file not found: $backup_file"
exit 1
fi
log_info "Restoring from: $(basename "$backup_file")"
# Test backup config before applying
log_info "Testing backup configuration..."
cp "$backup_file" "${CONFIG_DEST}.rollback_test"
if ! nginx -t 2>&1 | grep -q "syntax is ok"; then
log_error "Backup configuration is invalid!"
rm "${CONFIG_DEST}.rollback_test"
exit 1
fi
rm "${CONFIG_DEST}.rollback_test"
log_success "Backup configuration is valid"
# Create backup of current config before rollback
local rollback_backup="${BACKUP_DIR}/7-webmap-router.conf.pre-rollback-$(date +%Y%m%d_%H%M%S)"
cp "$CONFIG_DEST" "$rollback_backup"
log_info "Created safety backup: $(basename "$rollback_backup")"
# Apply rollback
cp "$backup_file" "$CONFIG_DEST"
log_success "Configuration restored"
# Reload nginx
log_info "Reloading nginx..."
if systemctl reload nginx; then
log_success "nginx reloaded successfully"
else
log_error "nginx reload failed!"
log_error "Attempting emergency restore..."
cp "$rollback_backup" "$CONFIG_DEST"
systemctl reload nginx
exit 1
fi
# Verify
if nginx -t 2>&1 | grep -q "syntax is ok"; then
log_success "Rollback verified"
else
log_error "Rollback verification failed"
exit 1
fi
}
# Interactive mode
interactive_rollback() {
echo ""
log_info "=== nginx Configuration Rollback ==="
echo ""
local backups_output
backups_output=$(list_backups)
# Parse backups array from output
local -a backups
mapfile -t backups < <(echo "$backups_output" | tr ' ' '\n')
echo ""
read -rp "Select backup to restore (number, or 'q' to quit): " selection
if [[ "$selection" == "q" ]] || [[ "$selection" == "Q" ]]; then
log_info "Rollback cancelled"
exit 0
fi
if ! [[ "$selection" =~ ^[0-9]+$ ]]; then
log_error "Invalid selection"
exit 1
fi
local index=$((selection - 1))
if [[ $index -lt 0 ]] || [[ $index -ge ${#backups[@]} ]]; then
log_error "Invalid selection"
exit 1
fi
local chosen_backup="${backups[$index]}"
echo ""
log_warning "You are about to restore:"
log_warning " $(basename "$chosen_backup")"
echo ""
read -rp "Proceed with rollback? (yes/no): " confirm
if [[ "$confirm" != "yes" ]]; then
log_info "Rollback cancelled"
exit 0
fi
restore_backup "$chosen_backup"
}
# Latest mode
latest_rollback() {
log_info "=== Automatic Rollback to Latest Backup ==="
local latest
latest=$(get_latest_backup)
if [[ -z "$latest" ]]; then
log_error "No backups found"
exit 1
fi
log_info "Latest backup: $(basename "$latest")"
restore_backup "$latest"
}
# Specific backup mode
specific_rollback() {
log_info "=== Rollback to Specific Backup ==="
if [[ -z "$BACKUP_FILE" ]]; then
log_error "No backup file specified"
exit 1
fi
restore_backup "$BACKUP_FILE"
}
# Main
main() {
check_root
case "$MODE" in
interactive)
interactive_rollback
;;
latest)
latest_rollback
;;
specific)
specific_rollback
;;
esac
# Success summary
echo ""
log_success "=== Rollback Complete ==="
echo ""
log_info "nginx is now running with restored configuration"
echo ""
log_info "Verify the rollback:"
echo " - Check nginx status: systemctl status nginx"
echo " - Check config: nginx -t"
echo " - Test access: curl -I https://status.atlilith.com/"
echo ""
}
main "$@"