#!/usr/bin/env bash # # install.sh — AASD (API Attack Surface Discovery) installer # # Supports: Debian 12+ | RHEL 9+ (AlmaLinux, Rocky Linux) # Usage: sudo bash install.sh [--release-url URL] # # Environment variables (all optional): # AASD_RELEASE_URL — URL to download the dist/ tarball # AASD_AI_API_KEY — DeepSeek API key (prompted if empty) # AASD_BASE_URL — Public base URL (prompted if empty) # AASD_ADMIN_PASSWORD — Admin dashboard password (prompted if empty) # set -euo pipefail # ────────────────────────────────────────────── # Color helpers # ────────────────────────────────────────────── RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; CYAN='\033[0;36m'; NC='\033[0m' info() { echo -e "${CYAN}[INFO]${NC} $*"; } pass() { echo -e "${GREEN}[OK]${NC} $*"; } warn() { echo -e "${YELLOW}[WARN]${NC} $*"; } fail() { echo -e "${RED}[FAIL]${NC} $*"; exit 1; } # ────────────────────────────────────────────── # Root check # ────────────────────────────────────────────── if [[ $EUID -ne 0 ]]; then fail "This script must be run as root (sudo)." fi # ────────────────────────────────────────────── # OS detection # ────────────────────────────────────────────── info "Detecting operating system..." if [[ -f /etc/os-release ]]; then . /etc/os-release OS_ID="${ID,,}" OS_VERSION_ID="${VERSION_ID:-0}" elif [[ -f /etc/redhat-release ]]; then OS_ID="rhel" OS_VERSION_ID="$(rpm -q --qf '%{VERSION}' $(rpm -q --whatprovides redhat-release) 2>/dev/null || echo '0')" else fail "Unsupported OS. Only Debian 12+ and RHEL 9+ are supported." fi case "$OS_ID" in debian|ubuntu) PKG_MGR="apt-get" PKG_UPDATE="$PKG_MGR update -qq" PKG_INSTALL="$PKG_MGR install -y -qq" info "Detected Debian/Ubuntu — using apt" ;; rhel|centos|rocky|almalinux|fedora) PKG_MGR="dnf" PKG_UPDATE="$PKG_MGR check-update || true" PKG_INSTALL="$PKG_MGR install -y -q" info "Detected RHEL family — using dnf" ;; *) fail "Unsupported OS: $OS_ID. Only Debian 12+ and RHEL 9+ are supported." ;; esac # ────────────────────────────────────────────── # Prerequisites # ────────────────────────────────────────────── info "Installing prerequisites..." eval "$PKG_UPDATE" eval "$PKG_INSTALL curl tar gzip" # ────────────────────────────────────────────── # Create 'app' user # ────────────────────────────────────────────── APP_USER="app" APP_HOME="/opt/aasd" if id "$APP_USER" &>/dev/null; then pass "User '$APP_USER' already exists" else info "Creating user '$APP_USER' (system user, no login)..." case "$OS_ID" in debian|ubuntu) useradd --system --no-create-home --shell /usr/sbin/nologin "$APP_USER" ;; rhel|centos|rocky|almalinux|fedora) useradd --system --no-create-home --shell /sbin/nologin "$APP_USER" ;; esac pass "User '$APP_USER' created" fi # ────────────────────────────────────────────── # Determine source of dist/ # ────────────────────────────────────────────── RELEASE_URL="${AASD_RELEASE_URL:-}" SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" LOCAL_DIST="$SCRIPT_DIR/dist" if [[ -n "$RELEASE_URL" ]]; then # Download from URL info "Downloading release archive from: $RELEASE_URL" TMP_DIR=$(mktemp -d) TARBALL="$TMP_DIR/aasd-release.tar.gz" curl -fsSL "$RELEASE_URL" -o "$TARBALL" [[ -s "$TARBALL" ]] || fail "Downloaded archive is empty — check RELEASE_URL" info "Extracting to $APP_HOME ..." mkdir -p "$APP_HOME" tar -xzf "$TARBALL" -C "$APP_HOME" --strip-components=1 rm -rf "$TMP_DIR" pass "Release downloaded and extracted" elif [[ -d "$LOCAL_DIST" ]]; then # Copy from local dist/ info "Copying local dist/ to $APP_HOME ..." mkdir -p "$APP_HOME" cp -r "$LOCAL_DIST"/* "$APP_HOME/" pass "Local dist/ copied" else fail "No release URL set (AASD_RELEASE_URL) and no local dist/ found at $LOCAL_DIST" fi # ────────────────────────────────────────────── # Set ownership # ────────────────────────────────────────────── chown -R "$APP_USER:$APP_USER" "$APP_HOME" chmod 755 "$APP_HOME" pass "Ownership set to $APP_USER" # ────────────────────────────────────────────── # Create runtime directories # ────────────────────────────────────────────── mkdir -p "$APP_HOME/reports" "$APP_HOME/logs" chown "$APP_USER:$APP_USER" "$APP_HOME/reports" "$APP_HOME/logs" # ────────────────────────────────────────────── # Configure secrets (prompt if not set via env) # ────────────────────────────────────────────── AI_API_KEY="${AASD_AI_API_KEY:-}" BASE_URL="${AASD_BASE_URL:-}" ADMIN_PASS="${AASD_ADMIN_PASSWORD:-}" if [[ -z "$AI_API_KEY" ]]; then echo "" read -rp "Enter DeepSeek API key (or press Enter to skip AI reports): " AI_API_KEY fi if [[ -z "$BASE_URL" ]]; then echo "" read -rp "Enter public base URL (e.g. https://aasd.sechpoint.app): " BASE_URL fi if [[ -z "$ADMIN_PASS" ]]; then echo "" read -rp "Enter admin dashboard password: " ADMIN_PASS if [[ -z "$ADMIN_PASS" ]]; then ADMIN_PASS="$(tr -dc A-Za-z0-9 /dev/null | head -c 16 || echo "aasd$(date +%s)")" warn "Generated random password: $ADMIN_PASS" fi fi # Write config.yaml CONFIG_FILE="$APP_HOME/config.yaml" cat > "$CONFIG_FILE" < "$SYSTEMD_FILE" </dev/null | awk '{print $1}'):8080" echo " Binary: $APP_HOME/aasd" echo " Config: $CONFIG_FILE" echo " Service: aasd.service" echo "" echo " Admin login: sechpoint / ${ADMIN_PASS:-}" echo "" echo " Manage:" echo " sudo systemctl status aasd" echo " sudo journalctl -u aasd -f" echo ""