ADG Оставить заявку
Блог Автоматизация 5 мин чтения

Nornir + NAPALM: аудит конфигурации 120 коммутаторов за 40 секунд и результаты в Elasticsearch

Автоматизируем аудит сетевого оборудования через Nornir и NAPALM: проверяем соответствие baseline, параллельно опрашиваем коммутаторы, результаты пишем в Elasticsearch.

Контекст момента

NAPALM и Nornir набирают популярность как Python-библиотеки для сетевой автоматизации - сообщество активно переходит от одиночных скриптов к фреймворкам

Задача пришла от клиента с развитой сетевой инфраструктурой: около 120 коммутаторов Cisco и несколько Juniper, и нужно регулярно проверять, что конфигурация не разошлась с baseline. «Разошлась» - это когда кто-то зашёл руками и что-то поменял. NTP-серверы не те, SNMP community не тот, AAA настроена не по шаблону. Инвентаризация вручную делалась раз в квартал и занимала несколько дней. Хотелось чаще и без человека.

Ansible для сетевых задач мы уже щупали, писали про коллекции network.* - см. опыт с Ansible Collections. Но именно для аудита он избыточен: у него нет параллельного выполнения из коробки без нагромождений с async/poll, а главное - NAPALM как абстракция над vendor API там используется через обёртки. Решили попробовать нативный стек: Nornir как фреймворк + NAPALM напрямую.

Почему Nornir, а не очередной набор скриптов

Nornir - это Python-фреймворк для автоматизации сети. Не DSL, не YAML-конфиги с магией, а именно Python: задачи пишутся как функции, инвентарь - обычные YAML-файлы или любой плагин, параллелизм встроен через concurrent.futures. Версия 3.0 вышла весной, API заметно почистили.

Главное, что он даёт - не надо самому управлять пулом потоков и агрегацией результатов. Написал task-функцию, передал в nr.run() - получил структурированный AggregatedResult по каждому хосту. Упавшие хосты не роняют весь прогон.

NAPALM (Network Automation and Programmability Abstraction Layer with Multivendor support) - отдельная библиотека, которая даёт единый API поверх разных вендоров. get_facts(), get_interfaces(), get_ntp_servers() - возвращают одинаковую структуру данных независимо от того, Cisco IOS это или Juniper JunOS. Это и нужно для multi-vendor аудита.

Структура задачи

Инвентарь в Nornir живёт в hosts.yaml:

sw-access-01:
  hostname: 192.168.10.1
  platform: ios
  groups:
    - access_switches

sw-core-01:
  hostname: 10.0.1.1
  platform: junos
  groups:
    - core_switches

Группы наследуют параметры из groups.yaml, там credentials через переменные окружения. Реальных паролей в репозитории нет.

Сам аудит - набор task-функций. Каждая проверяет один аспект конфигурации:

from nornir import InitNornir
from nornir_napalm.plugins.tasks import napalm_get

def check_ntp(task):
    result = task.run(task=napalm_get, getters=["ntp_servers"])
    configured = set(result[0].result["ntp_servers"].keys())
    expected = set(task.host.data.get("expected_ntp", BASELINE["ntp_servers"]))
    missing = expected - configured
    extra = configured - expected
    return Result(
        host=task.host,
        result={"missing": list(missing), "extra": list(extra)},
        failed=bool(missing or extra),
    )

Такие же функции для SNMP community, banner, AAA, VTP mode. Каждая возвращает структурированный результат - что не так и в каком направлении.

Запуск параллельный, по умолчанию Nornir использует 20 потоков:

nr = InitNornir(config_file="nornir.yaml")
results = nr.run(task=full_audit)

На 120 хостах весь прогон занимает порядка 40 секунд. Большая часть времени - сетевые задержки при подключении к оборудованию, а не обработка.

Результаты в Elasticsearch

Хранить результаты только в stdout - потерять историю. Мы пишем каждый прогон в Elasticsearch: один документ на хост на прогон аудита. Индекс network-audit-YYYY.MM, ILM настроен - горячая фаза 30 дней, потом в холодную.

from datetime import datetime
from elasticsearch import Elasticsearch

es = Elasticsearch(ES_HOSTS)

def push_result(host_name, audit_result, run_id):
    doc = {
        "@timestamp": datetime.utcnow().isoformat(),
        "run_id": run_id,
        "host": host_name,
        "compliant": not audit_result.failed,
        "checks": {
            "ntp": audit_result.result.get("ntp"),
            "snmp": audit_result.result.get("snmp"),
            "aaa": audit_result.result.get("aaa"),
        }
    }
    es.index(index=f"network-audit-{datetime.utcnow():%Y.%m}", body=doc)

run_id - UUID на каждый запуск, чтобы можно было сравнивать прогоны между собой в Kibana. Смотрим trend: коммутатор был compliant неделю назад, сейчас нет - значит что-то менялось.

Про возможности Elasticsearch для аналитики недавно писали в посте про ES 7.9 - там ILM и transforms как раз по теме.

Что нашли в первом прогоне

Первый аудит показал картину, которую никто не ожидал в таких масштабах. Из 120 коммутаторов:

  • NTP. На двух десятках хостов прописан дополнительный NTP-сервер, которого нет в baseline. Оказался адрес старого сервера, который давно выведен из эксплуатации. Коммутаторы его опрашивают, тот не отвечает - все живут, но конфигурация не чистая.
  • SNMP community. Несколько коммутаторов имеют readonly-community не из стандартного списка. По одному даже нашли community «public» - классика жанра.
  • Banner. Примерно треть хостов без login banner или с устаревшим текстом. Формально нарушение регламента.
  • AAA. Тут всё относительно чисто - отклонений мало, и те в группе access-коммутаторов одного здания. Видимо, кто-то когда-то накатывал конфиг с ошибкой на партию.

Ничего критичного - но это именно то, что при ручном аудите либо не находят вообще, либо находят не полностью. Автоматика даёт полный охват без устатка и human error.

Где сейчас и что не решено

Запуск пока делается вручную или по cron - раз в сутки ночью. В идеале хотелось бы event-driven: изменение конфигурации на оборудовании -> syslog -> триггер аудита конкретного хоста. Syslog в Elasticsearch у клиента уже идёт, но склейка с аудитом - следующий шаг.

Nornir с NAPALM закрыл основную задачу: полный аудит за разумное время, результаты в хранилище, история видна. На Cisco IOS работает стабильно, с Juniper JunOS тоже без сюрпризов. Для аудита инфраструктуры это сейчас один из рабочих инструментов, который проверяется на реальном парке.

Единственное, что потребовало времени - разобраться с обработкой таймаутов. Если коммутатор в принципе недоступен, Nornir корректно пишет это в результат и идёт дальше, но SSH-таймаут по умолчанию великоват. В production пришлось тюнить через параметры Netmiko (NAPALM использует его под капотом для IOS).

Контакт

Нужна такая же инженерная работа?

Опишите задачу и контекст. Ответим в течение рабочего дня, при необходимости подпишем NDA.