Files
poc-frr-anycast/docs/2026-09-11-system-hardening-summary.md
T
ayurishchevandClaude Sonnet 5 72367682b5 Harden frr_anycast against unattended-upgrade-triggered route flush
Prod-инцидент: apt-daily-upgrade обновил libc6 -> postinst вызвал
рестарт зависимых юнитов -> перезапустился systemd-networkd -> он
вычистил из ядра BGP-маршруты zebra (KeepConfiguration не был задан,
networkd по умолчанию удаляет "чужие" маршруты при старте). Zebra не
знала о вычистке, трафик встал до ручного restart frr. Повторилось
10 сентября с обновлением systemd, но было замаскировано плейбуком.

Роль frr_anycast теперь защищает от этого класса сбоя безусловно:
- отключены apt-daily/apt-daily-upgrade (20auto-upgrades + маскирование
  таймеров и сервисов) - обновления пакетов только вручную;
- systemd-networkd получает drop-in KeepConfiguration=yes - устраняет
  сам механизм вычистки маршрутов при любом будущем рестарте networkd,
  не только от конкретного пакета-триггера;
- новый handler Restart systemd-networkd между Apply netplan и Restart
  frr (networkd должен переустановить владение интерфейсами до того,
  как zebra переустановит маршруты).

Шаблоны FRR/nftables не затронуты: render-check.sh 6/6,
render-check-cloud.sh 84/84, без изменений.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Bc3HkMiDwooSyLBLoMKNyF
2026-09-11 13:09:17 +03:00

37 lines
4.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Summary: защита от auto-update-триггеров и networkd route-flush
**Дата:** 2026-09-11
**План:** [2026-09-11-system-hardening-plan.md](2026-09-11-system-hardening-plan.md)
## Разбор инцидента
`apt-daily-upgrade.service` обновил `libc6` → postinst-скрипт вызвал `daemon-reexec`/рестарт зависимых юнитов → перезапустился `systemd-networkd`. Networkd по умолчанию (`KeepConfiguration` не задан) при старте вычищает на управляемых интерфейсах маршруты, которые не совпадают с его собственным конфигом — «чужие», включая BGP-маршруты, установленные zebra через netlink. Zebra о вычистке не узнавала (её внутренняя RIB не менялась) — маршруты в кернел-FIB отсутствовали до ручного `systemctl restart frr` в 08:57. Повторный триггер 10 сентября (обновление `systemd`) был замаскирован тем, что следом отработал плейбук и перезапустил FRR сам. Ключевой вывод (подтверждён): триггером может стать обновление любого пакета, тянущего рестарт networkd — защита нужна структурная, не «дождаться конкретного пакета».
## Что сделано
В `roles/frr_anycast/tasks/main.yml` добавлены безусловные задачи (применяются на всех узлах обеих сред):
1. Отключение периодического apt (`/etc/apt/apt.conf.d/20auto-upgrades` → `Update-Package-Lists "0"`, `Unattended-Upgrade "0"`) + маскирование `apt-daily.timer`/`apt-daily-upgrade.timer`/их `.service` — двойная защита от повторного включения.
2. `systemd-networkd` drop-in `/etc/systemd/networkd.conf.d/99-keep-configuration.conf` с `KeepConfiguration=yes` — устраняет сам механизм вычистки маршрутов при рестарте networkd, независимо от причины рестарта.
3. Новый handler `Restart systemd-networkd` в `handlers/main.yml`, размещён между `Apply netplan` и `Restart frr` (порядок важен — networkd должен перечитать `KeepConfiguration` и переустановить владение интерфейсами до того, как zebra переустанавливает маршруты).
Обновления пакетов остаются возможны, но только явным ручным `apt update && apt upgrade` — автоматический/unattended путь полностью исключён.
## Результаты проверки
- `--syntax-check` — OK для `site-a.yml` и `site-cloud.yml`.
- `render-check.sh` (площадка A) — 6/6, без изменений.
- `render-check-cloud.sh` (site-cloud) — 84/84, без изменений.
Новые задачи не трогают шаблоны FRR/nftables, поэтому регресс-тесты рендера не затронуты — это дополнение к системной защите ОС, а не к BGP-конфигурации.
## Известное ограничение
Реальный apply на живых ВМ не выполнялся (ВМ не подняты, как и в предыдущих изменениях этой сессии) — эффект `KeepConfiguration=yes` и маскирования таймеров проверен только синтаксически/по документации модулей, не на реальном перезапуске networkd.
## Изменённые файлы
- `ansible/roles/frr_anycast/tasks/main.yml`, `ansible/roles/frr_anycast/handlers/main.yml`.
- `README.md` — новый раздел «Защита от auto-update-триггеров и networkd route-flush».
- `docs/2026-09-11-system-hardening-plan.md`, `docs/2026-09-11-system-hardening-summary.md`.