From 8dbd97238a2c864984acdc7a6e6ade93fa52876b Mon Sep 17 00:00:00 2001 From: zuevav Date: Thu, 24 Sep 2026 13:15:49 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9E=D0=B1=D1=80=D0=B0=D0=B7:=20=D1=83=D1=87?= =?UTF-8?q?=D1=91=D1=82=D0=BD=D1=8B=D0=B5=20=D0=B7=D0=B0=D0=BF=D0=B8=D1=81?= =?UTF-8?q?=D0=B8=20=D0=9E=D0=A1=20root=5Fbj=20(sudo)=20=D0=B8=20user=5Fbj?= =?UTF-8?q?=20=D0=B7=D0=B0=D0=B4=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D0=BC=D0=B0=D1=82=D0=B8=D1=87=D0=B5=D1=81?= =?UTF-8?q?=D0=BA=D0=B8,=20=D0=BF=D0=B0=D1=80=D0=BE=D0=BB=D0=B8=20=D0=B3?= =?UTF-8?q?=D0=B5=D0=BD=D0=B5=D1=80=D0=B8=D1=80=D1=83=D1=8E=D1=82=D1=81?= =?UTF-8?q?=D1=8F=20=D0=BF=D1=80=D0=B8=20=D0=BF=D0=B5=D1=80=D0=B2=D0=BE?= =?UTF-8?q?=D0=B9=20=D0=B7=D0=B0=D0=B3=D1=80=D1=83=D0=B7=D0=BA=D0=B5=20(?= =?UTF-8?q?=D0=BC=D0=BE=D0=B6=D0=BD=D0=BE=20=D0=B2=D0=B2=D0=B5=D1=81=D1=82?= =?UTF-8?q?=D0=B8=20=D1=81=D0=B2=D0=BE=D0=B8)=20=D0=B8=20=D0=BF=D0=BE?= =?UTF-8?q?=D0=BA=D0=B0=D0=B7=D1=8B=D0=B2=D0=B0=D1=8E=D1=82=D1=81=D1=8F=20?= =?UTF-8?q?=D0=BE=D0=B4=D0=B8=D0=BD=20=D1=80=D0=B0=D0=B7=20=D0=BD=D0=B0=20?= =?UTF-8?q?=D0=B8=D1=82=D0=BE=D0=B3=D0=BE=D0=B2=D0=BE=D0=BC=20=D1=8D=D0=BA?= =?UTF-8?q?=D1=80=D0=B0=D0=BD=D0=B5;=20firstboot=20=D0=BD=D0=B0=20bash=20(?= =?UTF-8?q?read=20-t/-p)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- deploy/iso/bj-firstboot | 47 +++++++++++++++++++++++++++++++++--- deploy/iso/preseed.cfg | 10 ++++++-- deploy/linux/sbin/bj-welcome | 8 ++++-- 3 files changed, 57 insertions(+), 8 deletions(-) diff --git a/deploy/iso/bj-firstboot b/deploy/iso/bj-firstboot index 4b13531..a5fee8a 100755 --- a/deploy/iso/bj-firstboot +++ b/deploy/iso/bj-firstboot @@ -1,4 +1,4 @@ -#!/bin/sh +#!/bin/bash # Первая загрузка сервера, установленного с образа Bridge&Join. Спрашивает ключ продукта на консоли; # без ключа ставит ядро bj с образа (/var/lib/bj/bundle), а ключ вводится в браузере на первой # странице настройки. Пока bj не установлен, вопрос повторяется при каждой загрузке (с таймаутом), @@ -15,6 +15,41 @@ finish() { [ -x /usr/local/sbin/bj-welcome ] && /usr/local/sbin/bj-welcome } urls() { ip -4 -o addr show scope global 2>/dev/null | awk '{split($4,a,"/"); printf " http://%s:8080%s\n", a[1], "'"$1"'"}'; } +ACC_DONE=/var/lib/bj/.bj/os-accounts-set +ACCOUNTS="" +genpw() { tr -dc 'ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnpqrstuvwxyz23456789' < /dev/urandom | head -c 12 | sed 's/\(....\)\(....\)/\1-\2-/'; } +askpw() { # $1 — логин, $2 — предложенный пароль; печатает итоговый пароль + while true; do + printf ' Пароль для %s: %s\n Enter — принять, или введите свой (не короче 10 символов): ' "$1" "$2" > /dev/tty + stty -echo < /dev/tty; read -r P1 < /dev/tty; stty echo < /dev/tty; printf '\n' > /dev/tty + [ -z "$P1" ] && { printf '%s' "$2"; return; } + [ ${#P1} -lt 10 ] && { printf ' Короче 10 символов, ещё раз.\n' > /dev/tty; continue; } + printf ' Повторите: ' > /dev/tty; stty -echo < /dev/tty; read -r P2 < /dev/tty; stty echo < /dev/tty; printf '\n' > /dev/tty + [ "$P1" = "$P2" ] && { printf '%s' "$P1"; return; } + printf ' Не совпало, ещё раз.\n' > /dev/tty + done +} +setup_accounts() { + [ -f "$ACC_DONE" ] && return + id user_bj >/dev/null 2>&1 || useradd -m -s /bin/bash -c "Пользователь сервера bj" -G adm,systemd-journal user_bj + id root_bj >/dev/null 2>&1 && usermod -aG sudo root_bj + clear + printf '\n Bridge&Join: учётные записи сервера\n ────────────────────────────────────────────────────────────\n' + printf ' root_bj — администратор сервера (команды через sudo)\n user_bj — обычный вход (журналы, без прав администратора)\n' + printf ' Работа с bj — в браузере; эти учётные записи нужны для обслуживания ОС.\n\n' + PA=$(askpw root_bj "$(genpw)"); PU=$(askpw user_bj "$(genpw)") + printf 'root_bj:%s\nuser_bj:%s\n' "$PA" "$PU" | chpasswd + mkdir -p "$(dirname "$ACC_DONE")" && date -Iseconds > "$ACC_DONE" + ACCOUNTS=$(printf ' root_bj (администратор, sudo) пароль: %s\n user_bj (обычный вход) пароль: %s\n' "$PA" "$PU") + unset PA PU +} +show_accounts() { + [ -n "$ACCOUNTS" ] || return + printf '\n ┌── ЗАПИШИТЕ: учётные записи сервера ──────────────────────────┐\n%s\n' "$ACCOUNTS" + printf ' └── пароли нигде не сохранены и больше не будут показаны ──────┘\n' + printf ' Сменить пароль: passwd (под своей учётной записью)\n\n' +} +setup_accounts clear printf '\n Bridge&Join: установка на сервер\n ────────────────────────────────────────────────────────────\n' printf ' Debian установлен. Осталось установить bj.\n\n' @@ -42,19 +77,23 @@ while true; do if /usr/local/sbin/bj-installer install --bundle "$BUNDLE" --server "$SERVER" --channel "$CHANNEL"; then finish printf '\n Ключ продукта спросит первая страница настройки в браузере:\n'; urls /first-run; printf '\n' - read -t 60 -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ || true + show_accounts + read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ || true exit 0 fi + show_accounts printf '\n Установка с образа не завершилась. Подробности выше; повторить:\n sudo bj-installer install --bundle %s\n\n' "$BUNDLE" sleep 5; exit 0 fi + show_accounts printf '\n Установка bj отложена. Вопрос повторится при следующей загрузке; вручную:\n sudo bj-installer install --code КЛЮЧ-ПРОДУКТА\n\n' - sleep 3 + read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ || true exit 0 fi if /usr/local/sbin/bj-installer install --code "$CODE" --server "$SERVER" --channel "$CHANNEL"; then finish - read -t 60 -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ || true + show_accounts + read -r -p " Нажмите Enter, чтобы перейти к экрану входа. " _ || true exit 0 fi printf '\n Установка не завершилась. Проверьте ключ продукта и сеть и попробуйте ещё раз.\n\n' diff --git a/deploy/iso/preseed.cfg b/deploy/iso/preseed.cfg index 0f2729e..0086bfe 100644 --- a/deploy/iso/preseed.cfg +++ b/deploy/iso/preseed.cfg @@ -35,10 +35,16 @@ d-i apt-setup/cdrom/set-first boolean false d-i apt-setup/non-free-firmware boolean true d-i apt-setup/services-select multiselect security, updates -# Учётная запись: одна — администратор ОС с sudo (вход root отключён). Установщик спросит -# полное имя, ЛОГИН и пароль — логин человек видит и задаёт сам; им же входят в консоль сервера. +# Учётные записи ОС задаются автоматически, установщик Debian их не спрашивает: +# root_bj — администратор сервера (sudo), user_bj — вход без прав администратора (журналы). +# Вход root отключён. Пароли генерирует bj-firstboot при первой загрузке и показывает на экране +# (можно ввести свои); на диске они не хранятся. До этого момента пароль root_bj заблокирован. d-i passwd/root-login boolean false d-i passwd/make-user boolean true +d-i passwd/user-fullname string Администратор сервера bj +d-i passwd/username string root_bj +d-i passwd/user-password-crypted password ! +d-i passwd/user-default-groups string sudo adm systemd-journal # Разметка: весь выбранный диск, одна файловая система; диск и стирание подтверждаются при установке d-i partman-auto/method string regular diff --git a/deploy/linux/sbin/bj-welcome b/deploy/linux/sbin/bj-welcome index 01c3085..36c5142 100755 --- a/deploy/linux/sbin/bj-welcome +++ b/deploy/linux/sbin/bj-welcome @@ -54,8 +54,12 @@ fi *) printf ' Лицензия НЕ АКТИВИРОВАНА: введите ключ продукта в «Настройка → Лицензия».\n';; esac fi - ADM=$(getent group sudo | cut -d: -f4 | tr ',' ' ') - printf '\n Вход в консоль сервера (обслуживание): логин администратора ОС%s и его пароль,\n заданные при установке Debian; команды — через sudo. Веб-вход — по адресу выше.\n\n' "${ADM:+ ($ADM)}" + if id root_bj >/dev/null 2>&1; then + printf '\n Вход в консоль сервера (обслуживание): root_bj — администратор (sudo), user_bj — обычный.\n Пароли показаны один раз при первой загрузке. Веб-вход в bj — по адресу выше.\n\n' + else + ADM=$(getent group sudo | cut -d: -f4 | tr ',' ' ') + printf '\n Вход в консоль сервера (обслуживание): логин администратора ОС%s и его пароль,\n заданные при установке; команды — через sudo. Веб-вход — по адресу выше.\n\n' "${ADM:+ ($ADM)}" + fi } > "$ISSUE.tmp" if ! cmp -s "$ISSUE.tmp" "$ISSUE" 2>/dev/null; then mv -f "$ISSUE.tmp" "$ISSUE"