Эндпоинт firewall-export
ℹ️ Эндпоинт доступен начиная с версии MikoPBX 2026.1.76.
Техническая страница для разработчиков своих bouncer'ов и для интеграций с edge-провайдерами (Cloudflare, AWS WAF, кастомные nftables-генераторы).
Базовая информация
Базовый URL:
https://<MIKOPBX-HOST>/pbxcore/api/v3/firewall-bouncer/Эндпоинты:
GET /v1/decisions/stream— полный snapshot решений в формате CrowdSec LAPI. Стоковыйcs-firewall-bouncerдописывает этот путь кapi_urlсам.GET /v1/whitelist— allow-list оператора как плоский JSON-массив (расширение MikoPBX, см. Whitelist).
Аутентификация: bouncer-токен принимается в двух заголовках:
X-Api-Key: <token>— соглашение CrowdSec, шлёт стоковыйcs-firewall-bouncer.Authorization: Bearer <token>— удобен дляcurl, Postman и кастомных HTTP-клиентов. Оба варианта валидируют одну и ту же строку вApiKeys, path-restriction и ACL действуют одинаково.
Permission scope:
firewall_bouncer. Создавайте токен сallowed_paths: {"/api/v3/firewall-bouncer": "read"}— пресет в UI ApiKeys уже делает это правильно.Совместимость: тело ответа
decisions/streamповторяет shape CrowdSec LAPI один-в-один —{new, deleted}на верхнем уровне, без обёртки. Существующие CrowdSec bouncer'ы (cs-firewall-bouncer,cs-cloudflare-bouncer,cs-nginx-bouncerи десятки community-плагинов) работают «из коробки».
Decisions stream
GET /pbxcore/api/v3/firewall-bouncer/v1/decisions/stream
{
"new": [
{
"id": 12345,
"origin": "mikopbx-fail2ban",
"type": "ban",
"scope": "Ip",
"value": "203.0.113.7",
"duration": "3600s",
"scenario": "mikopbx/sip"
},
{
"id": 678901,
"origin": "mikopbx-networkfilters",
"type": "ban",
"scope": "Range",
"value": "198.51.100.0/24",
"duration": "8760h",
"scenario": "mikopbx/manual"
}
],
"deleted": []
}Поля решения
id
int
Стабильный положительный 32-битный ID — crc32(value + scenario) & 0x7fffffff.
origin
string
mikopbx-fail2ban (Redis) или mikopbx-networkfilters (БД оператора).
type
string
Всегда "ban".
scope
string
"Ip" для одиночного адреса или "Range" для CIDR.
value
string
IP-адрес или CIDR.
duration
string
Оставшееся время до истечения, например "3600s" или "8760h".
scenario
string
mikopbx/sip, mikopbx/http, mikopbx/ami, mikopbx/iax, mikopbx/manual.
Сопоставление с CrowdSec
mikopbx-fail2ban
aggregated origin
Redis-ключи firewall:<cat>:<ip>
mikopbx-networkfilters
aggregated origin
Таблица m_NetworkFilters.deny
mikopbx/sip
scenario tag
Категория sip в Redis
mikopbx/http
scenario tag
Категория http в Redis
mikopbx/ami
scenario tag
Категория ami в Redis
mikopbx/iax
scenario tag
Категория iax в Redis
mikopbx/manual
scenario tag
Записи оператора в UI «Файрвол»
Семантика опроса
На каждый poll возвращается полный snapshot текущих банов в массиве
new. Bouncer'ы обновляют таймауты своих ipset / nftables- записей при каждом появлении IP, поэтому активный бан живёт ровно столько, сколько указал источник в полеduration.Массив
deletedсодержит per-bouncer дифф с прошлого poll'а. MikoPBX хранит последний выданный snapshot per-ApiKey id (Redis-ключ_PH_REDIS_CLIENT:fwbouncer:cursor:<token-id>, TTL 1 ч, обновляется на каждом poll'е — курсор истекает только после часа молчания bouncer'а). Решения, исчезнувшие между двумя опросами — снятие бана оператором, истечение TTL, удаление записи NetworkFilters — попадают вdeletedполными объектами на следующем poll'е, и bouncer удаляет запись из своего локального стора немедленно, не дожидаясь естественного истечения таймаута ipset.update_frequency: 5–10s— рекомендованная частота опроса.
Поведение query-параметров от bouncer'а:
startup
startup=true игнорирует сохранённый cursor только для текущего poll'а — полный snapshot в new, пустой deleted — после чего записывает свежий snapshot в cursor. СЛЕДУЮЩИЙ poll уже диффится с этим свежим snapshot'ом штатно. Bouncer'ы посылают это на первом poll'е после рестарта. Прочие значения (включая false) трактуются как обычные опросы.
scopes
Принимается, но игнорируется. MikoPBX отдаёт только scope=Ip и scope=Range; server-side фильтрация не выполняется.
origins
Принимается, но игнорируется. Оба origin (mikopbx-fail2ban, mikopbx-networkfilters) всегда присутствуют в ответе. Bouncer'ы, желающие фильтровать, делают это на своей стороне.
Изоляция курсоров позволяет нескольким независимым bouncer'ам (например, один работает локально с nftables, второй гонит правила в Cloudflare) каждому вести свой дифф — выдавайте один ApiKey на bouncer. Совместное использование одного ApiKey несколькими bouncer'ами заставляет их делить один курсор: poll'ы разных bouncer'ов будут чередовать записи snapshot'а, давая недетерминированные тайминги deleted[] и пропущенные eviction-события для короткоживущих банов.
Примеры
curl
Минимальный кастомный bouncer (Python)
Обратите внимание: JSON-тело — это LAPI shape на верхнем уровне, без обёртки {result, data, ...} вокруг new/deleted.
Whitelist
GET /pbxcore/api/v3/firewall-bouncer/v1/whitelist возвращает allow-list оператора как плоский JSON-массив:
Источники, объединённые в ответ:
NetworkFiltersс признакомnewer_block_ip = '1',Fail2BanRules.whitelist.
Эндпоинт — специфика MikoPBX. Стоковый cs-firewall-bouncer его не опрашивает: в CrowdSec LAPI нет типа решения «allow», bouncer ведёт собственный whitelists.yaml. Предоставлен для MikoPBX-aware интеграций, которым нужна согласованность whitelist на стороне сервера.
MikoPBX дополнительно проверяет whitelist на write-side (в DockerNetworkFilterService::isIpWhitelisted), но это защита в глубину — ваш bouncer всё равно должен вычитать whitelist из new перед применением блокировок.
Безопасность
Эндпоинт whitelist отдаёт операторские allow-list сети. Никогда не выставляйте его без аутентификации.
Bouncer-токен оптимально привязывать к NetworkFilter, разрешающему только IP хоста bouncer'а. При несовпадении источника API вернёт 403.
После compromise — отзовите токен через UI ApiKeys; bouncer перестанет получать новые решения и через 30 секунд начнут истекать его локальные блокировки (если такой режим включён).
Last updated
Was this helpful?

