Quick Install Script for Vulnerability Management (InsightVM) in InsightGovCloud

Copy and paste this code block into a new file and follow the Linux installation instructions in Deploy Vulnerability Management (InsightVM) in InsightGovCloud.

Folder highlights Script content details the unattended Linux installation for Vulnerability Management (InsightVM) InsightGovCloud, including password policy checks and FIPS mode configuration steps.

Copy
 
#!/bin/bash
set -euo pipefail
#
# FedRAMP Linux Quick Start Script (v0.98)
# - Security: downloads SHA-512 checksum and verifies installer before execution.
# - Collects required user inputs and enforces a basic password policy (min 8 chars, mixed case, digit, special)
# - Ease of use: uses unattended install with direct cli call (not response.vars)
# - Performance: polling loop for log markers
# - Compatibility: avoids "bash -lc" login shell behavior; uses "bash -c".
# - Checks for Federal or FIPS = false
#
# - Verbose + colorized checks for existing install and FedRAMP/FIPS log markers
# - Existing install guard verifies: RNG (advisory), process running, log markers, CustomEnvironment.properties; exits success if compliant, fails otherwise
# - Uses /tmp for downloads (installer + checksum)
 
# --- Colors ---
C_RESET="\033[0m"
C_BOLD="\033[1m"
C_BLUE="\033[1;34m"
C_GRAY="\033[90m"
C_GREEN="\033[32m"
C_YELLOW="\033[33m"
C_RED="\033[31m"
 
ok()   { echo -e "${C_GREEN}[SUCCESS]${C_RESET} $*"; }
warn() { echo -e "${C_YELLOW}[WARNING]${C_RESET} $*"; }
fail() { echo -e "${C_RED}[ERROR]${C_RESET} $*"; }
info() { echo -e "${C_BLUE}[INFO]${C_RESET} $*"; }
 
print_step() {
  echo -e "\n${C_BLUE}${C_BOLD}==> $1${C_RESET}"
}
 
run_cmd() {
  echo -e "${C_GRAY}$ $*${C_RESET}"
  bash -c "$@"
}
 
have() { command -v "$1" >/dev/null 2>&1; }
 
# --- Password complexity ---
pw_error() { echo -e "${C_RED}Password policy error:${C_RESET} $1" >&2; }
 
