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
This commit is contained in:
1 parent
804fee4ffa
commit
72367682b5
5 files changed
+122
-1
No files matched your search
@@ -0,0 +1,36 @@
|
||||
# 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`.
|
||||
Reference in new issue
Block a user