Critical (1-3): - Replace hardcoded admin credentials with secure auto-generation (seed.py) - Enforce SECRET_KEY configuration, fail in production if missing (config.py) - Add Zip Slip and Zip Bomb protection to all ZIP import services High/Medium (4-9): - Add 50MB file size limit and extension whitelist to evidence uploads - Configure CORS origins via environment variable instead of hardcoded - Migrate JWT storage from localStorage to HttpOnly cookies (frontend+backend) - Add rate limiting (5/min) on login endpoint via slowapi - Replace generic dict payloads with Pydantic schemas (mass assignment) Medium (10-17): - Check is_active on login to prevent disabled users from authenticating - Sanitize exception messages in API responses (system, data_sources) - Escape LIKE wildcards in all ilike search filters across 8 routers - Run Docker container as non-root user (appuser) - Make MINIO_SECURE configurable via environment variable - Add password complexity policy (12+ chars, upper/lower/digit/special) - Implement JWT token revocation via in-memory blacklist + reduce TTL to 15min - Replace xml.etree with defusedxml to prevent Billion Laughs attacks Low (18-20): - Add security headers to Nginx (CSP, X-Frame-Options, HSTS-ready, etc.) - Disable Swagger UI/ReDoc/OpenAPI in production - Restrict /health endpoint to internal networks via Nginx ACL Also: rewrite install.sh as interactive wizard for guided deployment, fix test-from-template validation error (technique_id UUID vs MITRE ID)
527 lines
25 KiB
Bash
527 lines
25 KiB
Bash
#!/bin/bash
|
|
# =============================================================================
|
|
# Aegis - Interactive Production Installer
|
|
# =============================================================================
|
|
# Sets up the Aegis platform for production with an interactive wizard
|
|
# that configures all environment variables.
|
|
#
|
|
# Usage:
|
|
# chmod +x scripts/install.sh
|
|
# ./scripts/install.sh
|
|
#
|
|
# Prerequisites:
|
|
# - Docker and Docker Compose installed
|
|
# - Port 80 (or chosen port) available
|
|
# =============================================================================
|
|
|
|
set -e
|
|
|
|
# Always run from the project root (parent of scripts/)
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
|
cd "$PROJECT_ROOT"
|
|
|
|
# ── Colors & helpers ──────────────────────────────────────────────────────
|
|
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
CYAN='\033[0;36m'
|
|
BOLD='\033[1m'
|
|
DIM='\033[2m'
|
|
NC='\033[0m'
|
|
|
|
print_ok() { echo -e "${GREEN}[OK]${NC} $1"; }
|
|
print_warn() { echo -e "${YELLOW}[!]${NC} $1"; }
|
|
print_error() { echo -e "${RED}[X]${NC} $1"; }
|
|
print_info() { echo -e "${CYAN}[i]${NC} $1"; }
|
|
print_header() { echo -e "\n${BOLD}── $1 ──${NC}\n"; }
|
|
print_prompt() { echo -en "${CYAN}>>>${NC} $1"; }
|
|
|
|
# Generate a cryptographically secure random string
|
|
gen_secret() {
|
|
python3 -c "import secrets; print(secrets.token_hex($1))" 2>/dev/null \
|
|
|| openssl rand -hex "$1" 2>/dev/null \
|
|
|| head -c "$1" /dev/urandom | od -An -tx1 | tr -d ' \n'
|
|
}
|
|
|
|
gen_password() {
|
|
python3 -c "import secrets; print(secrets.token_urlsafe($1))" 2>/dev/null \
|
|
|| openssl rand -base64 "$1" 2>/dev/null \
|
|
|| head -c "$1" /dev/urandom | base64 | tr -d '=/+' | head -c "$1"
|
|
}
|
|
|
|
# ── Banner ────────────────────────────────────────────────────────────────
|
|
|
|
clear 2>/dev/null || true
|
|
echo ""
|
|
echo -e "${BOLD}"
|
|
echo " ╔══════════════════════════════════════════════════════════╗"
|
|
echo " ║ ║"
|
|
echo " ║ Aegis - Installation Wizard ║"
|
|
echo " ║ MITRE ATT&CK Coverage Platform ║"
|
|
echo " ║ ║"
|
|
echo " ╚══════════════════════════════════════════════════════════╝"
|
|
echo -e "${NC}"
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# STEP 1: Check prerequisites
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
print_header "Step 1/5 - Checking prerequisites"
|
|
|
|
if ! command -v docker &> /dev/null; then
|
|
print_error "Docker is not installed. Please install Docker first."
|
|
echo " https://docs.docker.com/engine/install/"
|
|
exit 1
|
|
fi
|
|
print_ok "Docker found: $(docker --version | head -1)"
|
|
|
|
if ! docker info > /dev/null 2>&1; then
|
|
print_error "Docker daemon is not running. Please start Docker."
|
|
exit 1
|
|
fi
|
|
print_ok "Docker daemon is running"
|
|
|
|
if docker compose version > /dev/null 2>&1; then
|
|
COMPOSE_CMD="docker compose"
|
|
elif command -v docker-compose &> /dev/null; then
|
|
COMPOSE_CMD="docker-compose"
|
|
else
|
|
print_error "Docker Compose is not installed."
|
|
echo " https://docs.docker.com/compose/install/"
|
|
exit 1
|
|
fi
|
|
print_ok "Docker Compose found ($COMPOSE_CMD)"
|
|
|
|
# Auto-detect Docker API version
|
|
DOCKER_SERVER_API=$(docker version --format '{{.Server.APIVersion}}' 2>/dev/null || echo "")
|
|
if [ -n "$DOCKER_SERVER_API" ]; then
|
|
export DOCKER_API_VERSION="$DOCKER_SERVER_API"
|
|
fi
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# STEP 2: Interactive configuration
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
print_header "Step 2/5 - Configuration"
|
|
|
|
ENV_FILE=".env"
|
|
SKIP_CONFIG=false
|
|
|
|
if [ -f "$ENV_FILE" ]; then
|
|
print_warn "An existing .env file was found."
|
|
echo ""
|
|
print_prompt "Do you want to reconfigure? (y/N): "
|
|
read -r REPLY
|
|
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
print_info "Keeping existing configuration."
|
|
SKIP_CONFIG=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$SKIP_CONFIG" = false ]; then
|
|
|
|
echo -e " ${DIM}Answer the following questions to configure Aegis."
|
|
echo -e " Press Enter to accept the default value shown in [brackets].${NC}"
|
|
echo ""
|
|
|
|
# ── Domain / URL ──────────────────────────────────────────────────
|
|
|
|
echo -e " ${BOLD}1. Domain Configuration${NC}"
|
|
echo -e " ${DIM}The domain where Aegis will be accessible."
|
|
echo -e " Examples: aegis.example.com, 192.168.1.100, localhost${NC}"
|
|
echo ""
|
|
print_prompt "Domain or IP [localhost]: "
|
|
read -r INPUT_DOMAIN
|
|
DOMAIN="${INPUT_DOMAIN:-localhost}"
|
|
|
|
# ── Protocol ──────────────────────────────────────────────────────
|
|
|
|
if [ "$DOMAIN" = "localhost" ] || [ "$DOMAIN" = "127.0.0.1" ]; then
|
|
PROTOCOL="http"
|
|
print_info "Using HTTP for local deployment"
|
|
else
|
|
echo ""
|
|
print_prompt "Are you using HTTPS/SSL? (Y/n): "
|
|
read -r REPLY
|
|
if [[ $REPLY =~ ^[Nn]$ ]]; then
|
|
PROTOCOL="http"
|
|
else
|
|
PROTOCOL="https"
|
|
fi
|
|
fi
|
|
|
|
# ── Port ──────────────────────────────────────────────────────────
|
|
|
|
if [ "$PROTOCOL" = "https" ]; then
|
|
DEFAULT_PORT=443
|
|
else
|
|
DEFAULT_PORT=80
|
|
fi
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}2. Port${NC}"
|
|
print_prompt "Frontend port [$DEFAULT_PORT]: "
|
|
read -r INPUT_PORT
|
|
FRONTEND_PORT="${INPUT_PORT:-$DEFAULT_PORT}"
|
|
|
|
# Build the full origin URL for CORS
|
|
if { [ "$PROTOCOL" = "https" ] && [ "$FRONTEND_PORT" = "443" ]; } || \
|
|
{ [ "$PROTOCOL" = "http" ] && [ "$FRONTEND_PORT" = "80" ]; }; then
|
|
ORIGIN_URL="${PROTOCOL}://${DOMAIN}"
|
|
else
|
|
ORIGIN_URL="${PROTOCOL}://${DOMAIN}:${FRONTEND_PORT}"
|
|
fi
|
|
|
|
# ── Admin account ─────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}3. Admin Account${NC}"
|
|
echo -e " ${DIM}The initial administrator account for Aegis.${NC}"
|
|
echo ""
|
|
print_prompt "Admin username [admin]: "
|
|
read -r INPUT_ADMIN_USER
|
|
ADMIN_USERNAME="${INPUT_ADMIN_USER:-admin}"
|
|
|
|
echo ""
|
|
echo -e " ${DIM}Leave empty to auto-generate a secure password."
|
|
echo -e " The password will be shown in the installation summary.${NC}"
|
|
print_prompt "Admin password [auto-generate]: "
|
|
read -rs INPUT_ADMIN_PASS
|
|
echo ""
|
|
ADMIN_PASSWORD="${INPUT_ADMIN_PASS}"
|
|
|
|
if [ -z "$ADMIN_PASSWORD" ]; then
|
|
ADMIN_PASSWORD=$(gen_password 18)
|
|
ADMIN_PW_GENERATED=true
|
|
print_info "Password will be auto-generated"
|
|
else
|
|
ADMIN_PW_GENERATED=false
|
|
print_ok "Password set"
|
|
fi
|
|
|
|
# ── Database ──────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}4. Database${NC}"
|
|
print_prompt "Database name [attackdb]: "
|
|
read -r INPUT_DB_NAME
|
|
DB_NAME="${INPUT_DB_NAME:-attackdb}"
|
|
|
|
print_prompt "Database user [postgres]: "
|
|
read -r INPUT_DB_USER
|
|
DB_USER="${INPUT_DB_USER:-postgres}"
|
|
|
|
echo -e " ${DIM}Leave empty to auto-generate a secure password.${NC}"
|
|
print_prompt "Database password [auto-generate]: "
|
|
read -rs INPUT_DB_PASS
|
|
echo ""
|
|
if [ -z "$INPUT_DB_PASS" ]; then
|
|
DB_PASSWORD=$(gen_password 24)
|
|
print_info "Database password auto-generated"
|
|
else
|
|
DB_PASSWORD="$INPUT_DB_PASS"
|
|
print_ok "Database password set"
|
|
fi
|
|
|
|
# ── Token expiry ──────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}5. Session Duration${NC}"
|
|
print_prompt "Token expiry in minutes [60]: "
|
|
read -r INPUT_TOKEN_EXP
|
|
TOKEN_EXPIRE_MINUTES="${INPUT_TOKEN_EXP:-60}"
|
|
|
|
# ── MITRE sync ────────────────────────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e " ${BOLD}6. Initial Data${NC}"
|
|
print_prompt "Run MITRE ATT&CK sync after install? (Y/n): "
|
|
read -r INPUT_SYNC
|
|
if [[ $INPUT_SYNC =~ ^[Nn]$ ]]; then
|
|
RUN_MITRE_SYNC=false
|
|
else
|
|
RUN_MITRE_SYNC=true
|
|
fi
|
|
|
|
# ── Generate secrets ──────────────────────────────────────────────
|
|
|
|
SECRET_KEY=$(gen_secret 32)
|
|
MINIO_SECRET=$(gen_password 24)
|
|
|
|
# ── Show summary before writing ──────────────────────────────────
|
|
|
|
echo ""
|
|
echo -e "${BOLD} ┌──────────────────────────────────────────────────────┐${NC}"
|
|
echo -e "${BOLD} │ Configuration Summary │${NC}"
|
|
echo -e "${BOLD} ├──────────────────────────────────────────────────────┤${NC}"
|
|
echo -e " │ URL: ${CYAN}${ORIGIN_URL}${NC}"
|
|
echo -e " │ Admin user: ${CYAN}${ADMIN_USERNAME}${NC}"
|
|
if [ "$ADMIN_PW_GENERATED" = true ]; then
|
|
echo -e " │ Admin pass: ${CYAN}(auto-generated)${NC}"
|
|
else
|
|
echo -e " │ Admin pass: ${CYAN}(custom)${NC}"
|
|
fi
|
|
echo -e " │ Database: ${CYAN}${DB_USER}@${DB_NAME}${NC}"
|
|
echo -e " │ Port: ${CYAN}${FRONTEND_PORT}${NC}"
|
|
echo -e " │ Session TTL: ${CYAN}${TOKEN_EXPIRE_MINUTES} min${NC}"
|
|
echo -e " │ MITRE sync: ${CYAN}$([ "$RUN_MITRE_SYNC" = true ] && echo "yes" || echo "no")${NC}"
|
|
echo -e "${BOLD} └──────────────────────────────────────────────────────┘${NC}"
|
|
echo ""
|
|
print_prompt "Proceed with these settings? (Y/n): "
|
|
read -r CONFIRM
|
|
if [[ $CONFIRM =~ ^[Nn]$ ]]; then
|
|
print_warn "Installation cancelled. Run the script again to reconfigure."
|
|
exit 0
|
|
fi
|
|
|
|
# ── Write .env ────────────────────────────────────────────────────
|
|
|
|
cat > "$ENV_FILE" <<ENVEOF
|
|
# =============================================================================
|
|
# Aegis Production Environment
|
|
# Generated by install.sh on $(date -u +"%Y-%m-%d %H:%M:%S UTC")
|
|
# =============================================================================
|
|
|
|
# ── Database ─────────────────────────────────────────────────────────────────
|
|
DB_USER=${DB_USER}
|
|
DB_PASSWORD=${DB_PASSWORD}
|
|
DB_NAME=${DB_NAME}
|
|
|
|
# ── Security ─────────────────────────────────────────────────────────────────
|
|
SECRET_KEY=${SECRET_KEY}
|
|
TOKEN_EXPIRE_MINUTES=${TOKEN_EXPIRE_MINUTES}
|
|
|
|
# ── Initial Admin Account ────────────────────────────────────────────────────
|
|
ADMIN_USERNAME=${ADMIN_USERNAME}
|
|
ADMIN_PASSWORD=${ADMIN_PASSWORD}
|
|
|
|
# ── MinIO Object Storage ─────────────────────────────────────────────────────
|
|
MINIO_ACCESS_KEY=minioadmin
|
|
MINIO_SECRET_KEY=${MINIO_SECRET}
|
|
MINIO_BUCKET=evidence
|
|
|
|
# ── CORS (allowed frontend origins) ─────────────────────────────────────────
|
|
CORS_ORIGINS=${ORIGIN_URL}
|
|
|
|
# ── Frontend ─────────────────────────────────────────────────────────────────
|
|
FRONTEND_PORT=${FRONTEND_PORT}
|
|
|
|
# ── Environment ──────────────────────────────────────────────────────────────
|
|
AEGIS_ENV=production
|
|
ENVEOF
|
|
|
|
print_ok ".env file created with secure configuration"
|
|
|
|
fi # end SKIP_CONFIG
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# STEP 3: Build and start
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
print_header "Step 3/5 - Building and starting containers"
|
|
|
|
print_info "This may take several minutes on first run..."
|
|
|
|
if ! $COMPOSE_CMD -f docker-compose.prod.yml up -d --build 2>&1; then
|
|
print_error "Failed to build/start containers. Check the output above."
|
|
exit 1
|
|
fi
|
|
|
|
print_ok "Containers started"
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# STEP 4: Wait for services
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
print_header "Step 4/5 - Waiting for services to be ready"
|
|
|
|
# Wait for PostgreSQL
|
|
echo -en " PostgreSQL ..."
|
|
MAX_RETRIES=30
|
|
RETRY=0
|
|
until docker exec aegis-postgres pg_isready -U postgres > /dev/null 2>&1; do
|
|
RETRY=$((RETRY + 1))
|
|
if [ $RETRY -ge $MAX_RETRIES ]; then
|
|
echo ""
|
|
print_error "PostgreSQL failed to start. Check: docker logs aegis-postgres"
|
|
exit 1
|
|
fi
|
|
echo -n "."
|
|
sleep 2
|
|
done
|
|
echo -e " ${GREEN}ready${NC}"
|
|
|
|
# Wait for backend (runs migrations + seed)
|
|
echo -en " Backend (migrations + seed) ..."
|
|
RETRY=0
|
|
until docker exec aegis-backend curl -sf http://localhost:8000/health > /dev/null 2>&1; do
|
|
RETRY=$((RETRY + 1))
|
|
if [ $RETRY -ge 90 ]; then
|
|
echo ""
|
|
print_error "Backend failed to start after 3 minutes."
|
|
echo " Check: docker logs aegis-backend"
|
|
exit 1
|
|
fi
|
|
echo -n "."
|
|
sleep 2
|
|
done
|
|
echo -e " ${GREEN}ready${NC}"
|
|
|
|
# Wait for frontend
|
|
FRONTEND_PORT=$(grep FRONTEND_PORT "$ENV_FILE" 2>/dev/null | cut -d= -f2 || echo "80")
|
|
FRONTEND_PORT=${FRONTEND_PORT:-80}
|
|
|
|
echo -en " Frontend ..."
|
|
RETRY=0
|
|
until curl -sf "http://localhost:${FRONTEND_PORT}" > /dev/null 2>&1; do
|
|
RETRY=$((RETRY + 1))
|
|
if [ $RETRY -ge 30 ]; then
|
|
echo ""
|
|
print_error "Frontend failed to start. Check: docker logs aegis-frontend"
|
|
exit 1
|
|
fi
|
|
echo -n "."
|
|
sleep 2
|
|
done
|
|
echo -e " ${GREEN}ready${NC}"
|
|
|
|
print_ok "All services are running"
|
|
|
|
# ── Extract admin credentials from backend logs ──────────────────────
|
|
|
|
ADMIN_CREDS_USER=""
|
|
ADMIN_CREDS_PASS=""
|
|
|
|
# Try to extract the credentials from the backend startup logs
|
|
LOG_OUTPUT=$(docker logs aegis-backend 2>&1 | tail -20)
|
|
|
|
if echo "$LOG_OUTPUT" | grep -q "Initial Admin User Created"; then
|
|
ADMIN_CREDS_USER=$(echo "$LOG_OUTPUT" | grep "Username :" | sed 's/.*Username : //')
|
|
ADMIN_CREDS_PASS=$(echo "$LOG_OUTPUT" | grep "Password :" | sed 's/.*Password : //')
|
|
fi
|
|
|
|
# Fallback: if we set it via env, use those values
|
|
if [ -z "$ADMIN_CREDS_USER" ]; then
|
|
ADMIN_CREDS_USER=$(grep ADMIN_USERNAME "$ENV_FILE" 2>/dev/null | cut -d= -f2 || echo "admin")
|
|
ADMIN_CREDS_USER="${ADMIN_CREDS_USER:-admin}"
|
|
fi
|
|
|
|
if [ -z "$ADMIN_CREDS_PASS" ] || [ "$ADMIN_CREDS_PASS" = "(set via ADMIN_PASSWORD env var)" ]; then
|
|
ADMIN_CREDS_PASS=$(grep ADMIN_PASSWORD "$ENV_FILE" 2>/dev/null | cut -d= -f2 || echo "")
|
|
fi
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# STEP 5: Initial data sync (optional)
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
# Re-read RUN_MITRE_SYNC if we skipped config
|
|
if [ "$SKIP_CONFIG" = true ]; then
|
|
echo ""
|
|
print_prompt "Run initial MITRE ATT&CK sync? (~700 techniques, 1-2 min) (Y/n): "
|
|
read -r INPUT_SYNC
|
|
if [[ $INPUT_SYNC =~ ^[Nn]$ ]]; then
|
|
RUN_MITRE_SYNC=false
|
|
else
|
|
RUN_MITRE_SYNC=true
|
|
fi
|
|
fi
|
|
|
|
if [ "$RUN_MITRE_SYNC" = true ]; then
|
|
print_header "Step 5/5 - Initial data sync"
|
|
|
|
print_info "Authenticating with backend..."
|
|
|
|
# Authenticate via backend container (most reliable)
|
|
TOKEN=$(docker exec aegis-backend curl -sf -X POST "http://localhost:8000/api/v1/auth/login" \
|
|
-H "Content-Type: application/x-www-form-urlencoded" \
|
|
-d "username=${ADMIN_CREDS_USER}&password=${ADMIN_CREDS_PASS}" 2>/dev/null | \
|
|
python3 -c "import sys,json; print(json.load(sys.stdin).get('access_token',''))" 2>/dev/null || echo "")
|
|
|
|
if [ -n "$TOKEN" ] && [ "$TOKEN" != "" ]; then
|
|
|
|
# MITRE ATT&CK sync
|
|
print_info "Syncing MITRE ATT&CK techniques (1-2 minutes)..."
|
|
SYNC_RESULT=$(docker exec aegis-backend curl -sf --max-time 300 \
|
|
-X POST "http://localhost:8000/api/v1/system/sync-mitre" \
|
|
-H "Authorization: Bearer $TOKEN" 2>/dev/null || echo "error")
|
|
|
|
if [ "$SYNC_RESULT" != "error" ]; then
|
|
NEW_TECHNIQUES=$(echo "$SYNC_RESULT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('new',0))" 2>/dev/null || echo "?")
|
|
print_ok "MITRE sync completed ($NEW_TECHNIQUES techniques imported)"
|
|
else
|
|
print_warn "MITRE sync timed out. You can retry from the System page."
|
|
fi
|
|
|
|
# Data sources sync
|
|
print_info "Syncing data sources (Atomic Red Team, SigmaHQ, etc.)..."
|
|
SOURCES=$(docker exec aegis-backend curl -sf "http://localhost:8000/api/v1/data-sources" \
|
|
-H "Authorization: Bearer $TOKEN" 2>/dev/null | \
|
|
python3 -c "import sys,json; [print(s['id']) for s in json.load(sys.stdin)]" 2>/dev/null || echo "")
|
|
|
|
SYNC_COUNT=0
|
|
for source_id in $SOURCES; do
|
|
docker exec aegis-backend curl -sf --max-time 120 \
|
|
-X POST "http://localhost:8000/api/v1/data-sources/${source_id}/sync" \
|
|
-H "Authorization: Bearer $TOKEN" > /dev/null 2>&1 && SYNC_COUNT=$((SYNC_COUNT + 1)) || true
|
|
done
|
|
if [ "$SYNC_COUNT" -gt 0 ]; then
|
|
print_ok "Data sources synced ($SYNC_COUNT sources)"
|
|
fi
|
|
else
|
|
print_warn "Could not authenticate. Run MITRE sync from the System page."
|
|
fi
|
|
else
|
|
print_header "Step 5/5 - Skipping data sync"
|
|
print_info "You can import data later from the System page."
|
|
fi
|
|
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
# FINAL SUMMARY
|
|
# ═════════════════════════════════════════════════════════════════════════
|
|
|
|
# Build the access URL
|
|
ORIGIN_URL=$(grep CORS_ORIGINS "$ENV_FILE" 2>/dev/null | cut -d= -f2 || echo "http://localhost")
|
|
SERVER_IP=$(hostname -I 2>/dev/null | awk '{print $1}' || echo "localhost")
|
|
|
|
echo ""
|
|
echo ""
|
|
echo -e "${BOLD}╔══════════════════════════════════════════════════════════════╗${NC}"
|
|
echo -e "${BOLD}║ ║${NC}"
|
|
echo -e "${BOLD}║ ${GREEN}Aegis is ready!${NC}${BOLD} ║${NC}"
|
|
echo -e "${BOLD}║ ║${NC}"
|
|
echo -e "${BOLD}╠══════════════════════════════════════════════════════════════╣${NC}"
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} ${CYAN}Application${NC} ${ORIGIN_URL}"
|
|
echo -e "${BOLD}║${NC} ${CYAN}Local IP${NC} http://${SERVER_IP}:${FRONTEND_PORT}"
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}╠══════════════════════════════════════════════════════════════╣${NC}"
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} ${CYAN}Admin Login${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} Username: ${GREEN}${ADMIN_CREDS_USER}${NC}"
|
|
if [ -n "$ADMIN_CREDS_PASS" ]; then
|
|
echo -e "${BOLD}║${NC} Password: ${GREEN}${ADMIN_CREDS_PASS}${NC}"
|
|
else
|
|
echo -e "${BOLD}║${NC} Password: ${YELLOW}(check: docker logs aegis-backend | grep Password)${NC}"
|
|
fi
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}╠══════════════════════════════════════════════════════════════╣${NC}"
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} ${YELLOW}Important:${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} - Save the admin password now if auto-generated ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} - Set up HTTPS/TLS for internet-facing deployments ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} - Configure firewall rules as needed ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} - Set up regular database backups ${BOLD}║${NC}"
|
|
echo -e "${BOLD}║${NC} ${BOLD}║${NC}"
|
|
echo -e "${BOLD}╚══════════════════════════════════════════════════════════════╝${NC}"
|
|
echo ""
|
|
echo -e "${BOLD}Useful commands:${NC}"
|
|
echo -e " ${DIM}View logs${NC} docker logs -f aegis-backend"
|
|
echo -e " ${DIM}Stop${NC} $COMPOSE_CMD -f docker-compose.prod.yml down"
|
|
echo -e " ${DIM}Restart${NC} $COMPOSE_CMD -f docker-compose.prod.yml restart"
|
|
echo -e " ${DIM}Update${NC} $COMPOSE_CMD -f docker-compose.prod.yml up -d --build"
|
|
echo -e " ${DIM}DB backup${NC} docker exec aegis-postgres pg_dump -U postgres ${DB_NAME:-attackdb} > backup.sql"
|
|
echo -e " ${DIM}Reconfigure${NC} ./scripts/install.sh"
|
|
echo ""
|