check_password_complexity() {
  local password="$1"
  local username="${2:-}"
  local min_len=8
 
  info "Password policy: >=${min_len} chars, upper/lower/digit/special, no whitespace, no username substring"
 
  if (( ${#password} < min_len )); then
    pw_error "Password must be at least ${min_len} characters."
    return 1
  fi
  if grep -qE '[[:space:]]' <<<"$password"; then
    pw_error "Password must not contain whitespace."
    return 1
  fi
  if ! grep -qE '[A-Z]' <<<"$password"; then
    pw_error "Password must contain at least one uppercase letter."
    return 1
  fi
  if ! grep -qE '[a-z]' <<<"$password"; then
    pw_error "Password must contain at least one lowercase letter."
    return 1
  fi
  if ! grep -qE '[0-9]' <<<"$password"; then
    pw_error "Password must contain at least one digit."
    return 1
  fi
  if ! grep -qE '[^A-Za-z0-9]' <<<"$password"; then
    pw_error "Password must contain at least one special character."
    return 1
  fi
 
  if [[ -n "$username" ]]; then
    shopt -s nocasematch
    if [[ "$password" == *"$username"* ]]; then
      shopt -u nocasematch
      pw_error "Password must not contain the username."
      return 1
    fi
    shopt -u nocasematch
  fi
 
  ok "Password meets complexity requirements."
  return 0
}
 
# --- RNG helpers ---
rng_service_candidates=("rngd" "rng-tools" "rng-tools-debian")
 
find_rng_service() {
  for s in "${rng_service_candidates[@]}"; do
    if systemctl list-unit-files --type=service 2>/dev/null | awk '{print $1}' | grep -qx "${s}.service"; then
      echo "${s}.service"
      return 0
    fi
  done
  if have rngd; then
    echo "rngd.service"
    return 0
  fi
  return 1
}
 
# --- SELinux helpers ---
selinux_is_enabled() {
  if have selinuxenabled; then
    selinuxenabled && return 0 || return 1
  fi
  if have getenforce; then
    [[ "$(getenforce 2>/dev/null || echo Disabled)" != "Disabled" ]] && return 0 || return 1
  fi
  return 1
}
 
# --- Process check (existing install) ---
# Must match cases like:
# root 4495 ... SCREEN -d -m -S nexposeconsole /opt/rapid7/nexpose/nsc/nsc.sh
nexpose_process_is_running() {
  pgrep -fa "/opt/rapid7/nexpose/nsc/nsc\.sh" >/dev/null 2>&1
}
 
get_nexpose_process_line() {
  # Return one representative line if present, formatted without the leading username
  # e.g. "4495 SCREEN -d -m -S nexposeconsole /opt/rapid7/nexpose/nsc/nsc.sh"
  pgrep -fa "/opt/rapid7/nexpose/nsc/nsc\.sh" 2>/dev/null | head -n 1 | awk '{ $1=$1; print }' || true
}
 
# --- Existing install detection (quiet) ---
nexpose_is_installed_quiet() {
  [[ -d /opt/rapid7/nexpose/nsc ]] || return 1
  [[ -f /opt/rapid7/nexpose/nsc/nsc.sh ]] || return 1
  return 0
}
 
verify_existing_installation() {
  print_step "Existing install detected. Verifying FedRAMP/FIPS compliance..."
  ok "Existing install detected. Verifying FedRAMP/FIPS compliance..."
 
  local LOG="/opt/rapid7/nexpose/nsc/logs/nsc.log"
  local CUSTOM_ENV="/opt/rapid7/nexpose/nsc/CustomEnvironment.properties"
 
  local MARK_FED_TRUE="Console is a Federal instance = true"
  local MARK_FIPS_TRUE="Console FIPS Mode switched on = true"
  local MARK_FED_FALSE="Console is a Federal instance = false"
  local MARK_FIPS_FALSE="Console FIPS Mode switched on = false"
 
  local log_ok=0
  local env_ok=0
  local rng_ok=0
  local proc_ok=0
 
  # Process (required) - print first on success
  if nexpose_process_is_running; then
    local pline
    pline="$(get_nexpose_process_line)"
    if [[ -n "$pline" ]]; then
      ok "Process running: ${pline}"
    else
      ok "Process running: /opt/rapid7/nexpose/nsc/nsc.sh"
    fi
    proc_ok=1
  fi
 
  # RNG (advisory)
  if RNG_SVC="$(find_rng_service 2>/dev/null)"; then
    if systemctl is-active --quiet "$RNG_SVC"; then
      ok "RNG active: $RNG_SVC"
      rng_ok=1
    else
      warn "RNG installed but inactive: $RNG_SVC"
    fi
  else
    warn "No RNG service detected."
  fi
 
  # Logs
  if [[ -f "$LOG" ]]; then
    if sudo grep -qF "$MARK_FED_FALSE" "$LOG" || sudo grep -qF "$MARK_FIPS_FALSE" "$LOG"; then
      fail "Detected explicit non-compliant log markers (false)."
      fail "Searched for false markers:"
      fail " - $MARK_FED_FALSE"
      fail " - $MARK_FIPS_FALSE"
      echo -e "${C_GRAY}"
      sudo grep -nE "Console is a Federal instance = |Console FIPS Mode switched on = " "$LOG" | tail -n 100 || true
      echo -e "${C_RESET}"
      # Continue to final failure summary below
    else
      if sudo grep -qF "$MARK_FED_TRUE" "$LOG" && sudo grep -qF "$MARK_FIPS_TRUE" "$LOG"; then
        ok "Log markers verified (Federal=true, FIPS=true). Sample:"
        log_ok=1
      else
        fail "FedRAMP/FIPS log verification failed."
        fail "Search of logs did not find:"
        if sudo grep -qF "$MARK_FED_TRUE" "$LOG"; then
          fail " - ${MARK_FED_TRUE}. (Found)"
        else
          fail " - ${MARK_FED_TRUE}. (Not found)"
        fi
        if sudo grep -qF "$MARK_FIPS_TRUE" "$LOG"; then
          fail " - ${MARK_FIPS_TRUE}. (Found)"
        else
          fail " - ${MARK_FIPS_TRUE}. (Not found)"
        fi
      fi
    fi
  else
    fail "Log file not found."
  fi
 
  # CustomEnvironment.properties
  if [[ -f "$CUSTOM_ENV" ]]; then
    local miss=0
    if ! grep -q "^com\.rapid7\.federal=true" "$CUSTOM_ENV"; then
      fail "Missing/incorrect property: com.rapid7.federal=true"
      miss=1
    fi
    if ! grep -q "^fipsMode=1" "$CUSTOM_ENV"; then
      fail "Missing/incorrect property: fipsMode=1"
      miss=1
    fi
    if (( miss == 0 )); then
      env_ok=1
    fi
  else
    fail "CustomEnvironment.properties not found."
  fi
 
  # Process requirement failure detail
  if (( proc_ok != 1 )); then
    fail "Process check failed: could not find running nsc.sh process."
    info "Matching processes (if any):"
    echo -e "${C_GRAY}"
    ps -ef | grep -E "/opt/rapid7/nexpose/nsc/nsc\.sh|nexposeconsole|nsc\.sh" | grep -v grep || true
    echo -e "${C_RESET}"
  fi
 
  if (( log_ok == 1 && env_ok == 1 && proc_ok == 1 )); then
    ok "Existing installation is Federal + FIPS compliant. No changes made. Exiting."
    if (( rng_ok != 1 )); then
      warn "RNG not active; FIPS mode may not operate correctly."
    fi
    exit 0
  fi
 
  fail "Existing installation detected but not compliant. Aborting to avoid overwriting."
  warn "Next Steps:"
  warn " - Check that RNG is installed and running"
  warn " - Ensure FIPS and Federal instance is configured in: ${CUSTOM_ENV}"
  warn " - Complete the above checks, restart the daemon, and re-run this script."
  warn " - Logs: ${LOG}"
  exit 1
}
 
# --- Existing installation guard (quiet; no pre-check output) ---
if nexpose_is_installed_quiet; then
  verify_existing_installation
fi
 
# --- Collect user variables for unattended install ---
print_step "Collecting user variables for installer..."
read -rp "Enter company name: " NX_NAME
read -rp "Enter first name: " FIRST
read -rp "Enter last name: " LAST
read -rp "Enter console admin username: " NX_USERNAME
 
while true; do
  read -rsp "Enter console admin password: " NX_PASSWORD
  echo
  read -rsp "Re-enter console admin password: " NX_PASSWORD2
  echo
 
  if [[ "$NX_PASSWORD" != "$NX_PASSWORD2" ]]; then
    fail "Passwords do not match. Try again."
    continue
  fi
 
  if ! check_password_complexity "$NX_PASSWORD" "$NX_USERNAME"; then
    fail "Password does not meet complexity requirements. Try again."
    continue
  fi
 
  ok "Password accepted."
  break
done
 
# --- Package manager detection ---
PKG="unknown"
if have dnf; then
  PKG="dnf"
elif have apt-get; then
  PKG="apt"
elif have yum; then
  PKG="dnf"
fi
 
if [[ "$PKG" == "unknown" ]]; then
  fail "Unsupported distro. Need dnf or apt-get."
  exit 1
fi
ok "Detected package manager: $PKG"
 
# --- Update and install prerequisites ---
print_step "Updating system packages..."
if [[ "$PKG" == "dnf" ]]; then
  run_cmd "sudo dnf -y update"
elif [[ "$PKG" == "apt" ]]; then
  run_cmd "sudo apt-get update -y"
fi
ok "System update complete."
 
print_step "Installing prerequisite packages (RNG, SELinux tools when available, curl)..."
if [[ "$PKG" == "dnf" ]]; then
  run_cmd "sudo dnf -y install rng-tools policycoreutils policycoreutils-python-utils curl"
elif [[ "$PKG" == "apt" ]]; then
  run_cmd "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y curl"
  run_cmd "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y policycoreutils || true"
  run_cmd "sudo DEBIAN_FRONTEND=noninteractive apt-get install -y rng-tools5 || sudo DEBIAN_FRONTEND=noninteractive apt-get install -y rng-tools || true"
fi
ok "Prerequisites installed."
 
print_step "Enabling and starting RNG daemon..."
if RNG_SVC="$(find_rng_service 2>/dev/null)"; then
  run_cmd "sudo systemctl enable --now ${RNG_SVC}"
  if systemctl is-active --quiet "$RNG_SVC"; then
    ok "RNG active: $RNG_SVC"
  else
    warn "RNG installed but not active yet: $RNG_SVC"
  fi
else
  warn "Could not detect rng daemon. FIPS mode may be impacted. Install will continue."
fi
 
# --- Directory setup ---
print_step "Creating /opt/rapid7/nexpose directory..."
run_cmd "sudo install -d -m 755 /opt/rapid7/nexpose"
run_cmd "sudo chown -R root:root /opt/rapid7"
ok "Directory prepared: /opt/rapid7/nexpose"
 
# --- SELinux pre-config (only if SELinux is enabled) ---
if selinux_is_enabled && have semanage; then
  print_step "SELinux detected: labeling Rapid7 directories and opening TCP 3780..."
  run_cmd "sudo semanage fcontext -a -t usr_t '/opt/rapid7(/.*)?' || true"
  run_cmd "sudo semanage fcontext -a -t bin_t '/opt/rapid7/nexpose(/.*)?' || true"
  run_cmd "sudo semanage fcontext -a -t var_log_t '/opt/rapid7/nexpose/nsc/logs(/.*)?' || true"
  run_cmd "sudo semanage port -a -t http_port_t -p tcp 3780 2>/dev/null || sudo semanage port -m -t http_port_t -p tcp 3780 || true"
  print_step "Applying SELinux labels..."
  run_cmd "sudo restorecon -RF /opt/rapid7 || true"
  ok "SELinux configuration applied (best-effort)."
else
  warn "SELinux not enabled/detected or semanage missing. Skipping SELinux steps."
fi
 
# --- Download installer and verify checksum (in /tmp) ---
INSTALLER="/tmp/Rapid7Setup-Linux64.bin"
CHECKSUM_FILE="/tmp/Rapid7Setup-Linux64.bin.sha512sum"
 
print_step "Downloading Rapid7 Vulnerability Management (InsightVM) installer and checksum to /tmp..."
run_cmd "sudo curl -fL https://download2.rapid7.com/download/InsightVM/Rapid7Setup-Linux64.bin -o '${INSTALLER}'"
run_cmd "sudo curl -fL https://download2.rapid7.com/download/InsightVM/Rapid7Setup-Linux64.bin.sha512sum -o '${CHECKSUM_FILE}'"
ok "Downloads complete."
 
print_step "Verifying installer checksum..."
run_cmd "cd /tmp && sha512sum -c Rapid7Setup-Linux64.bin.sha512sum"
ok "Checksum verification successful."
 
run_cmd "sudo chmod +x '${INSTALLER}'"
ok "Installer marked executable."
 
# --- Run installer with -V args (no response.vars), avoid $Boolean expansion under set -u ---
print_step "Running Vulnerability Management (InsightVM) installer..."
warn "Password is supplied via command-line arguments; it may be visible to other processes via ps during install."
 
INSTALL_CMD=(
  sudo "$INSTALLER" -q -overwrite
  "-Vfirstname=$FIRST" "-Vlastname=$LAST"
  "-Vcompany=$NX_NAME" "-Vusername=$NX_USERNAME"
  "-Vpassword1=$NX_PASSWORD" "-Vpassword2=$NX_PASSWORD"
  '-Vsys.component.typical$Boolean=true'
  '-Vsys.component.engine$Boolean=false'
  '-VcommunicationDirectionChoice$Integer=1'
  '-VrequirePasswordChange$Boolean=true'
  '-VinitService$Boolean=true'
)
 
echo -e "${C_GRAY}$ sudo $INSTALLER -q -overwrite -Vfirstname=... -Vlastname=... -Vcompany=... -Vusername=... -Vpassword1=REDACTED -Vpassword2=REDACTED ...${C_RESET}"
 
if "${INSTALL_CMD[@]}"; then
  ok "Installer completed successfully."
else
  fail "Installer returned a non-zero exit code."
  exit 1
fi
 
# --- FIPS & FedRAMP configuration ---
print_step "Enabling InsightGovCloud and FIPS mode..."
run_cmd "sudo bash -c \"cat > /opt/rapid7/nexpose/nsc/CustomEnvironment.properties <<'EOF'
fipsMode=1
com.rapid7.federal=true
EOF
\""
ok "CustomEnvironment.properties written."
 
# Re-apply labels if SELinux is present
if selinux_is_enabled; then
  print_step "Re-applying SELinux labels..."
  run_cmd "sudo restorecon -RF /opt/rapid7/nexpose || true"
  ok "SELinux labels re-applied."
else
  warn "SELinux not enabled; skipping restorecon."
fi
 
# --- Start console service ---
print_step "Reloading systemd and enabling Nexpose Console..."
run_cmd "sudo systemctl daemon-reload || true"
run_cmd "sudo systemctl enable --now nexposeconsole.service || true"
 
# --- Verify console successfully starts with FIPS/Federal ---
print_step "Verifying FIPS/Federal mode in logs (polling)..."
LOG="/opt/rapid7/nexpose/nsc/logs/nsc.log"
MAX_WAIT_SECONDS=180
POLL_INTERVAL=10
ELAPSED=0
 
MARK_FED_TRUE="Console is a Federal instance = true"
MARK_FIPS_TRUE="Console FIPS Mode switched on = true"
MARK_FED_FALSE="Console is a Federal instance = false"
MARK_FIPS_FALSE="Console FIPS Mode switched on = false"
 
while (( ELAPSED < MAX_WAIT_SECONDS )); do
  if [[ -f "$LOG" ]]; then
    if sudo grep -qF "$MARK_FED_FALSE" "$LOG" || sudo grep -qF "$MARK_FIPS_FALSE" "$LOG"; then
      fail "Detected explicit false markers in log. Aborting."
      echo -e "${C_GRAY}"
      sudo grep -nE "Console is a Federal instance = |Console FIPS Mode switched on = " "$LOG" | tail -n 100 || true
      echo -e "${C_RESET}"
      exit 1
    fi
 
    if sudo grep -qF "$MARK_FED_TRUE" "$LOG" && sudo grep -qF "$MARK_FIPS_TRUE" "$LOG"; then
      ok "Verified: Federal + FIPS active."
      exit 0
    fi
  fi
 
  sleep "$POLL_INTERVAL"
  ELAPSED=$((ELAPSED + POLL_INTERVAL))
done
 
fail "Did not detect both Federal=true and FIPS=true within ${MAX_WAIT_SECONDS}s."
warn "Suggested checks:"
warn " - sudo systemctl status nexposeconsole.service"
warn " - sudo tail -n 200 $LOG"
exit 1