#!/bin/bash set -euo pipefail ZARYA_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)" source "${ZARYA_DIR}/lib/common.sh" TARGET_IP="" ALIAS="" PORT="${SRV_DEFAULT_PORT:-1488}" USER_NAME="${SRV_DEFAULT_USER:-atlas}" TCP_PORTS="${SRV_DEFAULT_TCP_PORTS:-1488 80 443}" UDP_PORTS="${SRV_DEFAULT_UDP_PORTS:-51820}" UFW_IN="${SRV_UFW_INCOMING:-deny}" UFW_OUT="${SRV_UFW_OUTGOING:-allow}" UFW_FWD="${SRV_UFW_FORWARD:-deny}" UFW_APP="${SRV_UFW_APPLICATION:-skip}" ENABLE_BBR="${SRV_ENABLE_BBR:-true}" DISABLE_IPV6="${SRV_DISABLE_IPV6:-true}" DISABLE_ICMP="${SRV_DISABLE_ICMP:-false}" VERIFY_GATE="false" while [[ $# -gt 0 ]]; do case "$1" in --verify|--test|-v) VERIFY_GATE="true" shift ;; --port) PORT="$2" shift 2 ;; --user) USER_NAME="$2" shift 2 ;; --tcp) TCP_PORTS="$2" shift 2 ;; --udp) UDP_PORTS="$2" shift 2 ;; --disable-icmp) DISABLE_ICMP="true" shift ;; --enable-icmp) DISABLE_ICMP="false" shift ;; --disable-ipv6) DISABLE_IPV6="true" shift ;; --enable-ipv6) DISABLE_IPV6="false" shift ;; --no-bbr) ENABLE_BBR="false" shift ;; --help|-h) echo "Использование: z init vps [ALIAS] [--verify] [--port N] [--user NAME] [--tcp 'PORTS'] [--udp 'PORTS'] [--disable-icmp] [--disable-ipv6] [--no-bbr]" exit 0 ;; *) if [[ -z "${TARGET_IP}" ]]; then TARGET_IP="$1" elif [[ -z "${ALIAS}" ]]; then ALIAS="$1" fi shift ;; esac done if [[ -z "${TARGET_IP}" ]]; then log_err "IP-адрес целевого сервера обязателен. Введите 'z init vps --help'." exit 1 fi SSH_CONFIG="${HOME}/.ssh/config" if [[ -z "${ALIAS}" ]]; then CURRENT_MAX=$(grep -oP 'Host\s+n\K[0-9]+(?=\.srv)' "${SSH_CONFIG}" 2>/dev/null | sort -n | tail -n1 || true) CURRENT_MAX="${CURRENT_MAX:-0}" NEXT_NUM=$(( CURRENT_MAX + 1 )) ALIAS="n${NEXT_NUM}.srv" fi if [[ ! -f "${RAM_KEY}" ]] || [[ ! -s "${RAM_KEY}" ]]; then log_err "Аппаратный ключ в RAM отсутствует (${RAM_KEY}). Выполните 'z login'." exit 1 fi PUBKEY_B64=$(ssh-keygen -y -f "${RAM_KEY}" | base64 -w0) ssh-keygen -R "${TARGET_IP}" >/dev/null 2>&1 || true ssh-keygen -R "${ALIAS}" >/dev/null 2>&1 || true ssh-keygen -R "[${TARGET_IP}]:${PORT}" >/dev/null 2>&1 || true ssh-keygen -R "[${TARGET_IP}]:22" >/dev/null 2>&1 || true log_info "Инициализация ноды ${ALIAS} (${TARGET_IP}:${PORT})..." ssh -o StrictHostKeyChecking=accept-new -p 22 "root@${TARGET_IP}" \ "env BOOTSTRAP_USER='${USER_NAME}' \ BOOTSTRAP_PORT='${PORT}' \ BOOTSTRAP_PUBKEY_B64='${PUBKEY_B64}' \ BOOTSTRAP_TCP_PORTS='${TCP_PORTS}' \ BOOTSTRAP_UDP_PORTS='${UDP_PORTS}' \ BOOTSTRAP_UFW_IN='${UFW_IN}' \ BOOTSTRAP_UFW_OUT='${UFW_OUT}' \ BOOTSTRAP_UFW_FWD='${UFW_FWD}' \ BOOTSTRAP_UFW_APP='${UFW_APP}' \ BOOTSTRAP_ENABLE_BBR='${ENABLE_BBR}' \ BOOTSTRAP_DISABLE_IPV6='${DISABLE_IPV6}' \ BOOTSTRAP_DISABLE_ICMP='${DISABLE_ICMP}' \ bash -s" < "${ZARYA_DIR}/templates/vps-bootstrap.sh" ssh_register_node "${ALIAS}" "${TARGET_IP}" if [[ "${VERIFY_GATE}" == "true" ]]; then log_warn "Включен режим ручного подтверждения." echo "Откройте соседний терминал и выполните: ssh ${ALIAS}" read -r -p "Подключение успешно? [y/N]: " CONFIRM if [[ "${CONFIRM}" != "y" && "${CONFIRM}" != "Y" ]]; then log_err "Подтверждение отклонено оператором. Откат конфигурации..." ssh -o ConnectTimeout=10 -p "${PORT}" -i "${RAM_KEY}" "${USER_NAME}@${TARGET_IP}" "sudo ufw disable && sudo sed -i -E 's/^Port .*/Port 22/' /etc/ssh/sshd_config && sudo systemctl restart ssh.service" || true log_warn "Откат завершен: порт 22 возвращен, UFW выключен." exit 1 fi fi log_info "Автоматическая валидация ноды ${ALIAS}..." if ! ssh -o ConnectTimeout=5 -o BatchMode=yes "${ALIAS}" "hostname" >/dev/null 2>&1; then log_err "Валидация FIDO2-ключа для ${ALIAS} провалена." echo "Диагностика SSH-соединения:" ssh -v -o ConnectTimeout=5 -o BatchMode=yes "${ALIAS}" 2>&1 | grep -E 'Offering|Authenticat|Denied|Connection' || true exit 1 fi log_ok "Сервер ${ALIAS} (${TARGET_IP}:${PORT}) успешно инициализирован и подтвержден."