Files
EvoFirewall/docs/agents.md
T
Denozordec d552f4f326
Build and Push EvoFirewall Docker Image / build-and-push (push) Successful in 1m45s
Build and Push EvoFirewall Docker Image / create-release (push) Skipped
feat(api): implement self-update mechanism for Linux agents
- Added a `maybe_self_update` function in `evofw-firewall.sh` to allow agents to pull the latest version of the sync script from the server, enhancing the agent's ability to stay updated.
- Updated the `/v1/agent/sync-script` endpoint to return ETag and script SHA256 headers, enabling efficient caching and conditional requests.
- Modified the agent policy response to include `script_sha256`, providing visibility into the current version of the sync script.
- Enhanced tests to verify the self-update functionality and ensure correct behavior of the sync script endpoint.

These changes improve the maintainability and reliability of Linux agents by enabling automatic updates of critical scripts.
2026-08-15 16:56:00 +07:00

10 KiB
Raw Blame History

Agents

Short install (рекомендуется)

В UI /agentsДобавить агента:

  1. Создаётся агент со статусом Invited (сразу виден в таблице) + install-ссылка.
  2. Скопируйте one-liner (колонка Install или Sheet):

Linux:

curl -fsSL https://<cp>/agent-install/<id> | bash

MikroTik:

/tool fetch url="https://<cp>/agent-install/<id>" dst-path=evofw-install.rsc; /import file-name=evofw-install.rsc
  1. После enroll статус станет Pending — одобрите агента (Approve).
  2. Approved — агент синхронизирует политику.

Повторный запуск той же install-ссылки на хосте, где агент уже стоит: обновляет sync-скрипт / timer (или MikroTik scheduler) и пересоздаёт nft rules (в т.ч. deny_port_hits), без повторного enroll — CLIENT_ID/token сохраняются. Сбрасывается last_hash, затем сразу force sync. Полный переустановки с новым токеном: EVOFW_INSTALL_FORCE=1 (Linux).

API (auth): POST /api/v1/install-links { "name": "web-01", "platform": "linux" | "mikrotik" }.

Linux (legacy one-liner)

curl -fsSL https://<cp>/v1/agent/install.sh | \
  EVOFW_CP_URL=https://<cp> \
  EVOFW_SEED=<seed> \
  EVOFW_CLIENT_NAME="web-01" \
  bash

Создаёт нового агента со статусом Pending (без Invited).

Файлы: /etc/evofw/agent.conf, /usr/local/sbin/evofw-firewall.sh, timer evofw-firewall.timer (default 1min).

Install сам ставит зависимости через apt/dnf/yum/apk: curl, jq (или python3), nftables/iptables(+ipset). Планировщик: systemd timer если есть /run/systemd/system, иначе ставит cron/cronie и пишет crontab. Значения в agent.conf всегда в single quotes (имена с пробелами безопасны). Sync при статусе pending завершается с exit 0 (pending approval), чтобы systemd timer не был failed.

Если /etc/evofw/agent.conf уже есть — install переходит в update: скачивает свежий sync-script + uninstall.sh, перезаписывает unit/timer, оставляет токен. EVOFW_INSTALL_FORCE=1 — полный re-enroll (новый токен; для уже Approved install-link обычно не сработает).

Linux self-update (sync-script)

После того как на хосте стоит скрипт с maybe_self_update, агент сам подтягивает новую версию при каждом timer (~1 мин), до GET /v1/agent/policy (pending тоже обновляются):

  1. sha256 локального /usr/local/sbin/evofw-firewall.sh
  2. GET /v1/agent/sync-script с If-None-Match: "<sha256>"304 = без изменений
  3. 200: проверка shebang + sha256 тела → install -m 755, сброс last_hash, exec EVOFW_SKIP_SELF_UPDATE=1 новой копии
  4. Ошибка download/verify — лог и продолжение текущим скриптом

GET /v1/agent/policy содержит script_sha256 (не входит в policy.hash).

Bootstrap: агенты без maybe_self_update не умеют самообновляться. После деплоя API — один re-run install-ссылки (или ручная замена sync-script). Дальше curl не нужен.

MikroTik scheduler не обновляется этим путём — только повторный import install .rsc.

Uninstall (Linux):

curl -fsSL https://<cp>/v1/agent/uninstall.sh | bash
# или локально после install:
sudo /usr/local/sbin/evofw-uninstall.sh

Backend auto-detect: nft → ipset → iptables.

Whitelist: nft chain policy drop + allow set. Blacklist: policy accept + deny set.

Per-IP blocked stats (Linux)

Linux agent reports optional ip_hits in POST /v1/agent/apply-report:

  • nft: tries set deny_v4 with flags interval; counter;. If the kernel rejects counters on interval sets, falls back to plain interval (aggregate Traffic ↓ still works; per-IP empty).
  • Upgrade path: on install-link re-run, last_hash is cleared once so sets/chain can be recreated (chain deleted before set replace) — обновляет и port-hit правила.
  • ipset: prefers hash:net … counters on create; existing sets without counters are left as-is.
  • Payload: only entries with packets > 0, top 200 by packets.
  • Control plane: agent_ip_block_stats, accumulates deltas of absolute kernel counters (как Traffic ↓). После flush set/chain (policy apply) CP сбрасывает per-IP baseline (last_reported), иначе вторая эпоха счётчиков теряется (Traffic растёт, Blocked IPs — нет).
  • GET /api/v1/agents/:id/blocked-ips, reset via POST …/stats/reset.
  • UI: agent detail → Blocked IPs. Sum of Blocked IPs ≈ Traffic ↓ для deny (при default accept); default-drop / allow в Traffic считаются отдельно.

IPv6 skipped.

Destination ports (Linux nft)

На nft агент ведёт dynamic set deny_port_hits (ipv4_addr . inet_proto . inet_service, timeout 1h, counter):

  • Deny rule для tcp/udp: update @deny_port_hits { ip saddr . meta l4proto . th dport } + drop; прочие протоколы — plain drop.
  • В apply-report: optional port_hits top 500 { ip, port, protocol, packets }.
  • CP: agent_port_block_stats (absolute deltas). Set не flush’ится на каждый policy apply (элементы живут по timeout) — baseline не сбрасывается при Traffic flush.
  • GET /api/v1/agents/:id/blocked-ports — aggregate top 50 портов; в blocked-ips у каждого IP — ports top 5.
  • UI: Top ports + колонка Ports в Blocked IPs (только platform=linux).
  • ipset/iptables: port_hits: []. MikroTik — без port hits.
  • Агенты с self-update подтянут nft-правила сами; без него — один re-run install one-liner (см. выше).

IPv6 skipped.

Host firewall snapshot + Port ACL (Linux)

Observed (Host firewall)

Каждый sync агент собирает best-effort снимок и шлёт в apply-report.host_firewall:

  • nft list ruleset, iptables-save, optional ufw / firewall-cmd, ss -lntu
  • Каждое правило: ownership: evofw | foreign (метка по имени table/chain/comment evofw)
  • CP: agent_host_firewall_snapshots; GET /api/v1/agents/:id/host-firewall
  • UI agent detail → tab Host firewall (Rules / Listeners)

Foreign правила только отображаются — с CP не редактируются.

Desired (Port ACL)

Per-agent таблица agent_port_rules: open|close, tcp|udp|both, port range, src_kind: all|cidr|list.

  • API: CRUD /api/v1/agents/:id/port-rules, import /port-rules/import (from list или policy set sources)
  • Policy apply_version: 3port_rules[] с expanded src_cidrs
  • nft apply: после L3 allow — close drop, затем open accept (comment "evofw-port-<id>")
  • UI: tab Port ACL (DataGrid + Sheet create/edit + Import)
  • ipset / MikroTik: без L4 apply; секции скрыты для non-linux

Мутация Port ACL бампит policy_generation → agent re-apply.

MikroTik (RouterOS 7.21+)

В UI /agentsДобавить агента → platform MikroTik. Скопируйте one-liner:

/tool fetch url="https://<cp>/agent-install/<id>" dst-path=evofw-install.rsc; /import file-name=evofw-install.rsc

Или короткий slug: https://<cp>/<slug>.

Install RSC:

  1. Enroll (с install_link_id → агент Invited → Pending).
  2. Создаёт filter-правила evofw-* в начале цепочек input/forward (place-before) и address-list EVOFW_DENY / EVOFW_ALLOW / dynamic EVOFW_HITS.
  3. Scheduler evofw-sync каждую минуту: GET /v1/agent/policy (JSON) → rebuild deny/allow + report (+ ip_hits из HITS). Не использует /import огромного .rsc.

Лог: /log print where message~"evofw". Ручной sync: /system script run evofw-sync. Traffic ↓/↑ в UI — сумма packets с evofw-deny-drop-* / evofw-allow-* / evofw-default-drop-* (накопительно, пока правила не пересозданы re-install).

Per-IP / Blocked IPs (MikroTik)

Цепочка deny: hit → drop (семантика drop/allow/default как раньше):

  1. evofw-deny-hit-input/forwardadd-src-to-address-listEVOFW_HITS, address-list-timeout=1h (passthrough).
  2. evofw-deny-drop-input/forwarddrop по EVOFW_DENY.

В EVOFW_HITS попадают реальные src /32. Policy rebuild не чистит HITS (только DENY/ALLOW). Sync шлёт top-200 в ip_hits; CP mode presence: last_seen обновляется, пока IP в HITS; packets (Hits) увеличивается только при первом появлении или повторном входе после исчезновения из списка (~>2.5 мин без report), а не на каждый sync.

UI: agent detail → Blocked IPs (колонка Hits).

Default action задаётся на агенте (default_action: accept | drop):

  • accept — пакет вне deny/allow пропускается
  • drop — пакет вне deny/allow отбрасывается (forward)

Цепочка: deny-hit → deny-drop → allow-accept → default. Наборы несут только правила deny/allow, без exclusive mode.

Force sync

sudo rm -f /var/lib/evofw/last_hash
sudo /usr/local/sbin/evofw-firewall.sh