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

4.2 KiB
Raw Permalink Blame History

Summary: защита от auto-update-триггеров и networkd route-flush

Дата: 2026-09-11 План: 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.