gitex2026/AttackSurface/install.sh
2026-04-24 20:11:23 +00:00

250 lines
9.5 KiB
Bash

#!/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/urandom 2>/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" <<CONFIGEOF
ai:
provider_url: "https://api.deepseek.com"
api_key: "${AI_API_KEY:-}"
model: "deepseek-chat"
server:
base_url: "${BASE_URL:-}"
admin:
username: "sechpoint"
password: "${ADMIN_PASS:-}"
CONFIGEOF
chown "$APP_USER:$APP_USER" "$CONFIG_FILE"
chmod 600 "$CONFIG_FILE"
pass "Configuration written to $CONFIG_FILE"
# ──────────────────────────────────────────────
# Create systemd service
# ──────────────────────────────────────────────
SYSTEMD_FILE="/etc/systemd/system/aasd.service"
cat > "$SYSTEMD_FILE" <<SERVICEEOF
[Unit]
Description=AASD — API Attack Surface Discovery
Documentation=https://github.com/valllabh/aasd
After=network.target
[Service]
Type=simple
User=$APP_USER
Group=$APP_USER
WorkingDirectory=$APP_HOME
ExecStart=$APP_HOME/aasd
Restart=on-failure
RestartSec=5
LimitNOFILE=4096
# Security hardening
NoNewPrivileges=true
ProtectSystem=full
ProtectHome=true
[Install]
WantedBy=multi-user.target
SERVICEEOF
chmod 644 "$SYSTEMD_FILE"
systemctl daemon-reload
systemctl enable aasd.service
pass "Systemd service created and enabled"
# ──────────────────────────────────────────────
# Start service
# ──────────────────────────────────────────────
info "Starting aasd.service..."
systemctl start aasd.service
sleep 2
if systemctl is-active --quiet aasd.service; then
pass "aasd.service is running"
else
warn "Service did not start — check: sudo journalctl -u aasd -n 50 --no-pager"
fi
# ──────────────────────────────────────────────
# Summary
# ──────────────────────────────────────────────
echo ""
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
echo -e "${GREEN} AASD installation complete${NC}"
echo -e "${GREEN}══════════════════════════════════════════════${NC}"
echo ""
echo " URL: http://$(hostname -I 2>/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:-<see config>}"
echo ""
echo " Manage:"
echo " sudo systemctl status aasd"
echo " sudo journalctl -u aasd -f"
echo ""