Первичная настройка, повторная проверка: копии без ключевых носителей СКЗИ (--one-file-system, без keymedia), без отпечатка железа и списка компонентов; восстановление на новый сервер — пароль базы bj из копии, база и пользователь ИШ; ключ для контура без канала запоминается и подключается при настройке канала; первый настроенный канал становится рабочим контуром; справочник сертификатов перечитывается после ключа и смены контура; шлюз НРД — шаг 7, ключ — шаг 8 (ключ ставится в профиль ИШ); подсказка контура ключа по сертификату; ИШ: параметры работающего шлюза не перезаписываются; без чужого кода отправителя и получателя по умолчанию; прокси для выхода в интернет; установка с образа без интернета; HTTPS — новый сертификат при смене адреса; bj-network — без cloud-init; проверка готовности: справочник участников, сетевые доступы, учётные записи, последний обмен с НРД
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014FsEKyJrYF69Cj9ZXzFLRi
This commit is contained in:
@@ -33,10 +33,16 @@ runuser -u postgres -- pg_dump -Fc bj > "$W/bj.pgdump" || fail "дамп баз
|
||||
if runuser -u postgres -- psql -Atc "select 1 from pg_database where datname='igate'" 2>/dev/null | grep -q 1; then
|
||||
runuser -u postgres -- pg_dump -Fc igate > "$W/igate.pgdump" || fail "дамп базы igate"
|
||||
fi
|
||||
tarok -C / -czf "$W/bj-data.tar.gz" --exclude=etc/bj/backup-smb.cred var/lib/bj/.bj etc/bj || fail "архив данных bj"
|
||||
# Не копируем: пароль хранилища; то, что принадлежит этой машине (отпечаток железа, список установленных
|
||||
# компонентов — на новом сервере они свои); ключевые носители (флешка ключа монтируется в
|
||||
# /var/lib/igate/keymedia): ключи СКЗИ не должны уходить на сетевое хранилище — при восстановлении носитель
|
||||
# подключают заново. --one-file-system — не заходить ни в какие смонтированные носители.
|
||||
tarok -C / -czf "$W/bj-data.tar.gz" --one-file-system --exclude=etc/bj/backup-smb.cred --exclude=etc/bj/hw-id \
|
||||
--exclude=var/lib/bj/.bj/components.json var/lib/bj/.bj etc/bj || fail "архив данных bj"
|
||||
if [ -d /var/lib/igate ]; then
|
||||
tarok -C / -czf "$W/igate-data.tar.gz" --warning=no-file-changed --exclude='var/lib/igate/.cache' \
|
||||
--exclude='var/lib/igate/NSD Integration Gateway/logs*' --exclude='var/lib/igate/logs-cli' var/lib/igate || fail "архив шлюза НРД"
|
||||
tarok -C / -czf "$W/igate-data.tar.gz" --one-file-system --warning=no-file-changed --exclude='var/lib/igate/.cache' \
|
||||
--exclude='var/lib/igate/keymedia/*' --exclude='var/lib/igate/NSD Integration Gateway/logs*' \
|
||||
--exclude='var/lib/igate/logs-cli' var/lib/igate || fail "архив шлюза НРД"
|
||||
fi
|
||||
cat > "$W/backup-info.txt" <<INFO
|
||||
Bridge&Join — резервная копия сервера $(hostname) от $(date '+%d.%m.%Y %H:%M:%S')
|
||||
|
||||
@@ -129,13 +129,43 @@ PY
|
||||
LC_ALL=C PGOPTIONS='-c lc_messages=C' runuser -u postgres -- pg_restore --clean --if-exists -d bj < "$W/bj.pgdump" >/dev/null 2>"$W/pg.err"
|
||||
# «does not exist» при --clean на пустой базе — не ошибка; остальное — ошибка
|
||||
if grep -i "error" "$W/pg.err" | grep -vqi "does not exist"; then die "база bj: $(grep -i error "$W/pg.err" | grep -vi 'does not exist' | head -1)"; fi
|
||||
if [ -s "$W/igate.pgdump" ] && runuser -u postgres -- psql -Atc "select 1 from pg_database where datname='igate'" | grep -q 1; then
|
||||
if [ -s "$W/igate.pgdump" ]; then
|
||||
st db "восстановление базы шлюза НРД"
|
||||
# новый сервер: ИШ ещё не ставили — готовим пользователя, роль, базу и доступ без пароля (как ставит
|
||||
# bj-igate-admin), чтобы данные и каналы ИШ вернулись; сам пакет ИШ потом ставится на шаге «Шлюз НРД»
|
||||
id igate >/dev/null 2>&1 || useradd --system --home-dir /var/lib/igate --create-home --shell /usr/sbin/nologin igate
|
||||
runuser -u postgres -- psql -tAc "select 1 from pg_roles where rolname='igate'" | grep -q 1 || runuser -u postgres -- psql -qc "create role igate login"
|
||||
runuser -u postgres -- psql -lqt | cut -d'|' -f1 | grep -qw igate || runuser -u postgres -- createdb -O igate igate
|
||||
hba=$(runuser -u postgres -- psql -tAc "show hba_file")
|
||||
if [ -f "$hba" ] && ! grep -q '^# bj-igate-trust' "$hba"; then
|
||||
cp -a "$hba" "$hba.bak-bj-igate"
|
||||
{ printf '# bj-igate-trust\nlocal igate igate trust\nhost igate igate 127.0.0.1/32 trust\nhost igate igate ::1/128 trust\n'; cat "$hba.bak-bj-igate"; } > "$hba"
|
||||
runuser -u postgres -- psql -qtAc "select pg_reload_conf()" >/dev/null
|
||||
fi
|
||||
LC_ALL=C PGOPTIONS='-c lc_messages=C' runuser -u postgres -- pg_restore --clean --if-exists -d igate < "$W/igate.pgdump" >/dev/null 2>&1
|
||||
fi
|
||||
st files "восстановление данных bj и шлюза НРД"
|
||||
tar -C / -xzf "$W/bj-data.tar.gz" || die "распаковка данных bj"
|
||||
[ -s "$W/igate-data.tar.gz" ] && { tar -C / -xzf "$W/igate-data.tar.gz" || die "распаковка данных шлюза НРД"; }
|
||||
# своё у этой машины (отпечаток железа, установленные компоненты) — сохраняем поверх копии; ключевые
|
||||
# носители из старых копий не раскладываем: ключ СКЗИ — только на своём носителе
|
||||
mkdir -p "$W/keep"; cp -a /var/lib/bj/.bj/components.json /etc/bj/hw-id "$W/keep/" 2>/dev/null
|
||||
tar -C / -xzf "$W/bj-data.tar.gz" --exclude=etc/bj/hw-id --exclude=var/lib/bj/.bj/components.json || die "распаковка данных bj"
|
||||
[ -f "$W/keep/components.json" ] && cp -a "$W/keep/components.json" /var/lib/bj/.bj/components.json
|
||||
[ -f "$W/keep/hw-id" ] && cp -a "$W/keep/hw-id" /etc/bj/hw-id
|
||||
# пароль пользователя базы bj — как в восстановленных настройках: установщик нового сервера задал свой
|
||||
# случайный пароль, и без этого bj не подключился бы к своей базе (ушёл бы в хранение в памяти)
|
||||
pw=$(python3 - <<'PY'
|
||||
import json,urllib.parse
|
||||
try:
|
||||
d=json.load(open("/var/lib/bj/.bj/setup.json")).get("postgres",{}).get("dsn","")
|
||||
u=urllib.parse.urlparse(d)
|
||||
if u.username=="bj" and u.password and u.hostname in ("127.0.0.1","localhost"): print(urllib.parse.unquote(u.password))
|
||||
except Exception: pass
|
||||
PY
|
||||
)
|
||||
if [ -n "$pw" ]; then
|
||||
printf "ALTER ROLE bj WITH PASSWORD '%s';\n" "$(printf '%s' "$pw" | sed "s/'/''/g")" | runuser -u postgres -- psql -q >/dev/null 2>&1 || die "не удалось выставить пароль базы bj из копии"
|
||||
fi
|
||||
[ -s "$W/igate-data.tar.gz" ] && { tar -C / -xzf "$W/igate-data.tar.gz" --exclude='var/lib/igate/keymedia/*' || die "распаковка данных шлюза НРД"; }
|
||||
# копия хранилища в восстановленных настройках есть, а пароль в неё не входит — берём тот, с которым
|
||||
# восстанавливали, и возвращаем расписание копий
|
||||
if [ -r "$CONF" ]; then
|
||||
@@ -148,7 +178,12 @@ PY
|
||||
systemctl start bj-server >/dev/null 2>&1
|
||||
systemctl is-enabled bj-backup.timer >/dev/null 2>&1 && systemctl start bj-backup.timer >/dev/null 2>&1
|
||||
for u in bj-npr bj-lk; do systemctl is-enabled "$u" >/dev/null 2>&1 && systemctl start "$u" >/dev/null 2>&1; done
|
||||
had_igate=0; [ -s "$W/igate-data.tar.gz" ] && had_igate=1
|
||||
rm -rf "$W" /run/bj-restore.conf
|
||||
st done "восстановлено из копии $NAME" ;;
|
||||
if [ "$had_igate" = 1 ] && [ ! -x /opt/nsd/igate/igate-svc/igate-svc ]; then
|
||||
st done "восстановлено из копии $NAME. Шлюз НРД на этом сервере не установлен — установите его в мастере (шаг «Шлюз НРД»): настройки и каналы из копии подхватятся; ключ — подключите носитель и установите мастером ключа"
|
||||
else
|
||||
st done "восстановлено из копии $NAME"
|
||||
fi ;;
|
||||
*) err "неизвестная команда: $cmd" ;;
|
||||
esac
|
||||
|
||||
@@ -114,9 +114,11 @@ PY
|
||||
st deps "системные пакеты для работы ИШ без графики"
|
||||
need=""
|
||||
for p in gnome-keyring dbus xvfb xauth libsecret-tools unzip curl; do dpkg -s "$p" >/dev/null 2>&1 || need="$need $p"; done
|
||||
px=$(j proxy) # прокси организации (из настроек bj) — для apt и скачивания с nsd.ru
|
||||
aptpx=(); [ -n "$px" ] && aptpx=(-o "Acquire::http::Proxy=$px" -o "Acquire::https::Proxy=$px")
|
||||
if [ -n "$need" ]; then
|
||||
DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends $need || \
|
||||
{ DEBIAN_FRONTEND=noninteractive apt-get update -qq && DEBIAN_FRONTEND=noninteractive apt-get install -y -qq --no-install-recommends $need; } || die "не удалось установить пакеты:$need"
|
||||
DEBIAN_FRONTEND=noninteractive apt-get "${aptpx[@]}" install -y -qq --no-install-recommends $need || \
|
||||
{ DEBIAN_FRONTEND=noninteractive apt-get "${aptpx[@]}" update -qq && DEBIAN_FRONTEND=noninteractive apt-get "${aptpx[@]}" install -y -qq --no-install-recommends $need; } || die "не удалось установить пакеты:$need"
|
||||
fi
|
||||
|
||||
st package "дистрибутив ИШ"
|
||||
@@ -125,7 +127,7 @@ PY
|
||||
v=$(printf '%s' "$ver" | tr . -)
|
||||
url="https://www.nsd.ru/media/integratsionnyj-shlyuz/$v/igate-$v-amd64.zip"
|
||||
echo "скачивание $url"
|
||||
curl -fsSL -m 600 -A 'Mozilla/5.0 (X11; Linux x86_64) bj-installer' -H 'Accept: */*' -o "$W/igate.zip" "$url" || die "не удалось скачать дистрибутив ИШ $ver с сайта НРД ($url)"
|
||||
curl -fsSL -m 600 ${px:+-x "$px"} -A 'Mozilla/5.0 (X11; Linux x86_64) bj-installer' -H 'Accept: */*' -o "$W/igate.zip" "$url" || die "не удалось скачать дистрибутив ИШ $ver с сайта НРД ($url)"
|
||||
file="$W/igate.zip"
|
||||
fi
|
||||
case "$file" in
|
||||
@@ -200,6 +202,8 @@ StartLimitBurst=8
|
||||
User=$SVC_USER
|
||||
WorkingDirectory=$HOME_DIR
|
||||
# самоочистка перед стартом: осиротевшие сокеты, keyring, X-локи — иначе перезапуски срываются
|
||||
# каталог сеанса igate (XDG_RUNTIME_DIR): обычно его создаёт systemd-logind (linger), но без него keyring не стартует
|
||||
ExecStartPre=+/usr/bin/install -d -o $SVC_USER -g $SVC_USER -m 700 /run/user/$uid
|
||||
ExecStartPre=-/bin/bash -c 'rm -f /tmp/CoreFxPipe_NSD.IGate.* $HOME_DIR/.local/share/keyrings/login.keyring; find /tmp -maxdepth 1 -name ".X9*-lock" -delete 2>/dev/null; true'
|
||||
ExecStart=/usr/bin/dbus-run-session -- $WRAPPER
|
||||
Restart=on-failure
|
||||
@@ -215,28 +219,31 @@ EOF
|
||||
run_as_igate_keyring "timeout 90 $IGATE_DIR/igate-cli/igate-cli --data $HOME_DIR </dev/null >/dev/null 2>&1; true"
|
||||
psqlq -c "select to_regclass('public.parameters') is not null" | grep -q t || die "ИШ не создал схему базы (igate-cli). Журнал: $LOG"
|
||||
fi
|
||||
# глобальные параметры: Web API на localhost:8090 без авторизации и запуск движка без графики
|
||||
# Общие параметры ИШ. Обязательные для работы без графики и для bj (движок при старте, Web API на
|
||||
# localhost:8090 без авторизации) — выставляем всегда; остальные — только если их ещё нет: настройки ИШ,
|
||||
# который у клиента уже работает (очистка, хранение, прокси), не трогаем. Значения по умолчанию — эталон GUI.
|
||||
psqlq <<'SQL' || die "не записаны параметры ИШ"
|
||||
DELETE FROM parameters WHERE chanel_id IS NULL AND name IN ('runEngineOnStartApp','server.useServer','server.host','server.port','server.scheme',
|
||||
'server.authentication.enable','server.authentication.userName','server.authentication.password','server.certificate.storage',
|
||||
'server.certificate.store.location','server.certificate.store.name','server.certificate.file.path','server.certificate.file.password',
|
||||
'wsl.httpsMode','wsl.maxConnsPerServer','wsl.proxy.mode','wsl.proxy.address','wsl.proxy.port','wsl.proxy.username','wsl.proxy.password',
|
||||
'enableDbLogging','cleanAutomatically','cleanAtTime','cleanWhenLarger','cleanVacuum','storePeriod','archiveAutomatically');
|
||||
INSERT INTO parameters(name, value, chanel_id) VALUES
|
||||
('runEngineOnStartApp','True',NULL),('server.useServer','True',NULL),('server.host','localhost',NULL),('server.port','8090',NULL),
|
||||
('server.scheme','Http',NULL),('server.authentication.enable','False',NULL),('server.authentication.userName','',NULL),
|
||||
('server.authentication.password','',NULL),('server.certificate.storage','File',NULL),('server.certificate.store.location','CurrentUser',NULL),
|
||||
('server.certificate.store.name','My',NULL),('server.certificate.file.path','',NULL),('server.certificate.file.password','',NULL),
|
||||
('wsl.httpsMode','Auto',NULL),('wsl.maxConnsPerServer','4',NULL),('wsl.proxy.mode','None',NULL),('wsl.proxy.address','',NULL),
|
||||
('wsl.proxy.port','0',NULL),('wsl.proxy.username','',NULL),('wsl.proxy.password','',NULL),('enableDbLogging','False',NULL),
|
||||
('cleanAutomatically','True',NULL),('cleanAtTime','00:30:00',NULL),('cleanWhenLarger','1024',NULL),('cleanVacuum','False',NULL),
|
||||
('storePeriod','30',NULL),('archiveAutomatically','False',NULL);
|
||||
CREATE TEMP TABLE must(n text, v text);
|
||||
INSERT INTO must VALUES ('runEngineOnStartApp','True'),('server.useServer','True'),('server.host','localhost'),
|
||||
('server.port','8090'),('server.scheme','Http'),('server.authentication.enable','False');
|
||||
CREATE TEMP TABLE dflt(n text, v text);
|
||||
INSERT INTO dflt VALUES ('server.authentication.userName',''),('server.authentication.password',''),('server.certificate.storage','File'),
|
||||
('server.certificate.store.location','CurrentUser'),('server.certificate.store.name','My'),('server.certificate.file.path',''),
|
||||
('server.certificate.file.password',''),('wsl.httpsMode','Auto'),('wsl.maxConnsPerServer','4'),('wsl.proxy.mode','None'),
|
||||
('wsl.proxy.address',''),('wsl.proxy.port','0'),('wsl.proxy.username',''),('wsl.proxy.password',''),('enableDbLogging','False'),
|
||||
('cleanAutomatically','False'),('cleanAtTime','00:30:00'),('cleanWhenLarger','1024'),('cleanVacuum','False'),('storePeriod','15'),
|
||||
('archiveAutomatically','False');
|
||||
UPDATE parameters p SET value = m.v FROM must m WHERE p.chanel_id IS NULL AND p.name = m.n;
|
||||
INSERT INTO parameters(name, value, chanel_id)
|
||||
SELECT x.n, x.v, NULL FROM (SELECT * FROM must UNION ALL SELECT * FROM dflt) x
|
||||
WHERE NOT EXISTS (SELECT 1 FROM parameters p WHERE p.chanel_id IS NULL AND p.name = x.n);
|
||||
SQL
|
||||
|
||||
st start "запуск ИШ"
|
||||
systemctl enable igate >/dev/null 2>&1
|
||||
systemctl restart igate || die "служба igate не запустилась"
|
||||
wait_engine 120 || die "ИШ запущен, но движок не перешёл в Running за 2 минуты. Журнал ИШ: $DATA_DIR/logs-svc/log.txt"
|
||||
case "$(j file)" in /var/lib/bj/igate-upload/*) rm -f "$(j file)" ;; esac # загруженный архив больше не нужен
|
||||
st done "ИШ $(igate_version) установлен и работает; дальше — канал контура (TEST3 или боевой)" ;;
|
||||
|
||||
contour)
|
||||
@@ -247,6 +254,8 @@ SQL
|
||||
[[ "$dep" =~ ^[A-Z]{2}[0-9]{10}$ ]] || err "депозитарный код — вида MC0000000000"
|
||||
[[ -z "$prof" || "$prof" =~ ^[A-Za-z0-9_-]+$ ]] || err "недопустимое имя профиля Валидаты"
|
||||
[ -x "$IGATE_DIR/igate-svc/igate-svc" ] || err "ИШ не установлен"
|
||||
# ключ этого контура ставили раньше, чем канал: профиль запомнен установкой ключа
|
||||
if [ -z "$prof" ] && [ -s "$HOME_DIR/.bj-profile-$CODE" ]; then prof=$(tr -cd 'A-Za-z0-9_-' < "$HOME_DIR/.bj-profile-$CODE"); fi
|
||||
DIR=$(exchange_dir "$contour"); install -d -o "$SVC_USER" -g "$SVC_USER" -m 755 "$DIR"
|
||||
psqlq -v code="$CODE$dep" -v name="$NAME" -v ep="$EP" -v fp="$FP" -v typ="$TYPE" -v dep="$dep" -v prof="$prof" -v dir="$DIR" <<'SQL' || err "канал не записан в базу ИШ"
|
||||
BEGIN;
|
||||
|
||||
@@ -199,7 +199,15 @@ open(ini,"w").write("\n".join(L))
|
||||
PY
|
||||
fi
|
||||
# подключить профиль к ИШ: cryptography.profile в БД igate (канал 33)
|
||||
if [ "$IGATE_RES" = "ok" ]; then
|
||||
nchan=1
|
||||
if [ "$IGATE_RES" = "ok" ] && [ -n "$CHAN_PREFIX" ]; then
|
||||
nchan=$(su -s /bin/sh postgres -c "psql -d igate -tAc \"select count(*) from channels where code like '${CHAN_PREFIX}%'\"" 2>/dev/null | tr -d '[:space:]')
|
||||
fi
|
||||
if [ "$IGATE_RES" = "ok" ] && [ "${nchan:-0}" = 0 ]; then
|
||||
# канала этого контура в ИШ ещё нет: профиль запоминаем — bj-igate-admin подключит его при настройке канала
|
||||
printf '%s\n' "$PROFILE" > "/var/lib/igate/.bj-profile-$CHAN_PREFIX"; chown igate:igate "/var/lib/igate/.bj-profile-$CHAN_PREFIX" 2>/dev/null
|
||||
IGATE_RES="pending-channel"
|
||||
elif [ "$IGATE_RES" = "ok" ]; then
|
||||
# только канал контура этого ключа (BJ_CHANNEL); старый bj без контура — все каналы, как раньше. Канал с ключом включаем.
|
||||
if su -s /bin/sh postgres -c "psql -d igate -tAc \"update parameters set value='$PROFILE' where name='cryptography.profile' and $(chan_where); update channels set enable=true where id in (select chanel_id from parameters where name='cryptography.profile' and value='$PROFILE'); update parameters set value='True' where name='enable' and chanel_id in (select chanel_id from parameters where name='cryptography.profile' and value='$PROFILE')\"" >/dev/null 2>&1; then
|
||||
IGATE_RES="connected"
|
||||
|
||||
@@ -26,11 +26,14 @@ F=/etc/netplan/60-bj-static.yaml
|
||||
chmod 600 "$F"
|
||||
# прежние файлы с DHCP для этого интерфейса — выключаем, чтобы не было двух адресов
|
||||
for f in /etc/netplan/*.yaml; do [ "$f" = "$F" ] && continue; grep -q "$IF" "$f" 2>/dev/null && mv "$f" "$f.disabled-by-bj"; done
|
||||
# на Ubuntu с образа сетью управляет cloud-init: без запрета при перезагрузке он может вернуть DHCP
|
||||
CI=/etc/cloud/cloud.cfg.d/99-bj-disable-network-config.cfg
|
||||
[ -d /etc/cloud/cloud.cfg.d ] && printf 'network: {config: disabled}\n' > "$CI"
|
||||
echo " Применяю. Если связь пропадёт — через 120 секунд вернутся прежние настройки."
|
||||
if netplan try --timeout 120; then
|
||||
echo " ✓ Адрес ${ADDR%/*} закреплён. Веб-вход: https://${ADDR%/*}:8443/"
|
||||
[ -x /usr/local/sbin/bj-welcome ] && /usr/local/sbin/bj-welcome
|
||||
else
|
||||
for f in /etc/netplan/*.disabled-by-bj; do [ -f "$f" ] && mv "$f" "${f%.disabled-by-bj}"; done
|
||||
rm -f "$F"; netplan apply; echo " Настройки не приняты — оставлен прежний адрес."
|
||||
rm -f "$F" "$CI"; netplan apply; echo " Настройки не приняты — оставлен прежний адрес."
|
||||
fi
|
||||
|
||||
Reference in New Issue
Block a user