Files
poc-frr-anycast/docs/2026-09-11-system-hardening-plan.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

3.2 KiB
Raw Blame History

План внедрения: защита от 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 обновлены.