46 KiB
Ставим KES на ВМ1
Копируем на диск: scp "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.iso" "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.sig" prodVM1Deploy:/var/lib/han-deploy/incoming/
apt install rhash
ISO='/var/lib/han-deploy/incoming/049-16-d-01.iso' command -v rhash rhash --gost "$ISO"
ГОСТ совпал: rhash --gost дал ту же сумму, что на сайте вендора. ISO подлинный. 6a94b16afad211e8b9be5ec86f5379184f2b3a9e5869843fe763e2796e5ac1d3
sudo apt remove -y rhash sudo apt purge -y rhash
Дальше только копирование нужного DEB и снимки. GUI, i386 и RPM не трогайте. Установку ещё не запускайте.
ISO='/var/lib/han-deploy/incoming/049-16-d-01.iso'
install -d -m 0700 -o root -g root \
/root/kesl-install /mnt/kesl-iso
mount -o ro,loop "$ISO" /mnt/kesl-iso
find /mnt/kesl-iso -type f \
\( -iname 'kesl_*_amd64.deb' -o -iname '*.deb' \) |
sort
DEB='/mnt/kesl-iso/kesl/kesl_12.4.0-1225_amd64.deb'
dpkg-deb -f "$DEB" Package Version Architecture
sha256sum "$DEB"
install -m 0600 -o root -g root \
"$DEB" /root/kesl-install/kesl.deb
umount /mnt/kesl-iso
rmdir /mnt/kesl-iso
apt-get install /root/kesl-install/kesl.deb
cp -a /etc/docker/daemon.json /root/kesl-install/docker-daemon.before.json iptables-save > /root/kesl-install/iptables.before ufw status verbose > /root/kesl-install/ufw.before ls -l /root/kesl-install
Ожидается: Package: kesl, Version: 12.4.0-1225, Architecture: amd64.
Дальше установка с выключенной защитой, без кода активации и без сканирования. Перед командами явно примите EULA и политику конфиденциальности Kaspersky. KSN для этого пилота выключаем (USE_KSN=No).
install -m 0600 -o root -g root /dev/null /root/kesl-install/autoinstall.ini
cat >/root/kesl-install/autoinstall.ini <<'EOF'
KSVLA_MODE=No
ENDPOINT_AGENT_MODE=No
EULA_AGREED=Yes
PRIVACY_POLICY_AGREED=Yes
USE_KSN=No
GROUP_CLEAN=Yes
LOCALE=ru_RU.UTF-8
INSTALL_LICENSE=None
UPDATER_SOURCE=KLServers
UPDATE_EXECUTE=No
KERNEL_SRCS_INSTALL=No
USE_GUI=No
CONFIGURE_SELINUX=No
DISABLE_PROTECTION=Yes
INTERCEPTOR_MODE=UseFanotify
ENABLE_TRACES_ON_FIRST_STARTUP=No
EOF
chmod 0600 /root/kesl-install/autoinstall.ini
/opt/kaspersky/kesl/bin/kesl-setup.pl \
--autoinstall=/root/kesl-install/autoinstall.ini
echo "kesl-setup exit=$?"
systemctl --no-pager --no-legend status kesl || true
kesl-control --app-info
kesl-control --get-task-list
free -h
/usr/local/sbin/han-vm1-compose ps
docker stats --no-stream --format \
'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.PIDs}}'
Ожидается: служба kesl запущена, File Threat Protection не в Started, контейнеры healthy, available RAM не уходит ниже ~512 МБ.
kesl-control --get-app-settings
--file /root/kesl-install/app-settings.before.ini
install -m 0600 -o root -g root
/var/opt/kaspersky/kesl/common/kesl.ini
/root/kesl-install/kesl.ini.before
systemctl stop kesl python3 - <<'PY' from pathlib import Path path = Path("/var/opt/kaspersky/kesl/common/kesl.ini") text = path.read_text(encoding="utf-8") if "[General]" not in text: raise SystemExit("no [General] section in kesl.ini") wanted = {"ScanMemoryLimit": "1024", "MaxMemory": "2048MB"} lines = text.splitlines() in_general = False seen = set() out = [] for line in lines: stripped = line.strip() if stripped.startswith("[") and stripped.endswith("]"): in_general = stripped == "[General]" if in_general and "=" in stripped and not stripped.startswith("#"): key = stripped.split("=", 1)[0].strip() if key in wanted: out.append(f"{key}={wanted[key]}") seen.add(key) continue out.append(line) if seen != set(wanted): rebuilt = [] inserted = False in_general = False for line in out: stripped = line.strip() rebuilt.append(line) if stripped.startswith("[") and stripped.endswith("]"): if in_general and not inserted: for key, value in wanted.items(): if key not in seen: rebuilt.insert(-1, f"{key}={value}") inserted = True in_general = stripped == "[General]" if in_general and not inserted: for key, value in wanted.items(): if key not in seen: rebuilt.append(f"{key}={value}") out = rebuilt path.write_text("\n".join(out) + "\n", encoding="utf-8") print("updated ScanMemoryLimit/MaxMemory") PY grep -E '^(ScanMemoryLimit|MaxMemory)=' /var/opt/kaspersky/kesl/common/kesl.ini systemctl start kesl systemctl is-active kesl kesl-control --set-app-settings UseOnDemandCPULimit=Yes OnDemandCPULimit=15 free -h swapon --show
set +o history unset HISTFILE read -rsp 'KESL activation code: ' KESL_CODE; echo kesl-control --add-active-key "$KESL_CODE" unset KESL_CODE set -o history
kesl-control -L --query kesl-control --app-info kesl-control --get-task-state 1 /usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
free -h kesl-control --start-task 6 -W kesl-control --get-task-state 6 kesl-control --app-info free -h /usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
Ожидается ровно одна строка MaxMemory=1024MB, Update завершилась, Application databases loaded: Yes, лицензия не Inconsistent update. Если available RAM < 512 МБ или контейнер unhealthy — остановите Update (kesl-control --stop-task 6) и пришлите вывод. GUID ключа в следующий лог лучше не включать.
Базы загружены, ключ действителен, File Threat Protection доступна и остановлена, сервисы HAN healthy. АВЗ.2 по сути закрыта после почасового Update.
Вендор просит перезапуск KESL после обновления модуля. Container Monitoring этой лицензией не покрыт — контейнерный мониторинг пропускаем, компенсируем host File Threat Protection и точечным scan-file.
Сеть/firewall KESL не включаем. Сначала restart, расписание Update и исключения hot-data.
systemctl restart kesl systemctl is-active kesl kesl-control --get-task-state 1
kesl-control --get-task-state 6
kesl-control --app-info --json
START="$(LC_ALL=C date +'%Y/%b/%d %H:%M:%S;1')"
kesl-control --set-schedule 6 RuleType=Hourly
"StartTime=${START}" RunMissedStartRules=No RandomInterval=0
kesl-control --get-schedule 6
kesl-control --get-settings 1
--file /root/kesl-install/file-threat.before.ini
kesl-control --set-settings 1
--add-exclusion /var/lib/docker/volumes/han-chat_redis-data/_data
kesl-control --set-settings 1
--add-exclusion /var/lib/docker/volumes/han-chat_otel-queue/_data
kesl-control --set-settings 1
--add-exclusion /var/lib/docker/volumes/han-chat_nginx-cache/_data
kesl-control --set-settings 1 ScanArchived=No
kesl-control --get-settings 1
free -h /usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
Ожидается: Post-update actions: No action required, базы загружены, FTP Stopped, RuleType=Hourly, в настройках задачи 1 три исключения и ScanArchived=No. Пришлите вывод.
Исключения приняты, сервисы healthy. Почасовой Update не применился: 12.4 требует StartTime с интервалом, иначе остаётся Manual.
Сначала расписание, затем узкий scan-file без изменения файлов. File Threat Protection пока не запускаем.
kesl-control --get-schedule 6
kesl-control --scan-file /opt/han-chat/current/backend --action Inform kesl-control --get-task-state 1 free -h /usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
Ожидается: RuleType=Hourly и StartTime=...;1, scan-file без ошибок, FTP Stopped, контейнеры healthy. Если scan-file сильно поднимет swap или появятся unhealthy — остановите его и пришлите вывод.
Расписание Update почасовое, узкий scan-file прошёл чисто (421 объект, 0 угроз), swap не вырос, сервисы healthy.
Дальше File Threat Protection в режиме Notify: обнаружения пишутся в журнал, файлы не блокируются. Сеть/firewall KESL и Behavior Detection не включаем. Container scan этой лицензией недоступен — пропускаем.
kesl-control --set-app-settings InterceptorProtectionMode=Notify
kesl-control --start-task 1
kesl-control --get-task-state 1
kesl-control --app-info --json
free -h
docker stats --no-stream --format
'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.PIDs}}'
/usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
iptables -S HAN-CHAT-DOCKER
File Threat Protection уже Running, сервисы healthy, firewall не тронут. InterceptorProtectionMode на fanotify в 12.4 не существует — штатный режим и есть блокировка на время проверки. Для АВЗ.1 это достаточный путь; откат: kesl-control --stop-task 1.
Дальше контролируемый EICAR. Образец в чат после теста не копируйте.
install -d -m 0700 -o root -g root /root/kesl-eicar-test
printf '%s' 'X5O!P%@AP[4\PZX54(P^)7CC)7}$EICAR-STANDARD-ANTIVIRUS-TEST-FILE!$H+H*' \
> /root/kesl-eicar-test/eicar.com
ls -l /root/kesl-eicar-test
kesl-control --scan-file /root/kesl-eicar-test --action DisinfectDeleteIfNotPossible
kesl-control -E --query -n 30 --reverse
ls -la /root/kesl-eicar-test
rm -rf /root/kesl-eicar-test
kesl-control --get-task-state 1
kesl-control --get-schedule 6
free -h
/usr/local/sbin/han-vm1-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
Ставим KES на ВМ2
Готовим новый образ Message Safety MESSAGE_SAFETY_IMAGE=cr.selcloud.ru/han-images/han-message-safety@sha256:225808bd111be03112ab6693b5a10e3d97ae8cdbe5370a5d0aa5a8e2278a3044
Копируем проект
$Release = "1.0.1"
tar --exclude=services/.env `
--exclude='services/**/__pycache__' `
--exclude='services/**/.pytest_cache' `
--exclude='services/**/.ruff_cache' `
-czf "vm2-services-$Release.tar.gz" -C C:\Users\MI\Documents\Assistent\HAN_chat_specification\VM2_services\codebase services
Get-FileHash "vm2-services-$Release.tar.gz" -Algorithm SHA256
scp "vm2-services-$Release.tar.gz" prodVM2Deploy:/var/lib/han-deploy/incoming/
scp "vm2-services-$Release.tar.gz" devVM2Deploy:/var/lib/han-deploy/incoming/
Проверить размер диска
RELEASE='1.0.1'
EXPECTED_SHA256='1030DE6A50BA945FAEC5A45E1D42C47A01808E737AA1955871F3D2ED089F8879'
ARCHIVE="/var/lib/han-deploy/incoming/vm2-services-${RELEASE}.tar.gz"
printf '%s %s\n' "$EXPECTED_SHA256" "$ARCHIVE" | sha256sum --check -
tar -tvzf "$ARCHIVE"
if tar -tzf "ARCHIVE" | grep -Eq '(^/|(^|/)\.\.(/|)|^services/.env$)'; then
echo 'ОШИБКА: архив содержит небезопасный путь или .env' >&2
exit 1
fi
if tar -tzf "ARCHIVE" | grep -Ev '^services(/|)' | grep -q .; then
echo 'ОШИБКА: архив содержит файлы вне каталога services' >&2
exit 1
fi
if tar -tvzf "$ARCHIVE" | awk '$1 ~ /^[lh]/ { found=1 } END { exit !found }'; then
echo 'ОШИБКА: архив содержит symlink или hardlink' >&2
exit 1
fi
install -d -m 0755 -o root -g root /opt/han-chat/services
STAGING="$(mktemp -d /opt/han-chat/.vm2-release.XXXXXX)"
tar --extract --gzip --file "$ARCHIVE"
--directory "$STAGING" --no-same-owner --no-same-permissions
test -f "$STAGING/services/docker-compose.yml"
rsync -a --delete --exclude=.env
--chown=root:root --chmod=D755,F644
"$STAGING/services/" /opt/han-chat/services/
rm -rf -- "$STAGING"
chmod 0755 /opt/han-chat/services/deployment/preflight.sh
cd /opt/han-chat/services/
sudo apt update
sudo apt install -y dos2unix
find . -type f (
-name '.sh' -o -name '.py' -o -name '.service' -o -name '.sudoers' -o -name 'han-compose' -o -name 'han-secrets' -o -name 'han-message-safety-mode' -o -name '.yml' -o -name '.conf*' -o -name 'preflight.sh' -o -name '.yaml' -o -name '.md' -o -name '.toml' -o -name 'Dockerfile' -o -name '.acl*'
) -exec dos2unix {} +
find -type f -exec file {} ; | grep -i 'CRLF'
sudo apt remove -y dos2unix sudo apt purge -y dos2unix
Копируем образ на ВМ: scp "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.iso" "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.sig" prodVM2Deploy:/var/lib/han-deploy/incoming/
Проверка файла: apt install -y rhash ISO='/var/lib/han-deploy/incoming/049-16-d-01.iso' command -v rhash rhash --gost "$ISO"
Должно быть 6a94b16afad211e8b9be5ec86f5379184f2b3a9e5869843fe763e2796e5ac1d3
sudo apt remove -y rhash sudo apt purge -y rhash
Если совпадёт, извлеките DEB:
install -d -m 0700 -o root -g root \
/root/kesl-install /mnt/kesl-iso
mount -o ro,loop "$ISO" /mnt/kesl-iso
find /mnt/kesl-iso -type f \
\( -iname 'kesl_*_amd64.deb' -o -iname '*.deb' \) |
sort
Затем:
DEB='/mnt/kesl-iso/kesl/kesl_12.4.0-1225_amd64.deb'
dpkg-deb -f "$DEB" Package Version Architecture
sha256sum "$DEB"
install -m 0600 -o root -g root \
"$DEB" /root/kesl-install/kesl.deb
umount /mnt/kesl-iso
rmdir /mnt/kesl-iso
Ожидаемые свойства: kesl, версия 12.4.x, архитектура amd64. После этого можно выполнять: apt-get install /root/kesl-install/kesl.deb
Далее
install -m 0600 -o root -g root /dev/null /root/kesl-install/autoinstall.ini
cat > /root/kesl-install/autoinstall.ini <<'EOF'
KSVLA_MODE=No
ENDPOINT_AGENT_MODE=No
EULA_AGREED=Yes
PRIVACY_POLICY_AGREED=Yes
USE_KSN=No
GROUP_CLEAN=Yes
LOCALE=ru_RU.UTF-8
INSTALL_LICENSE=None
UPDATER_SOURCE=KLServers
UPDATE_EXECUTE=No
KERNEL_SRCS_INSTALL=No
USE_GUI=No
CONFIGURE_SELINUX=No
DISABLE_PROTECTION=Yes
INTERCEPTOR_MODE=UseFanotify
ENABLE_TRACES_ON_FIRST_STARTUP=No
EOF
chmod 0600 /root/kesl-install/autoinstall.ini
stat -c '%U:%G:%a %n' /root/kesl-install/autoinstall.ini
/opt/kaspersky/kesl/bin/kesl-setup.pl \
--autoinstall=/root/kesl-install/autoinstall.ini
echo "kesl-setup exit=$?"
systemctl --no-pager status kesl
kesl-control --app-info --json
kesl-control --get-task-list
set +o history
unset HISTFILE
read -rsp 'KESL activation code: ' KESL_CODE; echo
kesl-control --add-active-key "$KESL_CODE"
unset KESL_CODE
set -o history
kesl-control -L --query
Не стартуйте Update (task 6) и File Threat Protection (task 1), пока не срежете дефолты памяти. На 8 ГБ ScanMemoryLimit=8192 и MaxMemory=auto (до 50% RAM, минимум 2 ГБ) слишком много, тем более пока жив ClamAV.
Ключ из -L --query в evidence/репозиторий не копируйте — достаточно статуса Active subscription.
Дальше — секция 3 runbook. Кандидат для ВМ2: ScanMemoryLimit=1024, MaxMemory=2048MB. CPU: OnDemandCPULimit=15, как на пилоте ВМ1, пока ClamAV не снят.
1. Снимок текущих настроек
kesl-control --get-app-settings \
--file /root/kesl-install/app-settings.before.ini
install -m 0600 -o root -g root \
/var/opt/kaspersky/kesl/common/kesl.ini \
/root/kesl-install/kesl.ini.before
awk '/^\[General\]/,/^\[/' /var/opt/kaspersky/kesl/common/kesl.ini | head -n 40
2. Лимит CPU (KESL ещё работает)
kesl-control --set-app-settings \
UseOnDemandCPULimit=Yes OnDemandCPULimit=15
3. Память — только при остановленном KESL, файл целиком не подменять
Сначала посмотрите [General] из шага 1. Если там уже есть ScanMemoryLimit и MaxMemory:
systemctl stop kesl
systemctl is-active kesl
grep -nE '^(ScanMemoryLimit|MaxMemory)=' /var/opt/kaspersky/kesl/common/kesl.ini
sed -i \
-e 's/^ScanMemoryLimit=8192$/ScanMemoryLimit=1024/' \
-e 's/^MaxMemory=auto$/MaxMemory=2048MB/' \
/var/opt/kaspersky/kesl/common/kesl.ini
grep -nE '^(ScanMemoryLimit|MaxMemory)=' /var/opt/kaspersky/kesl/common/kesl.ini
systemctl start kesl
systemctl is-active kesl
kesl-control --get-app-settings | grep -iE 'UseOnDemandCPULimit|OnDemandCPULimit'
Ожидаемо после рестарта
kesl.service=active- в settings:
ScanMemoryLimit=1024,MaxMemory=2048MB,UseOnDemandCPULimit=Yes,OnDemandCPULimit=15 - task 1 и 6 по-прежнему
Stopped - базы всё ещё не загружены
После этого — загрузка баз:
kesl-control --start-task 6 -W
kesl-control --get-task-state 6
kesl-control --app-info --json
START="$(LC_ALL=C date +'%Y/%b/%d %H:%M:%S;1')"
kesl-control --set-schedule 6 RuleType=Hourly \
"StartTime=${START}" RunMissedStartRules=No RandomInterval=0
kesl-control --get-schedule 6
Обязательный следующий шаг — рестарт KESL. В --app-info есть:
Post-update actions: The application module has been updated. Restart the application.
Task 1 до рестарта не запускайте.
systemctl restart kesl
systemctl is-active kesl
kesl-control --app-info --json
grep -nE '^(ScanMemoryLimit|MaxMemory)=' /var/opt/kaspersky/kesl/common/kesl.ini
kesl-control --get-app-settings | grep -iE 'UseOnDemandCPULimit|OnDemandCPULimit'
kesl-control --get-schedule 6
kesl-control --get-task-state 1
kesl-control --get-task-state 6
kesl-control --get-settings 1 \
--file /root/kesl-install/file-threat.before.ini
kesl-control --set-settings 1 \
--add-exclusion /var/lib/docker/volumes/han-processing_redis-safety-data/_data
kesl-control --set-settings 1 \
--add-exclusion /var/lib/docker/volumes/han-processing_otel-queue/_data
kesl-control --start-task 1
kesl-control --set-settings 1 \
ActionOnThreat=DisinfectDeleteIfNotPossible ScanArchived=No
kesl-control --get-task-state 1
kesl-control --get-settings 1
Сразу снимите coexistence, пока OAS прогревается:
date -Is
free -h
swapon --show
vmstat 1 5
systemctl is-active kesl docker han-processing.service
kesl-control --app-info --json | grep -E 'File Threat|databases loaded|license'
/usr/local/sbin/han-vm2-compose ps
docker stats --no-stream
Установка брокера
set -Eeuo pipefail
BASE=/opt/han-chat/services/deployment/kesl
for file in \
kesl_scan_broker.py \
han-kesl-scan-broker.service \
han-kesl-scan-broker.socket \
han-kesl-scan-broker.tmpfiles.conf
do
test -f "$BASE/$file"
test ! -L "$BASE/$file"
done
if getent group han-message-safety >/dev/null; then
test "$(getent group han-message-safety | cut -d: -f3)" = 10001
else
! getent group 10001 >/dev/null
groupadd --system --gid 10001 han-message-safety
fi
install -d -m 0755 -o root -g root /usr/local/libexec
install -m 0750 -o root -g root \
"$BASE/kesl_scan_broker.py" \
/usr/local/libexec/han-kesl-scan-broker
install -m 0644 -o root -g root \
"$BASE/han-kesl-scan-broker.service" \
/etc/systemd/system/han-kesl-scan-broker.service
install -m 0644 -o root -g root \
"$BASE/han-kesl-scan-broker.socket" \
/etc/systemd/system/han-kesl-scan-broker.socket
install -m 0644 -o root -g root \
"$BASE/han-kesl-scan-broker.tmpfiles.conf" \
/etc/tmpfiles.d/han-kesl-scan-broker.conf
systemd-tmpfiles --create \
/etc/tmpfiles.d/han-kesl-scan-broker.conf
systemctl daemon-reload
systemd-analyze verify \
/etc/systemd/system/han-kesl-scan-broker.service \
/etc/systemd/system/han-kesl-scan-broker.socket
Если systemd-analyze verify завершился без ошибок, запуск:
systemctl enable --now han-kesl-scan-broker.socket
systemctl is-active kesl han-kesl-scan-broker.socket
stat -c '%U:%G:%a %n' /run/han-kesl /run/han-kesl/scan.sock
/usr/local/libexec/han-kesl-scan-broker --probe
Ожидаемые права: /run/han-kesl root:han-message-safety:750 /run/han-kesl/scan.sock root:han-message-safety:660
Создаём папку:
install -d -m 0700 -o root -g han-message-safety \
/var/lib/han-kesl-scan \
/var/lib/han-kesl-scan/staging
Проверка и запуск socket
systemd-analyze verify \
/etc/systemd/system/han-kesl-scan-broker.service \
/etc/systemd/system/han-kesl-scan-broker.socket
systemctl enable --now han-kesl-scan-broker.socket
systemctl is-active kesl han-kesl-scan-broker.socket
stat -c '%U:%G:%a %n' /run/han-kesl /run/han-kesl/scan.sock
/usr/local/libexec/han-kesl-scan-broker --probe
journalctl --since '-10 min' --no-pager -u han-kesl-scan-broker.service
Обновить .env editor /opt/han-chat/services/.env MESSAGE_SAFETY_IMAGE=cr.selcloud.ru/han-images/han-message-safety@sha256:225808bd111be03112ab6693b5a10e3d97ae8cdbe5370a5d0aa5a8e2278a3044 Удалить CLAMAV_IMAGE MESSAGE_SAFETY_CLAMAV_HOST MESSAGE_SAFETY_CLAMAV_PORT Добавить MESSAGE_SAFETY_ANTIVIRUS_SOCKET=/run/han-kesl/scan.sock
Активировать config schema 2 NEXT_VERSION='2'
/usr/local/sbin/han-vm2-compose --profile ops run --rm
--entrypoint message-safety-config message-safety-migrate
validate /app/app/artifacts/seed-config.yaml
/usr/local/sbin/han-vm2-compose --profile ops run --rm
--entrypoint message-safety-config message-safety-migrate
create /app/app/artifacts/seed-config.yaml
--version "$NEXT_VERSION" --actor ''
/usr/local/sbin/han-vm2-compose --profile ops run --rm
--entrypoint message-safety-config message-safety-migrate
activate --version "$NEXT_VERSION" --approved-by ''
Вернуть затертые IP editor /opt/han-chat/services/nginx/allowlists/bitrix-webhook-allowlist.conf allow 195.208.184.200; allow 89.208.230.2; allow 195.208.184.34; allow 89.208.228.219; deny all;
editor /opt/han-chat/services/nginx/allowlists/private-caller-allowlist.conf allow 10.0.0.11; deny all;
Переключить только Message Safety
cd /opt/han-chat/services/
deployment/preflight.sh
/usr/local/sbin/han-vm2-compose config --quiet
/usr/local/sbin/han-vm2-compose up -d --no-deps --force-recreate \
message-safety-api message-safety-worker
/usr/local/sbin/han-vm2-compose ps
/usr/local/sbin/han-vm2-compose ps --format "table {{.Service}}\t{{.Status}}\t{{.Ports}}"
HUP NGINX
/usr/local/sbin/han-vm2-compose exec -T nginx nginx -t -c /etc/nginx/nginx.conf
NGINX_ID=$(/usr/local/sbin/han-vm2-compose ps --status running --quiet nginx)
docker kill --signal HUP "$NGINX_ID"
/usr/local/sbin/han-vm2-compose exec -T nginx getent hosts message-safety-api
/usr/local/sbin/han-vm2-compose exec -T message-safety-api \
python -c 'import json,urllib.request; print(json.dumps(json.load(urllib.request.urlopen("http://127.0.0.1:8080/health/ready")), indent=2))'
Тестирование:
Секция 7 — не один скрипт, а пять независимых gates. EICAR только после письменного Security; образец не класть в git, chat и evidence — брать с eicar.org. Пункты 4–5 и cutover нельзя закрыть текущим образом Message Safety (он ещё на ClamAV): сначала 1–3 на хосте.
Все команды на devhanservice — под root. han-processing.service не restart/stop.
0. Перед тестами
kesl-control --get-task-state 1
kesl-control --app-info --json | grep -E 'File Threat|databases loaded|license'
systemctl is-active kesl han-kesl-scan-broker.socket
test -S /run/han-kesl/scan.sock
stat -c '%U:%G:%a %n' /run/han-kesl/scan.sock
/usr/local/libexec/han-kesl-scan-broker --probe
Нужно: task 1 Started, базы Yes, socket root:han-message-safety:660, probe "status":"ready". Если sock нет — systemctl restart han-kesl-scan-broker.socket, не .service.
1. Host OAS (АВЗ.1)
Каталог не в docker volume, /tmp, release, staging:
install -d -m 0700 -o root -g root /root/kesl-eicar-test
date -Is
kesl-control --get-task-state 1
Положите официальный eicar.com в /root/kesl-eicar-test/eicar.com:
curl -fsSL -o /root/kesl-eicar-test/eicar.com
'https://secure.eicar.org/eicar.com'
chmod 0600 /root/kesl-eicar-test/eicar.com
cat /root/kesl-eicar-test/eicar.com >/dev/null
ls -l /root/kesl-eicar-test
kesl-control -E --query -n 20 --reverse
Ожидаемо: объект удалён/в Backup, в журнале EICAR-Test-File / ThreatDetected. Если OAS на запись молчит (как на пилоте ВМ1) — явный ODS:
kesl-control --scan-file /root/kesl-eicar-test/eicar.com
kesl-control -E --query -n 20 --reverse
Уборка (не весь Backup):
kesl-control -B --query --reverse -n 20
kesl-control -B --mass-remove --query "DetectName == 'EICAR-Test-File'"
rm -rf /root/kesl-eicar-test
2. Broker: clean / EICAR / KESL down
install -d -m 0700 -o root -g root /root/kesl-install cat > /root/kesl-install/broker-client.py <<'PY' #!/usr/bin/env python3 import asyncio, json, struct, sys
SOCK = "/run/han-kesl/scan.sock"
async def call(op: str, body: bytes = b"") -> dict: r, w = await asyncio.open_unix_connection(SOCK) header = {"op": op} if op == "scan": header["size"] = len(body) raw = json.dumps(header, separators=(",", ":")).encode() w.write(struct.pack(">I", len(raw)) + raw + body) await w.drain() n = struct.unpack(">I", await r.readexactly(4))[0] resp = json.loads(await r.readexactly(n)) w.close() await w.wait_closed() return resp
async def main() -> None: op = sys.argv[1] body = sys.stdin.buffer.read() if op == "scan" else b"" print(json.dumps(await call(op, body), ensure_ascii=True, sort_keys=True))
if name == "main": if sys.argv[1:] not in (["status"], ["scan"]): raise SystemExit("usage: broker-client.py status|scan") asyncio.run(main()) PY chmod 0700 /root/kesl-install/broker-client.py
Проверка позитивного решения python3 /root/kesl-install/broker-client.py status printf 'HAN kesl broker clean canary\n' | python3 /root/kesl-install/broker-client.py scan
Проверка негативного решения curl -fsSL 'https://secure.eicar.org/eicar.com' | python3 /root/kesl-install/broker-client.py scan
Проверка недоступного сканнера systemctl stop kesl systemctl is-active kesl || true python3 /root/kesl-install/broker-client.py status printf 'error canary\n' | python3 /root/kesl-install/broker-client.py scan
Оба запроса должны вернуть scanner_unavailable. Затем восстановить: systemctl start kesl systemctl is-active kesl kesl-control --start-task 1 kesl-control --get-task-state 1 systemctl restart han-kesl-scan-broker.socket /usr/local/libexec/han-kesl-scan-broker --probe
3. 5 слотов и ~2 файла/с
На 4 ГБ DEV это нагрузка: смотрите free -h / vmstat. Откат OAS: kesl-control --stop-task 1.
python3 - <<'PY'
import asyncio, json, struct, time, statistics
SOCK = "/run/han-kesl/scan.sock"
BODY = b"HAN kesl throughput canary\n"
async def scan():
r, w = await asyncio.open_unix_connection(SOCK)
h = json.dumps({"op": "scan", "size": len(BODY)}, separators=(",", ":")).encode()
t0 = time.perf_counter()
w.write(struct.pack(">I", len(h)) + h + BODY)
await w.drain()
n = struct.unpack(">I", await r.readexactly(4))[0]
resp = json.loads(await r.readexactly(n))
dt = time.perf_counter() - t0
w.close(); await w.wait_closed()
return dt, resp
async def main():
burst = await asyncio.gather(*[scan() for _ in range(5)])
print("burst5", [(round(dt, 3), r.get("verdict") or r.get("error")) for dt, r in burst])
times = []
for _ in range(20):
dt, r = await scan()
assert r.get("verdict") == "clean", r
times.append(dt)
await asyncio.sleep(0.5) # ~2 file/s
times.sort()
p95 = times[int(0.95 * (len(times) - 1))]
print(f"n={len(times)} p50={times[len(times)//2]:.3f}s p95={p95:.3f}s max={times[-1]:.3f}s")
asyncio.run(main())
PY
Gate: все clean, p95 ≤ 60 с. Queue age p95 ≤ 5 с — из метрик Safety (после пункта 4), не из этого скрипта.
4. Message Safety 200 / 403 / 503
Сейчас контейнеры ещё на ClamAV. Пункт 4 — после recreate message-safety-api/worker на образ с bind /run/han-kesl (digest из окна 1.0.1). Clamd пока можно не снимать.
Проверка, что API видит KESL:
/usr/local/sbin/han-vm2-compose exec -T message-safety-api \
python -c 'import json,urllib.request; print(json.dumps(json.load(urllib.request.urlopen("http://127.0.0.1:8080/health/ready")), indent=2))'
antivirus=ok, files=ready (не mock).
- clean
200— text canary с ВМ1, как вRUNBOOK.ru.md(/internal/safety/v2/messages/check,content_kind=text). - malware
403+ sticky — file через реальный versioned object в quarantine S3 (выдуманный key нельзя; EICAR в bucket только если Security разрешил). Повтор того жеmessage_id+body — тот же403. - scanner error
503—systemctl stop kesl, file-check, ожидание503/ files unavailable; затем start kesl + restart socket +--start-task 1.
Пока worker ходит в clamd, это не gate KESL.
5. Smoke, firewall, 24 ч
iptables -S HAN-CHAT-VM2
ufw status verbose
/usr/local/sbin/han-vm2-compose ps
free -h
swapon --show
kesl-control --get-task-state 6
kesl-control --get-schedule 6
С ВМ1: openssl s_client + curl /internal/safety/status из RUNBOOK.ru.md. Сравните HAN-CHAT-VM2 с baseline. 24 ч: без OOM/restart/5xx, hourly Update сам зелёный.
curl --fail --silent --show-error
--cacert /etc/han/ca/vm2-internal-ca.crt
https://prodhanservice.ihan.ru:8443/internal/safety/status
https://processing.internal:8443/internal/safety/status
Cutover (только после 1–5)
Новая монотонная config version (не реактивировать старую):
cd /opt/han-chat/services/
NEXT_VERSION='3'
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
--entrypoint message-safety-config message-safety-migrate \
create /app/app/artifacts/seed-config.yaml \
--version "$NEXT_VERSION" --actor '<OPERATOR>'
/usr/local/sbin/han-vm2-compose --profile ops run --rm \
--entrypoint message-safety-config message-safety-migrate \
activate --version "$NEXT_VERSION" --approved-by '<APPROVER>'
/usr/local/sbin/han-vm2-compose up -d --no-deps --force-recreate \
message-safety-api message-safety-worker
В .env / compose не должно остаться clamd/freshclam. Затем:
/usr/local/sbin/han-vm2-compose up -d --remove-orphans
/usr/local/sbin/han-vm2-compose ps
docker ps -a --format '{{.Names}}' | grep -E 'clamd|freshclam' || echo 'no clamd/freshclam'
docker volume ls | grep -i clam || true
/usr/local/sbin/han-vm2-compose exec -T nginx nginx -t -c /etc/nginx/nginx.conf NGINX_ID=$(/usr/local/sbin/han-vm2-compose ps --status running --quiet nginx) docker kill --signal HUP "$NGINX_ID"
/usr/local/sbin/han-vm2-compose exec -T nginx getent hosts message-safety-api
/usr/local/sbin/han-vm2-compose exec -T message-safety-api
python -c 'import json,urllib.request; print(json.dumps(json.load(urllib.request.urlopen("http://127.0.0.1:8080/health/ready")), indent=2))'
Старый signature-CDN egress закрывается отдельно в firewall/SG — не через compose down -v.
На этом DEV-хосте (3.8 ГиБ, swap 391 МиБ) пункт 3 и file-EICAR через Safety лучше не совмещать с чем-то ещё. Если нужно, могу выписать только gate 1+2 компактным блоком под копирование в 260907_1.md.
Ставим KESL на ВМ1
Копируем на диск: scp -i C:\Users\MI.ssh\prodHan "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.iso" "C:\Users\MI\Documents\job\HAN_new_life\HANapp\docs\kes 12.4\049-16-d-01.sig" root@185.31.164.97:/tmp/
apt install rhash ISO='/tmp/049-16-d-01.iso' command -v rhash rhash --gost "$ISO"
ГОСТ совпал: rhash --gost дал ту же сумму, что на сайте вендора. ISO подлинный. 6a94b16afad211e8b9be5ec86f5379184f2b3a9e5869843fe763e2796e5ac1d3
sudo apt remove -y rhash sudo apt purge -y rhash
Подготовка
free -h
swapon --show
df -hT / /var/lib/docker /opt /tmp
df -ih / /var/lib/docker /opt /tmp
systemctl is-active docker ufw
1.2. SigNoz и volumes
cd /opt/signoz
docker info --format \
'driver={{.Driver}} root={{.DockerRootDir}} containers={{.Containers}} running={{.ContainersRunning}}'
docker compose -f pours/deployment/compose.yaml ps -a
docker stats --no-stream --format \
'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.BlockIO}}\t{{.PIDs}}'
curl -fsS --max-time 5 http://127.0.0.1:8080/api/v1/health
ss -lntp '( sport = :8080 or sport = :4317 or sport = :4318 )'
Снять фактические mountpoint hot-data. Prefix Compose не угадывать:
for c in \
signoz-telemetrystore-clickhouse-0-0 \
signoz-telemetrykeeper-clickhousekeeper-0 \
signoz-metastore-postgres-0 \
signoz-signoz-0
do
echo "=== $c ==="
docker inspect --format \
'{{range .Mounts}}{{.Type}} {{.Name}} {{.Source}} -> {{.Destination}}{{println}}{{end}}' \
"$c"
done
В change record перенести только host-пути данных ClickHouse, ClickHouse
Keeper, PostgreSQL metastore и, если есть отдельный volume приложения
SigNoz. Overlay2, /opt/signoz и /tmp в исключения не входят.
1.3. Firewall и OTLP
ufw status verbose
iptables-save | head
ss -lntp '( sport = :8080 or sport = :4317 or sport = :4318 )'
С ВМ1 (не ICMP):
timeout 3 bash -c 'exec 3<>/dev/tcp/10.0.0.13/4317' \
&& echo 'OTLP gRPC reachable'
Без живого OTLP и healthy стека к установке не переходить.
2. Дистрибутив и установка
ISO='/tmp/049-16-d-01.iso'
install -d -m 0700 -o root -g root \
/root/kesl-install /mnt/kesl-iso
mount -o ro,loop "$ISO" /mnt/kesl-iso
find /mnt/kesl-iso -type f \
\( -iname 'kesl_*_amd64.deb' -o -iname '*.deb' \) |
sort
DEB='/mnt/kesl-iso/kesl/kesl_12.4.0-1225_amd64.deb'
dpkg-deb -f "$DEB" Package Version Architecture
sha256sum "$DEB"
install -m 0600 -o root -g root \
"$DEB" /root/kesl-install/kesl.deb
umount /mnt/kesl-iso
rmdir /mnt/kesl-iso
apt-get remove -y rhash
apt-get purge -y rhash
apt-get autoremove -y
Снимки до установки:
test -f /etc/docker/daemon.json && \
cp -a /etc/docker/daemon.json /root/kesl-install/docker-daemon.before.json
iptables-save > /root/kesl-install/iptables.before
ufw status verbose > /root/kesl-install/ufw.before
ss -lntp '( sport = :8080 or sport = :4317 or sport = :4318 )' \
> /root/kesl-install/listeners.before
ls -l /root/kesl-install
apt-get install /root/kesl-install/kesl.deb
2.3. Первоначальная настройка без защиты
Значения EULA, Privacy Policy и KSN — после согласования, не механически.
Для этого окна, как на ВМ1/ВМ2: USE_KSN=No.
install -m 0600 -o root -g root /dev/null /root/kesl-install/autoinstall.ini
cat > /root/kesl-install/autoinstall.ini <<'EOF'
KSVLA_MODE=No
ENDPOINT_AGENT_MODE=No
EULA_AGREED=Yes
PRIVACY_POLICY_AGREED=Yes
USE_KSN=No
GROUP_CLEAN=Yes
LOCALE=ru_RU.UTF-8
INSTALL_LICENSE=None
UPDATER_SOURCE=KLServers
UPDATE_EXECUTE=No
KERNEL_SRCS_INSTALL=No
USE_GUI=No
CONFIGURE_SELINUX=No
DISABLE_PROTECTION=Yes
INTERCEPTOR_MODE=UseFanotify
ENABLE_TRACES_ON_FIRST_STARTUP=No
EOF
chmod 0600 /root/kesl-install/autoinstall.ini
stat -c '%U:%G:%a %n' /root/kesl-install/autoinstall.ini
/opt/kaspersky/kesl/bin/kesl-setup.pl \
--autoinstall=/root/kesl-install/autoinstall.ini
echo "kesl-setup exit=$?"
При INSTALL_LICENSE=None setup может вернуть 71. Не запускать повторно,
если kesl.service active и File Threat Protection Stopped.
systemctl --no-pager --no-legend status kesl || true
kesl-control --app-info
kesl-control --get-task-list
free -h
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps
curl -fsS --max-time 5 http://127.0.0.1:8080/api/v1/health
Ожидается: kesl запущен, задача 1 не Started, контейнеры healthy.
3. Resource budget до Update и FTP
3.1. Снимок
kesl-control --get-app-settings \
--file /root/kesl-install/app-settings.before.ini
install -m 0600 -o root -g root \
/var/opt/kaspersky/kesl/common/kesl.ini \
/root/kesl-install/kesl.ini.before
awk '/^\[General\]/,/^\[/' /var/opt/kaspersky/kesl/common/kesl.ini | head -n 40
3.2. Лимит CPU (KESL ещё работает)
kesl-control --set-app-settings \
UseOnDemandCPULimit=Yes OnDemandCPULimit=15
3.3. Память — только при остановленном KESL
Файл целиком не подменять. Сначала смотрите [General] из шага 3.1.
systemctl stop kesl
systemctl is-active kesl || true
grep -nE '^(ScanMemoryLimit|MaxMemory)=' \
/var/opt/kaspersky/kesl/common/kesl.ini
sed -i \
-e 's/^ScanMemoryLimit=8192$/ScanMemoryLimit=1024/' \
-e 's/^MaxMemory=auto$/MaxMemory=2048MB/' \
/var/opt/kaspersky/kesl/common/kesl.ini
grep -nE '^(ScanMemoryLimit|MaxMemory)=' \
/var/opt/kaspersky/kesl/common/kesl.ini
systemctl start kesl
systemctl is-active kesl
kesl-control --get-app-settings | grep -iE \
'UseOnDemandCPULimit|OnDemandCPULimit|ScanMemoryLimit|MaxMemory'
free -h
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps
На constrained 4 ГиБ замените значения в sed на 512 и 1024MB.
Ожидаемо: kesl.service active; task 1 и 6 Stopped; базы ещё не
загружены; ClickHouse/SigNoz healthy.
4. Активация
Код не помещать в autoinstall.ini, репозиторий, evidence, чат и history.
Нужен открытый egress из раздела 0.1.
set +o history
unset HISTFILE
read -rsp 'KESL activation code: ' KESL_CODE; echo
kesl-control --add-active-key "$KESL_CODE"
unset KESL_CODE
set -o history
kesl-control -L --query
kesl-control --app-info
В evidence — только статус вроде Active subscription и срок, не GUID
ключа. Если лицензия Inconsistent update или недействительна — stop.
5. АВЗ.2 — базы
ID подтвердить через --get-task-list (Update = 6).
kesl-control --get-settings 6
kesl-control --start-task 6 -W
kesl-control --get-task-state 6
kesl-control --app-info --json
free -h
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps
START="$(LC_ALL=C date +'%Y/%b/%d %H:%M:%S;1')"
kesl-control --set-schedule 6 RuleType=Hourly \
"StartTime=${START}" RunMissedStartRules=No RandomInterval=0
kesl-control --get-schedule 6
systemctl restart kesl
systemctl is-active kesl
kesl-control --app-info --json
grep -nE '^(ScanMemoryLimit|MaxMemory)=' \
/var/opt/kaspersky/kesl/common/kesl.ini
kesl-control --get-app-settings | grep -iE \
'UseOnDemandCPULimit|OnDemandCPULimit'
kesl-control --get-schedule 6
kesl-control --get-task-state 1
kesl-control --get-task-state 6
6. Исключения hot-data
Только фактические mountpoint из раздела 1.2. Кандидаты: данные ClickHouse,
ClickHouse Keeper, PostgreSQL metastore. Не исключать /var/lib/docker,
overlay2, /opt/signoz, /var/lib/han-deploy/incoming, /tmp, /root.
Снять mountpoint:
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps --format '{{.Name}}'
for c in \
signoz-telemetrystore-clickhouse-0-0 \
signoz-telemetrykeeper-clickhousekeeper-0 \
signoz-metastore-postgres-0
do
echo "=== $c ==="
docker inspect --format \
'{{range .Mounts}}{{if eq .Type "volume"}}{{.Source}} dest={{.Destination}} vol={{.Name}}{{println}}{{end}}{{end}}' \
"$c"
done
kesl-control --get-settings 1 \
--file /root/kesl-install/file-threat.before.ini
kesl-control --set-settings 1 \
--add-exclusion /var/lib/docker/volumes/signoz-telemetrystore-0-0-data/_data
kesl-control --set-settings 1 \
--add-exclusion /var/lib/docker/volumes/signoz-telemetrykeeper-0-data/_data
kesl-control --set-settings 1 \
--add-exclusion /var/lib/docker/volumes/signoz-metastore-postgres-0-data/_data
kesl-control --set-settings 1 ScanArchived=No
kesl-control --get-settings 1
Каждое исключение: владелец, причина (write-hot telemetry/metadata),
компенсация (FTP вне volume + периодический scan-file host-дерева
/opt/signoz/scripts), срок пересмотра, подтверждение Security.
7. Узкий on-demand scan-file
ODS schedules, кроме Update, оставить Manual. Не сканировать volumes ClickHouse/PostgreSQL и не запускать Container Scan.
kesl-control --get-task-list
kesl-control --get-schedule 2
kesl-control --set-schedule 2 RuleType=Manual
kesl-control --scan-file /opt/signoz/scripts --action Inform
kesl-control --get-task-state 1
free -h
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps
Ожидается: scan-file без ошибок, FTP всё ещё Stopped, стек healthy. Если вырос swap или unhealthy — остановить scan и не включать task 1.
8. Host protection — АВЗ.1
На Ubuntu 24.04 с fanotify параметр InterceptorProtectionMode не
поддерживается. Штатный режим — блокировка на время проверки. Откат:
kesl-control --stop-task 1.
kesl-control --start-task 1
kesl-control --set-settings 1 \
ActionOnThreat=DisinfectDeleteIfNotPossible ScanArchived=No
kesl-control --get-task-state 1
kesl-control --get-settings 1
kesl-control --app-info --json
free -h
docker stats --no-stream --format \
'table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}\t{{.PIDs}}'
cd /opt/signoz
docker compose -f pours/deployment/compose.yaml ps
ufw status verbose
ss -lntp '( sport = :8080 or sport = :4317 or sport = :4318 )'
Пилот: каждые 15 минут — health, OTLP, RAM/swap, события KESL, firewall.
При деградации: kesl-control --stop-task 1. Не расширять исключения
вслепую.
10. Приёмка стека и сужение egress
На ВМ3:
systemctl is-active kesl docker
kesl-control --app-info
kesl-control --get-task-state 1
kesl-control --get-task-state 6
kesl-control --get-schedule 6
cd /opt/signoz
sudo PRIVATE_IP=10.0.0.13 ./scripts/30-verify-signoz.sh
docker compose -f pours/deployment/compose.yaml ps
ufw status verbose
diff -u /root/kesl-install/ufw.before <(ufw status verbose) || true
ss -lntp '( sport = :8080 or sport = :4317 or sport = :4318 )'
free -h
swapon --show
df -hT / /opt /var/lib/docker
С ВМ1 повторить TCP 4317. Слушатели 8080 только на 127.0.0.1,
4317/4318 только на 192.168.0.5. Сравнить UFW с baseline: новых
правил KESL быть не должно.
24 часа: без OOM/restart/unhealthy, hourly Update сам зелёный, диск ClickHouse не упёрся в stop-порог.
rm -rf /root/kesl-eicar-test
# после копирования evidence:
# rm -rf /root/kesl-install
# rm -f /var/lib/han-deploy/incoming/049-16-d-01.iso \
# /var/lib/han-deploy/incoming/049-16-d-01.sig
13. Эксплуатационный режим
- Update (ID 6): каждый час; нужен постоянный узкий egress к KLServers.
- File Threat Protection (ID 1): постоянно,
DisinfectDeleteIfNotPossible,ScanArchived=No. - ODS: по согласованию в низкую нагрузку; не полный диск и не volumes БД.
- ContainerScan: не использовать при текущей лицензии.
- Ежедневно: лицензия, task 1
Started, дата баз, ошибки KESL, health SigNoz, свободное место/opt. - После upgrade KESL/kernel/Docker: повтор пилота и evidence delta.
Обновление образов SigNoz (20-deploy-signoz.sh) — отдельное break-glass
окно; его egress к Docker Hub/GitHub не заменяет allow-list KESL.