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
26 lines
3.2 KiB
Markdown
26 lines
3.2 KiB
Markdown
# План внедрения: защита от auto-update-триггеров и networkd route-flush
|
||
|
||
**Дата:** 2026-09-11
|
||
|
||
## Инцидент
|
||
|
||
`apt-daily-upgrade.service` обновил `libc6` → postinst вызвал `daemon-reexec`/рестарт зависимых юнитов → перезапустился `systemd-networkd`. Networkd по умолчанию (`KeepConfiguration` не задан) при старте вычищает на управляемых интерфейсах маршруты, которые не совпадают с его конфигом — «чужие» для него BGP-маршруты zebra. Zebra не знала о вычистке (её RIB не менялся), кернел-FIB был пуст до ручного `systemctl restart frr`. Аналогичный триггер сработал повторно 10 сентября (обновление `systemd`), но был замаскирован плейбуком, перезапускавшим FRR следом.
|
||
|
||
Вывод пользователя: триггером может стать обновление **любого** пакета, тянущего рестарт networkd — защита должна быть не от конкретного пакета, а структурная.
|
||
|
||
## Решение (роль `frr_anycast`, применяется безусловно на всех узлах)
|
||
|
||
1. **Отключить автоматические/unattended обновления**:
|
||
- `/etc/apt/apt.conf.d/20auto-upgrades` → `Update-Package-Lists "0"`, `Unattended-Upgrade "0"`.
|
||
- Замаскировать `apt-daily.timer`, `apt-daily-upgrade.timer` и их `.service` — двойная защита, даже если конфиг-файл будет вручную изменён.
|
||
- Обновления пакетов остаются возможны, но только явным `apt update && apt upgrade`, инициированным администратором.
|
||
2. **`systemd-networkd` не должен вычищать маршруты, поставленные не им** — drop-in `/etc/systemd/networkd.conf.d/99-keep-configuration.conf` с `KeepConfiguration=yes`. Защищает от той же категории сбоя при **любом** будущем рестарте networkd, независимо от причины.
|
||
3. Handler-цепочка при изменении networkd-конфига: `Restart systemd-networkd` → `Restart frr` (та же логика, что и ручной remediation 08:57 — зебра переустанавливает маршруты после того, как networkd перечитал конфиг).
|
||
|
||
## Definition of done
|
||
|
||
- Задачи добавлены в `roles/frr_anycast/tasks/main.yml`, handler — в `handlers/main.yml` (порядок: после `Apply netplan`, перед `Restart frr`).
|
||
- `frr.conf.j2`/`daemons.j2`/`nftables.conf.j2` не затронуты — `render-check.sh`/`render-check-cloud.sh` проходят без изменений (регресс-проверка).
|
||
- `--syntax-check` чист для обоих playbook'ов.
|
||
- README и summary обновлены.
|