Skip to content

v4.2: защита по аудиту флота — DNAT, CrowdSec scope, na-fw, SYNPROXY, честная диагностика - #46

Merged
jestivald merged 15 commits into
mainfrom
feat/v4.2-protect
Oct 3, 2026
Merged

jestivald merged 15 commits into
mainfrom
feat/v4.2-protect

Conversation

@jestivald

@jestivald jestivald commented Oct 3, 2026 •

Copy link
Copy Markdown
Owner

v4.2 — вторая часть исправлений по аудиту живого флота (~30 нод): защита закрывает то, что шло мимо неё, перестаёт резать своих, а диагностика перестаёт врать. Подробно — раздел v4.2 в CHANGELOG.md.

Что внутри

Защита (protect.sh)

  • DNAT_GUARD=1 — опубликованные Docker-порты (forward) получают проверки источника: whitelist, autoban, блок-листы, bogon.
  • CROWDSEC_SCOPE=ssh — блок-листы CrowdSec только на SSH (bouncer в set-only, правило ставит тулкит, whitelist исключён); all — как раньше.
  • Лог анти-скана только на переходах suspect/бан; именованные счётчики c_*; ban-once без бана с первого превышения.
  • SYNPROXY реально работает: проверка nft_synproxy, правило до invalid-drop, tcp_loose=0; бан, блок-листы и SYN-rate решаются до synproxy.
  • na-fw allow|unban — whitelist и разбан во всех слоях одной командой; локальные правила na_filter.d; баны переживают ре-ран; none в conf; SSH_PORT без вечного автодетекта.

Диагностика, оптимизатор, отчёт

  • na-diagnose: дельты счётчиков между запусками, порты из живых правил, CrowdSec по источникам, whitelist в 4 слоях, DNAT мимо na_filter, серты Caddy/nginx, убраны ложные ▲; --json --fast для частого опроса.
  • optimize: сверка sysctl с файлом-виновником, резерв портов ноды, RPS/XPS только где нужны, journald 10-* + persistent, откат runtime без ребута, проверки XanMod (Secure Boot, /boot, initrd, драйвер NIC), NA_IPV6_FORWARD.
  • na-report: CrowdSec по строкам raw, честные events_5m/unique_src_5m, asn_enrichment.

Правки по независимому ревью (c9fb778)

  • 🔴 Переход на CROWDSEC_SCOPE=ssh ронял bouncer: restart после наших таблиц — старый процесс сносил таблицу, новый в set-only не стартовал. Теперь stop → таблицы → start → проверка, иначе откат на all.
  • 🔴 na-fw молча падал на середине при пустом v6-whitelist: слои расходились.
  • 🟠 SYNPROXY обходил per-IP лимиты и блок-листы; TCP_PORTS=none ронял прогон.
  • 🟠 rollback optimize выключал форвардинг (Docker bridge) и мог опустить conntrack_max ниже count.
  • 🟡 Возврат ручного crowdsec-nft-scope при откате, whitelist-наборы с auto-merge, SSH_PORT без вечной метки, мелочи na-fw (лок, nft -c до изменений, отказ на /0), cscli --limit 0, тяжёлый --json → --fast, брошенные серты (▲ вместо ✘), сдвиг страны в na-report, v6-форвардинг на маршрутизирующих нодах, склейка резерва портов ядром.

Найдено новым CI (5bfa5b3)

  • nft 0.9.3 (Ubuntu 20.04): na-fw правил набор whitelist правила scope flush + add всем списком — при адресе внутри CIDR того же списка «interval overlaps», транзакция откатывалась, набор не обновлялся. Теперь поэлементно, покрытый адрес подтверждается get element.

Проверки

  • Локально: 13 юнит-наборов, shellcheck (gate и warning), lint-pipefail — зелёные.
  • CI зелёный (eaa7543): smoke-матрица теперь с Ubuntu 20.04 (nft 0.9.3 — самый старый из заявленных; Debian 11 вне LTS, его образ не ставит пакеты — убран, отмечено в README); tests/cs-scope-nft.sh — файл правила scope на настоящем nft; tests/crowdsec-e2e.sh — переключение ssh↔all на настоящем crowdsec-firewall-bouncer v0.0.36 (bouncer не падает, решения доезжают в обе стороны, cscli --limit 0 принимается); nft-behavior — SYNPROXY: SYN-rate, бан, whitelist.

До merge

  • CI зелёный
  • подписи 6 модулей minisign — последним коммитом (RELEASING.md)
  • merge --no-ff, тег v4.2, релиз

🤖 Generated with Claude Code

jestivald and others added 14 commits October 3, 2026 17:03
…скана на переходах, na-fw, локальные правила, баны переживают ре-ран

- forward: новые DNAT-соединения → dnat_guard (whitelist/fleet → пропуск, autoban/
  blocklist/bogon → drop); DNAT_GUARD=0 — выкл
- CROWDSEC_SCOPE=ssh (дефолт): bouncer set-only + своё правило только на SSH с
  исключением whitelist; all — как раньше; ручной crowdsec-nft-scope.service поглощается
