Внедрение KESL на ВМ2 + замена CLAMAV на KESL

This commit is contained in:
mi
2026-09-08 01:39:37 +03:00
parent 85df788f2d
commit fdfdeaffb4
43 changed files with 2210 additions and 329 deletions
@@ -62,7 +62,7 @@ SigNoz относится к этому классу, если его UI, OTLP
- public `443` разрешает только exact `/bitrix/sync/webhook/contact` и `/bitrix/sync/webhook/alert`; остальные paths закрыты;
- private ingress `8443/tcp` разрешён только от security group ВМ1 и утверждённого ops path для Message Safety/internal API;
- ни один public запрос ВМ2 не проходит через nginx ВМ1;
- `freshclam` имеет egress только к утверждённым источникам сигнатур;
- host KESL имеет egress только к утверждённым источникам обновления из operator KESL runbook; Message Safety и broker не получают общий internet egress;
- `bitrix-sync` имеет HTTPS egress только к утверждённому порталу Bitrix24;
- Safety worker имеет доступ только к managed PostgreSQL, S3-quarantine и доверенному DNS resolver;
- локальный OTEL Collector имеет private egress к SigNoz;
@@ -513,23 +513,28 @@ certificate/key проверяются preflight. Успешный hook обяз
при ненулевом exit code. Иначе Certbot/оркестратор может пометить успешный
renewal как hook error.
### Daemon и updater как разные security-профили
### Host KESL и root-owned broker
Если один vendor image используется для daemon и updater, им задаются разные
сети, mounts и health semantics. Проверенный паттерн ClamAV:
KESL 12.4 standalone и custom integration broker работают на host VM2, вне
Compose. Граница между non-root Message Safety worker и privileged host:
- `clamd` не имеет signature-CDN egress, читает signatures read-only и имеет
healthcheck реального daemon socket;
- `freshclam` один получает ограниченный egress и write к signatures;
- оба используют vendor `init-unprivileged` и только выделенные writable
`/run/clamav`, `/var/log/clamav` и `/tmp`;
- updater запускается как постоянный foreground daemon, чтобы restart policy
не превращала успешный one-shot exit в download loop/rate limit;
- унаследованный healthcheck, проверяющий отсутствующий в updater-контейнере
daemon, отключается; updater контролируется по `Up`, restart count, логам и
возрасту сигнатур;
- security policy разрешает настроить порог возраста не выше `720` часов
(30 дней); production-like seed использует более строгие `240` часов.
- root-owned broker слушает только Unix socket `/run/han-kesl/scan.sock`;
TCP listener и Docker socket запрещены;
- socket доступен только выделенной группе worker; owner/group/mode
проверяются после каждого restart/reboot;
- worker не получает `kesl-control`, shell или произвольный host path;
- broker принимает bounded request, создаёт контролируемый временный файл,
вызывает только `kesl-control --scan-file --action Inform` и гарантированно
очищает временные данные;
- только однозначный `clean` допускает allow; `infected` даёт deny; timeout,
stale database, неизвестный output/exit code и недоступность scanner дают
retry/`503`;
- KESL обновляет database ежечасно; update egress принадлежит host KESL и
ограничен approved sources;
- policy допускает `max_signature_age_hours` не выше `720`, seed — `240`.
Формат `kesl-control`, socket permissions, cleanup и throughput этой custom
integration подтверждаются gates на target VM2 с фактическим KESL 12.4.
Ошибки `read-only file system` устраняются точечным writable mount. Запрещено
лечить их глобальным `read_only: false`, root, `privileged` или broad
@@ -638,8 +643,8 @@ Fail2ban обязателен для SSH, временно или постоян
содержимому, а не только по декларации Compose;
- runtime/migration/config-admin DB roles разделены, временные cross-schema
grants выданы и отозваны владельцем;
- healthcheck проверяет процесс, реально присутствующий в контейнере, а
updater freshness контролируется отдельным сигналом;
- healthcheck проверяет процесс, реально присутствующий в контейнере, а KESL
broker/database freshness контролируется отдельным host-сигналом;
- healthcheck-команда и все её binaries подтверждены внутри exact pinned
digest; отсутствие `curl`/`wget` не обнаруживается впервые в production;
- внутренние ports недоступны извне;