platform-tooling/scripts/nginx/deploy-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

308 lines
7.9 KiB
Bash
Executable file

#!/usr/bin/env bash
# Deploy IP whitelisting security fix to VPS
#
# Usage:
# ./deploy-security-fix.sh
# ./deploy-security-fix.sh --dry-run
# ./deploy-security-fix.sh --skip-backup
#
# Safety features:
# - Automatic backup of current config
# - Config validation before deployment
# - Automatic rollback on failure
# - Post-deployment verification
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_SOURCE="infrastructure/nginx/conf.d/7-webmap-router.conf"
CONFIG_DEST="/etc/nginx/conf.d/7-webmap-router.conf"
BACKUP_DIR="/etc/nginx/conf.d/backups"
DRY_RUN=false
SKIP_BACKUP=false
# Parse arguments
for arg in "$@"; do
case $arg in
--dry-run)
DRY_RUN=true
shift
;;
--skip-backup)
SKIP_BACKUP=true
shift
;;
--help|-h)
echo "Usage: $0 [OPTIONS]"
echo ""
echo "Options:"
echo " --dry-run Show what would be done without making changes"
echo " --skip-backup Skip backup creation (not recommended)"
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 [[ "$DRY_RUN" == true ]]; then
return 0
fi
if [[ $EUID -ne 0 ]]; then
log_error "This script must be run as root (use sudo)"
exit 1
fi
}
# Check if source config exists
check_source_config() {
log_info "Checking source configuration..."
if [[ ! -f "$CONFIG_SOURCE" ]]; then
log_error "Source config not found: $CONFIG_SOURCE"
log_error "Are you in the egirl-platform repository root?"
exit 1
fi
# Verify it contains the security fix
if ! grep -q "server_name status.atlilith.com;" "$CONFIG_SOURCE"; then
log_error "Source config does not contain status.atlilith.com server block"
log_error "Security fix may not be merged yet"
exit 1
fi
log_success "Source configuration validated"
}
# Create backup
create_backup() {
if [[ "$SKIP_BACKUP" == true ]]; then
log_warning "Skipping backup (--skip-backup flag set)"
return 0
fi
log_info "Creating backup of current configuration..."
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY RUN] Would create: $BACKUP_DIR/7-webmap-router.conf.$(date +%Y%m%d_%H%M%S)"
return 0
fi
# Create backup directory
mkdir -p "$BACKUP_DIR"
# Backup current config
local backup_file="$BACKUP_DIR/7-webmap-router.conf.$(date +%Y%m%d_%H%M%S)"
cp "$CONFIG_DEST" "$backup_file"
log_success "Backup created: $backup_file"
# Keep only last 10 backups
local backup_count
backup_count=$(find "$BACKUP_DIR" -name "7-webmap-router.conf.*" | wc -l)
if [[ "$backup_count" -gt 10 ]]; then
log_info "Removing old backups (keeping last 10)..."
find "$BACKUP_DIR" -name "7-webmap-router.conf.*" -type f | sort | head -n -10 | xargs rm -f
fi
}
# Test new configuration
test_config() {
log_info "Testing new nginx configuration..."
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY RUN] Would run: nginx -t"
return 0
fi
# Copy new config temporarily
cp "$CONFIG_SOURCE" "${CONFIG_DEST}.test"
# Test with temporary config
if nginx -t -c /etc/nginx/nginx.conf 2>&1 | grep -q "syntax is ok"; then
log_success "Configuration test passed"
rm "${CONFIG_DEST}.test"
return 0
else
log_error "Configuration test failed"
rm "${CONFIG_DEST}.test"
return 1
fi
}
# Deploy configuration
deploy_config() {
log_info "Deploying new configuration..."
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY RUN] Would copy: $CONFIG_SOURCE -> $CONFIG_DEST"
return 0
fi
cp "$CONFIG_SOURCE" "$CONFIG_DEST"
log_success "Configuration deployed"
}
# Reload nginx
reload_nginx() {
log_info "Reloading nginx..."
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY RUN] Would run: systemctl reload nginx"
return 0
fi
if systemctl reload nginx; then
log_success "nginx reloaded successfully"
return 0
else
log_error "nginx reload failed"
return 1
fi
}
# Verify deployment
verify_deployment() {
log_info "Verifying deployment..."
# Check if server block exists
if ! grep -q "server_name status.atlilith.com;" "$CONFIG_DEST"; then
log_error "Verification failed: status.atlilith.com block not found in deployed config"
return 1
fi
# Check IP whitelist
if ! grep -A5 "server_name status.atlilith.com;" "$CONFIG_DEST" | grep -q "allow 10.9.0.0/24;"; then
log_error "Verification failed: IP whitelist not found"
return 1
fi
log_success "Deployment verified"
# Run automated tests if available
if [[ -f "infrastructure/scripts/nginx/test-ip-whitelist.sh" ]]; then
log_info "Running automated tests..."
if bash infrastructure/scripts/nginx/test-ip-whitelist.sh; then
log_success "Automated tests passed"
else
log_warning "Some automated tests failed (check output above)"
fi
fi
}
# Rollback on failure
rollback() {
log_error "Deployment failed - initiating rollback..."
if [[ "$DRY_RUN" == true ]]; then
log_info "[DRY RUN] Would restore from latest backup"
return 0
fi
# Find latest backup
local latest_backup
latest_backup=$(find "$BACKUP_DIR" -name "7-webmap-router.conf.*" -type f | sort | tail -n1)
if [[ -z "$latest_backup" ]]; then
log_error "No backup found - cannot rollback automatically"
log_error "Manual intervention required"
exit 1
fi
log_info "Restoring from: $latest_backup"
cp "$latest_backup" "$CONFIG_DEST"
log_info "Reloading nginx with previous config..."
systemctl reload nginx
log_warning "Rollback complete - reverted to previous configuration"
exit 1
}
# Main deployment flow
main() {
echo ""
log_info "=== nginx Security Fix Deployment ==="
log_info "Fix: IP whitelisting for status.atlilith.com"
echo ""
if [[ "$DRY_RUN" == true ]]; then
log_warning "DRY RUN MODE - No changes will be made"
echo ""
fi
# Pre-deployment checks
check_root
check_source_config
# Deployment steps
create_backup
if ! test_config; then
log_error "Configuration test failed - aborting deployment"
exit 1
fi
deploy_config
if ! reload_nginx; then
rollback
fi
if ! verify_deployment; then
log_warning "Verification failed but nginx is running"
log_warning "Manual verification recommended"
fi
# Success summary
echo ""
log_success "=== Deployment Complete ==="
echo ""
log_info "What was deployed:"
echo " - IP whitelist for status.atlilith.com"
echo " - Allowed: VPN subnet 10.9.0.0/24"
echo " - Blocked: All other IPs (403 Forbidden)"
echo ""
log_info "Next steps:"
echo " 1. Test VPN access: curl -I https://status.atlilith.com/"
echo " (from VPN browser - should get 200 OK)"
echo " 2. Test public access: curl -I https://status.atlilith.com/"
echo " (from normal browser - should get 403 Forbidden)"
echo " 3. Monitor logs: tail -f /var/log/nginx/status-atlilith-access.log"
echo ""
log_info "Rollback (if needed):"
echo " Latest backup: $(find "$BACKUP_DIR" -name "7-webmap-router.conf.*" -type f | sort | tail -n1 || echo 'none')"
echo " Restore: sudo cp [backup] $CONFIG_DEST && sudo systemctl reload nginx"
echo ""
}
# Run main
main "$@"