- лог [na portscan] только на переходе в suspect/бан (цепочки ps_suspect*/ps_ban*);
  именованные счётчики c_* на всех drop; na-fw-status их показывает
- SSH ban-once: бан только на повторном переборе (sshs4/6, 3× burst), не на ретрансмите
- SYNPROXY до ct state invalid drop + nf_conntrack_tcp_loose=0; забаненные — раньше
- анти-амплификация UDP (UDP_AMP_DROP), DHCPv6-ответы, :: убран из bogon_v6 (DAD)
- na-fw allow add|del|list, unban — whitelist во всех 4 слоях, nft -c до замены файла
- na_filter.d/{table,input}/*.nft — локальные правила, вклеиваются в каждую генерацию
- autoban/suspect с оставшимся сроком переносятся через ре-ран
- none = явно пусто (WHITELIST/UDP_PORTS/TCP_PORTS/UDP_BULK_PORTS/NODE_PORT_PEERS,
  NODE_PORT=none); пустой ENV — по-прежнему «как в conf»
- SSH: Listen сокет-юнита, все порты sshd -T, SSH_CONNECTION у предков (sudo),
  автодетект SSH_PORT больше не персистится (устаревший — оба порта + warn)
- detect_node_port: rw-node → host-сеть контейнеры по .Config.Image → .env;
  bridge-тенант не в счёт; несколько агентов — warn
- ctguard: ENABLE_CTGUARD=0 снимает таймер/таблицу/конфиг; DNAT-клиенты не фантомы
- fleet.env: токены валидируются, значения %q; фиды: префиксы шире /8 (v6 /19) — отказ
- na-firewall.service до network-pre (DefaultDependencies=no), SAFETY_DELAY ≥ 30,
  CrowdSec ставится до взвода сейфти, «y» проверяет, что таблица на месте
- маркер: crowdsec_scope, dnat_guard, nft_sha256, include_dir/files, node_port=none
- tests: apply-smoke/protect-unit/common-unit/ctguard-unit/nft-behavior (DNAT, SYNPROXY,
  ban-once, счётчики на настоящем ядре)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…XPS только где нужны, journald 10-*.conf + persistent, без v6-форвардинга, откат runtime без ребута, проверки XanMod; common — default_iface после dev, apt ждёт dpkg-лок

- sysctl: после применения значения наших файлов сверяются с ядром; перебивший ключ файл
  назван (systemd-analyze cat-config или перебор каталогов по имени), незаписанные ключи —
  отдельно. Снимок исходных значений — только при первом применении (sysctl.orig).
- ip_local_reserved_ports: LISTEN-порты xray/rw-core/rw-node (вкл. 127.0.0.1) и порт
  node-агента внутри 10000-65535; резерв оператора сохраняется, ушедший порт снимается.
- net.ipv6.conf.all.forwarding убран: при accept_ra=1 ядро перестаёт принимать RA.
- na-rps-setup: без RPS на 1 vCPU и при RX-очередей ≥ ядер, XPS только с NA_XPS=1,
  исходные маски — снимок rps-orig.tsv; маршрут — токен после dev.
- journald: 10-na-size.conf (старое na-size.conf снимается), volatile → Storage=persistent,
  если Storage= не задан явно.
- XanMod: отказ при Secure Boot и /boot < 200 МБ; initrd и драйвер NIC проверяются до
  «нужна перезагрузка».
- rollback optimize: sysctl/маски RPS-XPS/THP из снимков без ребута, оба имени drop-in.
- common: default_iface — токен после `dev` (venet0, multipath); apt_install —
  DPkg::Lock::Timeout=120.
- Тесты: новый tests/optimize-unit.sh, расширен tests/rps-unit.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…SI avg60, порты из живых правил, CrowdSec по источникам, 4 слоя whitelist, DNAT мимо na_filter, слушатели вне файрвола, просроченный серт и серты Caddy/nginx, без ложных ▲

- Снимок diag-counters.last (boot_id, окно ≥30 с): UDP RcvbufErrors (v4+v6), softnet
  drop/squeeze, ListenOverflows, steal — по приросту, а не с загрузки.
- Ложные ▲: ENABLE_XANMOD=0, уступка ротации стансе с капом, volatile-журнал и журнал ≈
  аптайму, лог анти-скана — доля журнала за сутки (не «>100000 за загрузку»), буферы от
  RAM-tier (+rmem_default), RPS при RX-очередей ≥ ядер, reboot-required от стоковых ядер.
- Порты для сенсоров — живые правила → protect.conf (обе идиомы := и =) → маркер;
  расхождение правил с conf — ▲ с последствиями ре-рана.
- CrowdSec: решения с -a по origin (локальные / CAPI+lists), scope из маркера,
  источники acquisition; эффективный allowlist (все s02-enrich/*.yaml) как 4-й слой.
- Новые сенсоры: DNAT-порты (docker + nft), публичные слушатели и порты без слушателя,
  MemAvailable/своп/balloon, nftables.service + flush ruleset, хэш na_filter.nft,
  счётчики c_*, порт xray в эфемерном диапазоне, обновление XanMod, docker без max-size,
  OOM за сутки по всем загрузкам.
- Серты: Caddy (docker volume / пакетный), ssl_certificate из nginx; просроченный — ✘,
  флаг «найден» отдельно.
- --json: новые поля только в хвосте (16 шт.).
- tests/diagnose-unit.sh: +12 разделов, сверка текста без escape-кодов цвета.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…е events_5m/unique_src_5m рядом с ban_rate_5m, asn_enrichment ok|partial|unavailable, JSON через json_escape

- drops_by_reason.crowdsec — активные локальные решения (строки `-o raw` с числовым id),
  crowdsec_decisions_all — с CAPI/списками (-a).
- ban_rate_5m сохранён ради совместимости; новые поля — в хвосте объекта.
- Имя AS из whois с управляющим символом больше не ломает --json.
- Новый tests/na-report-unit.sh.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…и оптимизатор; фрагмент CHANGELOG ветки diag

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…в современных ядрах нет), README/CHANGELOG защитной части

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… NA_REF-примеры

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…и не резервируются; анти-скан на 100% — «ослеп», а не «режет клиентов»

- diagnose listen_rows udp: UNCONN xray/rw-core на эфемерном порту вне UDP_PORTS —
  исходящий сокет (на нодах их десятки), не в «слушают публично» и не в «без резерва»
- optimize na_node_listen_ports: только TCP-LISTEN + UDP_PORTS из protect.conf — иначе
  ip_local_reserved_ports засорялся случайными портами и менялся каждый прогон
- dynset: ps*/psc* без timeout на 100% — ▲ «новые сканеры не ловятся», ✘ — только для
  лимитеров клиентов (SYN/UDP/SSH/ICMP/node-port)
