37 lines
4.3 KiB
Markdown
37 lines
4.3 KiB
Markdown
# Summary: outbound-фильтр BGP (устранение утечки 10.0.0.0/8)
|
||||
|
|
|
|||
|
|
**Дата:** 2026-09-10
|
|||
|
|
**План:** [2026-09-10-bgp-outbound-filter-plan.md](2026-09-10-bgp-outbound-filter-plan.md)
|
|||
|
|
|
|||
|
|
## Инцидент и причина
|
|||
|
|
|
|||
|
|
В PROD (`site-cloud`) FRR реэкспортировал входящий маршрут `10.0.0.0/8` обратно eBGP-соседям. Причина — структурная: ни у одного соседа (ни в `site-a`, ни в `site-cloud`) не было outbound-фильтра. `no bgp ebgp-requires-policy` отключал защитный механизм FRR (RFC 8212), который иначе не дал бы поднять eBGP-сессию без явной policy; единственный существующий route-map (`RM-PREPEND-OUT`, только на резервном канале site-cloud) не фильтровал — `permit 10` без `match` пропускал всё. Роутеры многодомны в разные внешние AS без изоляции по префиксам → любой маршрут в локальной BGP-таблице реэкспортировался всем eBGP-соседям.
|
|||
|
|
|
|||
|
|
## Что сделано
|
|||
|
|
|
|||
|
|
`ansible/roles/frr_anycast/templates/frr.conf.j2`:
|
|||
|
|
- Добавлен `ip prefix-list PL-ANYCAST-OUT seq 5 permit <anycast_prefix>`.
|
|||
|
|
- Добавлены `route-map RM-OUT` (только фильтр) и `route-map RM-OUT-PREPEND` (фильтр + prepend, рендерится только при наличии соседей с `prepend: true`) — оба матчат `PL-ANYCAST-OUT`, оба с явным `deny 20` в конце.
|
|||
|
|
- Каждому соседу в `bgp_neighbors` теперь назначен outbound route-map: `RM-OUT-PREPEND`, если `prepend: true`, иначе `RM-OUT` — раньше route-map вообще не навешивался на не-prepend соседей (0% фильтрации на основном канале site-cloud и на обоих соседях site-a).
|
|||
|
|
- `no bgp ebgp-requires-policy` **сознательно оставлен** — включение потребовало бы также inbound-policy на каждого соседа (иначе FRR перестанет принимать вообще все входящие маршруты), это отдельная, не запрошенная сейчас задача.
|
|||
|
|
|
|||
|
|
**Golden-файлы площадки A обновлены** (`frr/a{1,2,3}/frr.conf`) — добавлен тот же prefix-list/route-map-блок. Это намеренное изменение: та же уязвимость структурно присутствовала и в Docker-лабе (просто менее заметна, т.к. там оба BGP-соседа логически «свои»), фикс применён единообразно везде, где используется роль.
|
|||
|
|
|
|||
|
|
## Результаты проверки
|
|||
|
|
|
|||
|
|
- `render-check.sh` (площадка A) — 6/6 OK против обновлённых golden-файлов.
|
|||
|
|
- `render-check-cloud.sh` — 80/80 проверок: у всех 4 узлов ровно один outbound route-map на каждого из 4 соседей (по правильному типу), `nft -c -f` подтверждает синтаксическую валидность nftables (без изменений в этой части).
|
|||
|
|
- `--syntax-check` — OK для обоих playbook'ов.
|
|||
|
|
|
|||
|
|
## Не входит в этот фикс (сознательно)
|
|||
|
|
|
|||
|
|
- Inbound-фильтрация (RFC1918/bogon-фильтр на приём) — рекомендована как defense-in-depth, но не реализована.
|
|||
|
|
- Включение `bgp ebgp-requires-policy` обратно — требует отдельной проработки inbound-policy на каждого соседа.
|
|||
|
|
|
|||
|
|
## Изменённые файлы
|
|||
|
|
|
|||
|
|
- `ansible/roles/frr_anycast/templates/frr.conf.j2`.
|
|||
|
|
- `frr/a1/frr.conf`, `frr/a2/frr.conf`, `frr/a3/frr.conf` (golden, Docker-лаба).
|
|||
|
|
- `ansible/tests/render-check-cloud.sh` — обновлены проверки под новые имена route-map/prefix-list.
|
|||
|
|
- `README.md` — пояснение про обязательный outbound-фильтр.
|
|||
|
|
- `docs/2026-09-10-bgp-outbound-filter-plan.md`, `docs/2026-09-10-bgp-outbound-filter-summary.md`.
|