diff --git a/bin/zarya b/bin/zarya index 8ea1d52..5ce1031 100755 --- a/bin/zarya +++ b/bin/zarya @@ -26,6 +26,7 @@ case "${SUBCMD}" in pack) exec "${ZARYA_DIR}/cmd/pack.sh" "$@" ;; reset|nuke) exec "${ZARYA_DIR}/layers/reset.sh" "$@" ;; gc) exec "${ZARYA_DIR}/layers/gc.sh" "$@" ;; + srv-init|vps-init) exec "${ZARYA_DIR}/cmd/vps-init.sh" "$@" ;; help|--help|-h) cat < Плейбуки Ansible (01, 02) z a [-auto-approve] OpenTofu apply в RAM-изоляции + z srv-init [ALIAS] [FLAGS] Day-0 удаленный бутстрап ноды .srv в 1 клик Телеметрия и LLM: z snap Снятие аудита в state/snapshots/ z pack [all|atlas|code|state] Сборка контекстов Repomix для LLM diff --git a/cmd/vps-init.sh b/cmd/vps-init.sh new file mode 100755 index 0000000..f0d14c2 --- /dev/null +++ b/cmd/vps-init.sh @@ -0,0 +1,182 @@ +#!/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" + +PUBKEY="ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGY8TEByHoDFNsy18VG6BJALc8HUYeoKZz2PeKMyKMND atlas@core" + +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 srv-init [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 srv-init --help'." + exit 1 +fi + +if [[ -z "${ALIAS}" ]]; then + LAST_OCTET="${TARGET_IP##*.}" + ALIAS="n${LAST_OCTET}.srv" +fi + +log_info "Инициализация ноды ${ALIAS} (${TARGET_IP}:${PORT})..." + +ssh -o StrictHostKeyChecking=accept-new -p 22 "root@${TARGET_IP}" "bash -s" << REMOTE_EOF +set -euo pipefail + +id -u "${USER_NAME}" &>/dev/null || useradd -m -s /bin/bash -G sudo "${USER_NAME}" +mkdir -p "/home/${USER_NAME}/.ssh" +echo "${PUBKEY}" > "/home/${USER_NAME}/.ssh/authorized_keys" +chmod 700 "/home/${USER_NAME}/.ssh" +chmod 600 "/home/${USER_NAME}/.ssh/authorized_keys" +chown -R "${USER_NAME}:${USER_NAME}" "/home/${USER_NAME}/.ssh" + +echo "${USER_NAME} ALL=(ALL) NOPASSWD:ALL" > "/etc/sudoers.d/${USER_NAME}" +chmod 440 "/etc/sudoers.d/${USER_NAME}" + +if systemctl is-active --quiet ssh.socket 2>/dev/null; then + systemctl disable --now ssh.socket +fi + +rm -rf /etc/ssh/sshd_config.d/*.conf +cat << SSHEOF > /etc/ssh/sshd_config +Port ${PORT} +PasswordAuthentication no +KbdInteractiveAuthentication no +PermitRootLogin prohibit-password +PubkeyAuthentication yes +X11Forwarding no +AcceptEnv LANG LC_* +Subsystem sftp /usr/lib/openssh/sftp-server +SSHEOF + +systemctl enable --now ssh.service +systemctl restart ssh.service + +which ufw >/dev/null 2>&1 || (DEBIAN_FRONTEND=noninteractive apt-get update -y && DEBIAN_FRONTEND=noninteractive apt-get install -y ufw) +ufw --force reset +ufw default ${UFW_IN} incoming +ufw default ${UFW_OUT} outgoing +ufw default ${UFW_FWD} forward +sed -i -E 's/^DEFAULT_APPLICATION_POLICY=.*/DEFAULT_APPLICATION_POLICY="'${UFW_APP}'"/' /etc/default/ufw || true + +if [[ "${DISABLE_IPV6}" == "true" ]]; then + sed -i -E 's/^IPV6=.*/IPV6=no/' /etc/default/ufw || true +fi + +for p in ${TCP_PORTS}; do + ufw allow "\${p}/tcp" +done + +for p in ${UDP_PORTS}; do + ufw allow "\${p}/udp" +done + +ufw --force enable + +rm -f /etc/sysctl.d/99-atlas.conf +touch /etc/sysctl.d/99-atlas.conf + +if [[ "${ENABLE_BBR}" == "true" ]]; then + printf "net.core.default_qdisc = fq\nnet.ipv4.tcp_congestion_control = bbr\n" >> /etc/sysctl.d/99-atlas.conf +fi + +if [[ "${DISABLE_IPV6}" == "true" ]]; then + printf "net.ipv6.conf.all.disable_ipv6 = 1\nnet.ipv6.conf.default.disable_ipv6 = 1\nnet.ipv6.conf.lo.disable_ipv6 = 1\n" >> /etc/sysctl.d/99-atlas.conf +fi + +if [[ "${DISABLE_ICMP}" == "true" ]]; then + printf "net.ipv4.icmp_echo_ignore_all = 1\n" >> /etc/sysctl.d/99-atlas.conf +fi + +sysctl --system >/dev/null 2>&1 || true +REMOTE_EOF + +SSH_CONFIG="${HOME}/.ssh/config" +if ! grep -q "Host.*${ALIAS}" "${SSH_CONFIG}" 2>/dev/null; then + printf "\nHost %s\n Hostname %s\n" "${ALIAS}" "${TARGET_IP}" >> "${SSH_CONFIG}" +fi + +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}..." +ssh -o ConnectTimeout=5 "${ALIAS}" "hostname" +log_ok "Сервер ${ALIAS} успешно инициализирован и верифицирован." \ No newline at end of file diff --git a/config.env b/config.env index 9cfdc31..f22f0cc 100644 --- a/config.env +++ b/config.env @@ -1,6 +1,3 @@ -#!/bin/bash -# Atlas C2 Configuration SSOT - KDBX_PATH="${HOME}/Projects/atlas-secrets.kdbx" RAM_CACHE="/dev/shm/.atlas_secrets_cache" RAM_KEY="/dev/shm/.atlas_core" @@ -12,3 +9,17 @@ GIT_HOST="git.svo88.space" PVE_ENDPOINT="https://192.168.1.177:8006/" DEFAULT_SESSION_TTL=1 + +SRV_DEFAULT_PORT=1488 +SRV_DEFAULT_USER="atlas" +SRV_DEFAULT_TCP_PORTS="1488 80 443" +SRV_DEFAULT_UDP_PORTS="51820" + +SRV_UFW_INCOMING="deny" +SRV_UFW_OUTGOING="allow" +SRV_UFW_FORWARD="deny" +SRV_UFW_APPLICATION="skip" + +SRV_ENABLE_BBR="true" +SRV_DISABLE_IPV6="true" +SRV_DISABLE_ICMP="false" \ No newline at end of file