- окно дельт «45 с», а не «за 0 мин»

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…о :22 не ▲; set-only без правил при решениях — ▲)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…од pipefail, SYNPROXY без обхода лимитов, откат без потери форвардинга, брошенные серты, CI на старых nft и настоящем CrowdSec

- protect: переключение CROWDSEC_SCOPE в порядке stop → таблицы/режим → start → проверка
  (restart после наших таблиц: старый процесс сносил таблицу, новый в set-only не стартовал);
  не поднялся — откат на all; all удаляет наши таблицы и не перезапускает обычный bouncer;
  whitelist правила — именованные наборы с auto-merge; ручной crowdsec-nft-scope возвращается
  при откате; SYNPROXY: бан/блок-листы/SYN-rate до synproxy, whitelist сильнее бана, пустой
  TCP_PORTS не ставит synproxy, warn про глобальный tcp_loose=0; устаревший SSH_PORT без метки
  explicit; бюджет журнала по сумме лог-правил; detect_ssh_port без loopback
- na-fw: nft -c до любых изменений, лок protect, отказ на префиксах шире /8 (/16), наборы
  правила scope на ходу, не падает под pipefail на пустой семье
- rollback optimize: форвардинг не возвращается из снимка, conntrack_max не ниже 2× count
- optimize: NA_IPV6_FORWARD (авто по Ip6OutForwDatagrams, закрепление в conf); наш порт
  вырезается из диапазона, склеенного ядром с портом оператора
- diagnose: --json --fast; cscli --limit 0; брошенный серт — ▲ и cert_stale_*, а не ✘
- na-report: разделитель \x1f (пустая страна не сдвигает имя AS); cscli --limit 0
- тесты: cs-scope-nft (настоящий nft, в smoke + nft-behavior), crowdsec-e2e (настоящий
  bouncer), SYNPROXY в nft-behavior, Debian 11 / Ubuntu 20.04 в smoke-матрице

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…3 откатывал flush+add при адресе внутри CIDR), Debian 11 без debian-security в смоуке, e2e регистрирует bouncer в LAPI

Ubuntu 20.04 (nft 0.9.3): `add element` всем списком падал «interval overlaps», если адрес
лежит внутри CIDR из того же списка, и транзакция вместе с flush откатывалась — живой набор
whitelist правила CROWDSEC_SCOPE не обновлялся. Теперь add/del по одному элементу, покрытый
CIDR-ом адрес подтверждается `get element` (как в основном whitelist).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…debian-security вне LTS отдаёт 404)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…в из индексов, в snapshot тоже); старый nft покрывает Ubuntu 20.04 (0.9.3); README/CHANGELOG — что гоняется в CI

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jestivald jestivald changed the title v4.2 (WIP): защита по аудиту флота — DNAT, CrowdSec scope, na-fw, логи, диагностика v4.2: защита по аудиту флота — DNAT, CrowdSec scope, na-fw, SYNPROXY, честная диагностика Oct 3, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jestivald
jestivald marked this pull request as ready for review October 3, 2026 19:43
@jestivald
jestivald merged commit 92d2706 into main Oct 3, 2026
9 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant