feat(firewall): implement firewall blocklist feature with client management and policy rules
CI / changes (push) Successful in 12s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 25s
CI / web (push) Successful in 46s
CI / go (push) Successful in 1m15s
CI / bird2 (push) Successful in 18s
CI / release (push) Successful in 3m59s
CI / changes (push) Successful in 12s
CI / commitlint (push) Has been skipped
CI / openapi (push) Successful in 25s
CI / web (push) Successful in 46s
CI / go (push) Successful in 1m15s
CI / bird2 (push) Successful in 18s
CI / release (push) Successful in 3m59s
Introduced a comprehensive firewall blocklist feature, allowing for the management of firewall clients and their associated rules. This includes endpoints for enrolling clients, listing clients and rules, and reporting apply statuses. Enhanced the API to support firewall operations, including the ability to handle block/accept policies. Updated the documentation to reflect these changes and added necessary components in the web UI for better user interaction. Additionally, modified the agent server to support firewall failover and integrated firewall functionality into the existing architecture.
This commit is contained in:
@@ -43,6 +43,7 @@ opkey|01ARZ3NDEKTSV4RRFFQ69G5FAV|operator,nodekey|01ARZ3NDEKTSV4RRFFQ69G5FAV|nod
|
||||
| `editor` | 2 | Чтение + создание/изменение CRUD (модули, записи, peers и т.д.), без опасных операций уровня оператора. |
|
||||
| `operator` | 3 | Полный операторский доступ: apply, rollback, настройки, отмена задач и т.п. (как задано в handlers). |
|
||||
| `node` | отдельная | Только API для реплики: latest revision, скачивание бандла, enroll. Роль **`node` запрещена** для обычного CRUD — ответ `403 Forbidden`. |
|
||||
| `firewall` | отдельная | Только data-plane firewall-клиента: `GET /v1/firewall/blocklist`, `POST /v1/firewall/apply-report`, `POST /v1/firewall/heartbeat`. Токен в таблице `firewall_client`, не в `api_key`. См. [firewall.md](firewall.md). |
|
||||
|
||||
Обратное ограничение: для эндпоинтов ноды требуется именно роль **`node`**; остальные роли получают отказ.
|
||||
|
||||
|
||||
@@ -41,7 +41,8 @@
|
||||
| `broker` | Опциональный `EVOBGP_BROKER_URL` для будущей шины; сейчас задачи только in-process (`jobs.Registry`), пакет лишь логирует факт настройки URL. |
|
||||
| `pipeline` | Ingest+render в одном шаге для `module_refresh`: выборка префиксов (CDN/AS/IP/пустые DOMAINS), `CreateRenderRevision`, превью BIRD через `birdfmt`. |
|
||||
| `nodedispatch` | Panel→Node HTTP wake-up (`POST /v1/agent/sync`) после `deploy_apply`. |
|
||||
| `agentserver` | HTTP API на реплике (`serve`): sync + health для Traefik. |
|
||||
| `agentserver` | HTTP API на реплике (`serve`): sync + health для Traefik; опционально firewall failover (`/v1/firewall/*`). |
|
||||
| `firewall` | Вычисление policy block/accept → плоский CIDR blocklist. |
|
||||
|
||||
## Удалённые спикеры
|
||||
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
# Firewall blocklist
|
||||
|
||||
Подсистема синхронизации blocklist на произвольные Linux-серверы через bash-скрипт и HTTP API.
|
||||
|
||||
## Авторизация
|
||||
|
||||
1. **Enroll** — `POST /v1/firewall/enroll` с заголовком `X-EvoBGP-Seed` (значение `EVOBGP_BUNDLE_SEED_HEX` на CP). Клиент генерирует токен `evobgp_fw_*` локально.
|
||||
2. **Approve** — operator в Web UI (`/firewall` → Запросы).
|
||||
3. **Sync** — `GET /v1/firewall/blocklist` с `Authorization: Bearer <client_token>`.
|
||||
|
||||
## Политика block/accept
|
||||
|
||||
- **`block`** — добавить префиксы community в kernel blocklist.
|
||||
- **`accept`** — не блокировать.
|
||||
- **Default** — accept (пустой blocklist без явных `block`).
|
||||
|
||||
Правила задаются на уровне tenant (по умолчанию) и per-server (overrides клиента). Client scope проверяется раньше tenant-default.
|
||||
|
||||
## Установка на сервер
|
||||
|
||||
```bash
|
||||
curl -fsSL https://<api>/v1/firewall/install.sh | \
|
||||
EVOBGP_CP_URL=https://<api> \
|
||||
EVOBGP_SEED=<bundle_seed_hex> \
|
||||
EVOBGP_CLIENT_NAME="web-01" \
|
||||
bash
|
||||
```
|
||||
|
||||
Файлы: `/etc/evobgp/firewall.conf`, `/usr/local/sbin/evobgp-firewall.sh`, systemd timer `evobgp-firewall.timer`.
|
||||
|
||||
## Failover через speaker
|
||||
|
||||
При `EVOBGP_FIREWALL_FAILOVER_ENABLED=1` на speaker-agent CP реплицирует состояние через `POST /v1/agent/firewall-replicate`. Клиенты используют тот же DNS-домен.
|
||||
|
||||
См. также [access.md](access.md), [remote-speakers.md](remote-speakers.md).
|
||||
@@ -58,6 +58,8 @@ tags:
|
||||
Файловые runtime-логи Docker-сервисов (каталог EVOBGP_RUNTIME_LOGS_DIR).
|
||||
Доступно только в процессе evobgp-all с примонтированным volume; иначе 503.
|
||||
Просмотр — viewer+; очистка — operator+ (синхронно, с audit).
|
||||
- name: Firewall
|
||||
description: Linux firewall blocklist clients, policy rules (block/accept), and data-plane sync.
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -1579,6 +1581,68 @@ components:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
FirewallClient:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
name:
|
||||
type: string
|
||||
hostname:
|
||||
type: string
|
||||
token_prefix:
|
||||
type: string
|
||||
status:
|
||||
type: string
|
||||
enum: [pending, approved, revoked]
|
||||
last_seen_at:
|
||||
type: string
|
||||
format: date-time
|
||||
last_apply_at:
|
||||
type: string
|
||||
format: date-time
|
||||
last_apply_status:
|
||||
type: string
|
||||
last_apply_prefix_count:
|
||||
type: integer
|
||||
client_version:
|
||||
type: string
|
||||
|
||||
FirewallRule:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
client_id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
nullable: true
|
||||
priority:
|
||||
type: integer
|
||||
action:
|
||||
type: string
|
||||
enum: [block, accept]
|
||||
community_id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
nullable: true
|
||||
comment:
|
||||
type: string
|
||||
|
||||
FirewallBlocklist:
|
||||
type: object
|
||||
properties:
|
||||
client_id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
revision_id:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
prefixes:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
total:
|
||||
type: integer
|
||||
hash:
|
||||
type: string
|
||||
|
||||
paths:
|
||||
/v1/health:
|
||||
get:
|
||||
@@ -4299,3 +4363,134 @@ paths:
|
||||
$ref: "#/components/responses/Forbidden"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/enroll:
|
||||
post:
|
||||
tags: [Firewall]
|
||||
summary: Enroll firewall client (public, X-EvoBGP-Seed)
|
||||
security: []
|
||||
operationId: firewallEnroll
|
||||
parameters:
|
||||
- name: X-EvoBGP-Seed
|
||||
in: header
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [name, client_token]
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
hostname:
|
||||
type: string
|
||||
client_token:
|
||||
type: string
|
||||
client_version:
|
||||
type: string
|
||||
responses:
|
||||
"201":
|
||||
description: Client created (pending).
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/clients:
|
||||
get:
|
||||
tags: [Firewall]
|
||||
summary: List firewall clients
|
||||
operationId: listFirewallClients
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
items:
|
||||
type: array
|
||||
items:
|
||||
$ref: "#/components/schemas/FirewallClient"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/clients/{id}/approve:
|
||||
post:
|
||||
tags: [Firewall]
|
||||
summary: Approve pending client
|
||||
operationId: approveFirewallClient
|
||||
parameters:
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
responses:
|
||||
"200":
|
||||
description: Approved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/FirewallClient"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/rules:
|
||||
get:
|
||||
tags: [Firewall]
|
||||
summary: List firewall rules
|
||||
operationId: listFirewallRules
|
||||
parameters:
|
||||
- name: scope
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum: [tenant, client]
|
||||
- name: client_id
|
||||
in: query
|
||||
schema:
|
||||
$ref: "#/components/schemas/ResourceId"
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
post:
|
||||
tags: [Firewall]
|
||||
summary: Create firewall rule
|
||||
operationId: createFirewallRule
|
||||
responses:
|
||||
"201":
|
||||
description: Created
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/blocklist:
|
||||
get:
|
||||
tags: [Firewall]
|
||||
summary: Get evaluated blocklist (firewall client token)
|
||||
operationId: getFirewallBlocklist
|
||||
responses:
|
||||
"200":
|
||||
description: Blocklist
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/FirewallBlocklist"
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
/v1/firewall/apply-report:
|
||||
post:
|
||||
tags: [Firewall]
|
||||
summary: Report last apply status
|
||||
operationId: firewallApplyReport
|
||||
responses:
|
||||
"200":
|
||||
description: OK
|
||||
default:
|
||||
$ref: "#/components/responses/DefaultProblem"
|
||||
|
||||
@@ -114,5 +114,7 @@ Tenant `/v1/settings` (`bird_bgp_source_ipv4`) — fallback для master / ес
|
||||
| `EVOBGP_NODE_DISPATCH_ENABLED=1` | CP |
|
||||
| `EVOBGP_AGENT_SECRET` | реплика |
|
||||
| `EVOBGP_NODE_TOKEN` | реплика |
|
||||
| `EVOBGP_FIREWALL_FAILOVER_ENABLED=1` | реплика (опционально: отдавать `/v1/firewall/blocklist` при недоступности CP) |
|
||||
| `EVOBGP_FIREWALL_STATE_FILE` | реплика (default `/var/lib/evobgp-agent/firewall-state.json`) |
|
||||
| `EVOBGP_BUNDLE_PUBKEY_BASE64` | реплика |
|
||||
| `PANEL_IP_WHITELIST` | Traefik на реплике |
|
||||
|
||||
Reference in New Issue
Block a user