Много слов было сказано про концепцию Source of Truth в мире сетей, много копий сломано в дискуссиях о том, как лучше её реализовать. Кто-то голосует за Git, кто-то жить не может без Netbox, а кто-то по старинке хранит всё в Excel и собственной памяти.

Мы же в Hoff Tech вот уже больше года активно используем Nautobot, и нам есть чем поделиться с теми, кого гложут мысли: «Так, Nautobot установил, где у него кнопка что делать дальше?»

Сперва небольшое отступление

  1. Статья рассчитана на тех, кто собирается заняться сетевой автоматизацией, начинает ей заниматься или делает это уже давно. Если же вы не в курсе про Nautobot, но почитать очень хочется, вот документация — тыц, а вот демонстрация — тыц.

  2. Nautobot — это форк Netbox, и, хотя с момента ветвления прошло достаточно много времени и интерфейсы сильно различаются, всё приведённое в статье можно применить и к Netbox. Сделай в тексте ниже :%s/Nautobot/Netbox/g, суть останется такой же.

  3. Статья обзорная: вы не найдёте в ней ни строчки кода (ну почти). Конкретные реализации приведённых практик будут сильно зависеть от окружения.

Этап 0. Для чего вообще всё это нужно?

Расскажу на примере Hoff Tech. У нас на обслуживании enterprise-сеть, в которой под сотню филиалов и свой ЦОД (не один). Больше тысячи виртуальных машин, десятки тысяч IP-адресов, разбитых по функциональным сегментам и бизнес-юнитам, сотни единиц оборудования (и сетевого, и просто подключённого к сети). А если компания динамично расширяется, в том числе и за счёт поглощения новых структур? Присоединяешь к себе большую слабодокументированную сетевую инфраструктуру и понимаешь: хорошо, что у нас информация о сети хранится в удобном виде, её и достать легко, и актуализировать, и использовать в процессах автоматизации.

Но так было не всегда. Используемые префиксы и VLAN хранились в Excel, более-менее актуальный список маршрутизаторов/коммутаторов можно было найти только в inventory-файле ansible, а свободен или нет IP-адрес — мог проверить исключительно сетевик. Не удивительно, что в определённый момент количество сетевой информации начало влиять на её качество и актуальность. В общем, боль сетевого инженера как она есть.

И тут нам на помощь пришла система документирования сети. IPAM или, если брать шире, самый настоящий Network Source of Truth

Этап 1. Установка

Весь процесс установки подробно описан в официальной документации. Отмечу только то, что базу данных мы вынесли на отдельную виртуальную машину. В дальнейшем планируем поступить так же и с воркерами, которые обеспечивают работу внутренних скриптов автоматизации.

Что касается ресурсов, в этом плане Nautobot совсем не требователен. PostgreSQL с базой данных крутится на виртуалке с двумя ядрами и 4Gb памяти. Всё остальное — фронтенд, бэкенд, воркеры, реверс-прокси, брокер — на виртуалке 4 ядра/4 гига. Этого хватает, чтобы открыть без каких-либо задержек страницу с IP-адресами, коих у нас в базе больше 50 тыс. штук.

Сразу небольшой лайфхак. Для тестирования новых релизов и обучения приёмам работы с Nautobot мы подняли тестовый сервер, на который периодически переносим данные с продуктового. Чтобы пользователи случайно не перепутали сервера, логотип и favicon на тестовом сервере перекрасили из синего цвета в оранжевый. Теперь пользователю сразу понятно, в песочнице ли он и можно ли тренировать навыки удаления критически важных данных.

Для контроля доступа в Nautobot целесообразно использовать учетные данные корпоративного домена. В случае использования ADFS вам потребуется самостоятельно разработать плагин, например, на базе модуля django-adfs. Гораздо проще внедрить решения, аналогичные  Keycloak или Authelia, с ними не будет проблем. Во этом случае интеграция займет не более часа на чтение документации и правку конфигурационных файлов.

Итак, Nautobot установлен и доступен, пришла пора наполнить его жизнью.

Этап 2. Сетевые устройства, префиксы, VLAN

Официальная документация гласит, что Nautobot — это в первую очередь Network Source of Truth. То есть логично, что первыми в нём поселились сетевые устройства: маршрутизаторы и коммутаторы. Конечно, никто и не помышлял вносить данные руками. В это интересное для сетевиков время практически каждый из нас умеет в Python, поэтому у нас быстренько родились несколько джобов, обеспечивающих процесс наполнения данными (jobs — скрипты на Python, запускаемые прямо из интерфейса Nautobot).

AddDevices job. На входе получает список IP-адресов, тип устройства (коммутатор, роутер), платформу (Cisco IOS, Router OS, etc.) и сайт, к которому относятся добавляемые устройства. Джоб по SSH подключается к каждому девайсу из списка, парсит вывод show-команд и вносит структурированные данные в Nautubot. В результате получаем заполненные префиксы, вланы, устройства с интерфейсами и адресами. Этот джоб мы используем при появлении в сети новых устройств.

Небольшой лайфхак номер два. Перед добавлением новых устройств мы максимально заполнили используемые нами модели устройств (device_type). Данные взяли с https://github.com/netbox-community/devicetype-library. Теперь у каждого нового девайса всегда будут правильные набор портов и данные по электропотреблению, которые наследуются при создании от выбранного device type.

CheckDevices job. Проходит по всем сетевым устройствам и сравнивает информацию, хранящуюся в Nautobot (адреса интерфейсов, описания портов, разрешённые VLAN, etc.), с данными, полученными с девайса по SSH. Результаты работы джоба пушатся в git. Джоб регулярно выполняется по шедулеру и извещает сетевых инженеров об отличиях между ожидаемым и реальным состояниями устройства.

SearchDevices job. Проходит по всем сетевым устройствам и обнаруживает соседние устройства, которые видны по CDP/LLDP, но о которых ещё нет данных в Nautobot. Результаты работы джоба пушатся в git. Джоб регулярно выполняется по шедулеру и извещает сетевых инженеров о девайсах, которые по какой-то причине не добавлены в Nautobot.

UpdateDevices job. Проходит по всем сетевым устройствам и актуализирует данные в Nautobot в соответствии с реальным состоянием девайсов. Заодно джоб добавляет соединения между устройствами. Список обновляемых девайсов можно отфильтровать перед выполнением.

GetConfigs job. Проходит по всем сетевым устройствам, получает с них running- и startup-конфигурации и пушит их в git. Джоб регулярно выполняется по шедулеру и позволяет в любой момент увидеть актуальную конфигурацию и всю историю изменений. Этот джоб заменил нам всем известные Rancid и Oxidized

Все джобы используют под капотом модули scrapli и textfsm, под часть оборудования пришлось слегка адаптировать community-драйверы и подготовить собственные шаблоны textfsm. Общение с девайсами осуществляется по SSH, дополнительно рекомендую использовать asyncio, что может заметно уменьшить время работы джобов. Например, CheckDevices обходит все девайсы за пять минут, а это почти 800 единиц. При этом с каждого девайса он получает вывод в среднем шести команд, обрабатывает результаты и сравнивает с данными из Nautobot.

Таким образом, в Nautobot у нас появилось точное отображение сетевого ландшафта. В одном месте теперь можно узнать, в каком сайте какой префикс используется, какие VLAN настроены на портах коммутаторов, как VLAN и префиксы связаны. Неплохим плюсом оказалась и информация о соединениях между коммутаторами.

Этап 3. Перенос данных из исторических систем

Эта стадия внедрения у каждого своя, к сожалению, универсального рецепта пока никто не придумал.

У нас был развёрнут phpIPAM, из которого без особых усилий (2 модуля: phpypam и pynautobot, 1 вечер, 2 кружки кофе) были вытащены данные по статическим IP-адресам и серверным стойкам. Согласитесь, выполнять лишнюю работу никто не хочет, поэтому почему бы и не воспользоваться результатами чужого труда.

При заполнении стоек, кстати, вскрылся один нюанс. Представьте себе стойку:

Скрипт переноса вытащил данные по стойке из phpIPAM, создал необходимые типы устройств, серверные стойки. После этого добавил нужное количество устройств с названиями «панель коммутационная» и «организатор кабельный», разместил их в нужные юниты. Мы порадовались и забыли про эти элементы СКС. Ровно до того момента, когда кому-то из пользователей понадобилось добавить ещё одну коммутационную панель.

Оказалось, имя устройства в Nautobot должно быть уникальным, и при сохранении изменений через веб-интерфейс он это проверил и выдал ошибку. Нумеровать все подобные устройства для уникальности — верх безумия. К счастью, Nautobot позволяет оставлять имя устройства пустым. Выглядит это так:

Но в этой ложке мёда притаилась бочка дёгтя. Названия безымянных устройств в стойке выводятся как результат f"{self.device_type.manufacturer} {self.device_type.model} ({self.pk})", а это слишком длинно. Ну что же, пока ничего не остаётся, как править в коде Nautobot метод display() класса Device (совсем немножечко).  Для исправления ситуации мы после каждого обновления выполняем

sed -i.bak 's/{self.device_type.manufacturer} {self.device_type.model} ({self.pk})/{self.device_type.model}/' /opt/nautobot/lib/python3.8/site-packages/nautobot/dcim/models/devices.py

Небольшой лайфхак номер три. Не все изменения можно внести, используя Bulk edit в веб-интерфейсе. Для простых массовых действий мы часто используем nbshell. Например, для одноразовой очистки name у большого числа девайсов можно выполнить прямо в консоли следующую конструкцию:

for device in Device.objects.filter(device_type=DeviceType.objects.get(slug=’patch-panel’)):
  device.name = ’’
  device.save()

Не надо заморачиваться с подключением к API или импортом модулей. Среди прочего, в nbshell удобно смотреть справку по атрибутам и методам встроенных классов, используя стандартный help().

Этап 4. Концентрируемся на IPAM

Знания о том, какие VLAN разрешены на портах коммутатора или в каком VRF и с каким адресом настроен интерфейс маршрутизатора, очень полезны. Но «что сетевику хорошо, обычному админу, может, и не нужно». Обычного админа (основного пользователя Nautobot) больше интересует, какой IP-адрес у принтера или камеры или из какого диапазона назначить статический адрес новому устройству.

Часть этих вопросов мы закрыли, организовав регулярную синхронизацию данных в Nautobot с DHCP-серверами. DHCP у нас построен на базе Microsoft Windows Server, поэтому самый простой способ — использовать PowerShell:

  1. скрипт на PowerShell экспортирует диапазон выдаваемых адресов и зарезервированные адреса в XML-файл (командлет Export-DhcpServer);

  2. XML конвертируется в JSON;

  3. через API Nautobot вызывается джоб, которому передаётся сформированный JSON;

  4. джоб добавляет в Nautobot новые адреса и удаляет те, которые больше не выдаются.

Небольшой лайфхак номер четыре. Авторизацию в Nautobot организуем по токену, тут мы Америку не открыли. Но прав у пользователя с данным токеном никаких нет, только на запуск джобов. А во всех джобах в методе run() первым делом выполняется стандартная проверка на принадлежность запускающего к нужной группе:

job_script_name = f'job_{self.__module__}'
for group in self.request.user.groups.values_list('name', flat = True):
  if group.name == job_script_name:
    break
else:
  self.log_info(message='Неавторизованный запуск')
  return f'Вам не назначена группа безопасности "{job_script_name}"'

Так мы минимизируем угрозы от утери токена.

Таким образом, в Nautobot попадают все зарезервированные IP-адреса с заполненным полем "DNS name". Статус таких адресов определяется как DHCP reserved. А выдаваемые, но не зарезервированные, адреса имеют в Nautobot статус DHCP. Теперь мы можем определить степень заполненности подсети адресами: какие адреса действительно свободные, а какие могут быть выданы в любой момент.

Но это работает только с динамическими адресами. Что делать со статическими? Они, хоть и называются так, имеют тенденцию постоянно меняться. Тут нам помогает аналог switchmap — плагин porthistory. Я уже писал о нём статью на «Хабр». Этот плагин добавляет возможность хранить информацию о связке IP-MAC и последнем появлении MAC-адреса на том или ином порту коммутатора. Джоб, входящий в состав плагина, выполняет следующие действия:

  1. по SNMP получает с маршрутизаторов таблицу ARP;

  2. по SNMP получает с коммутаторов таблицу MAC-адресов;

  3. если IP-адреса из таблицы ARP нет среди выдаваемых по DHCP, значит, это статический адрес и его надо добавить в Nautobot (естественно, если его ещё там нет) со статусом Static;

  4. по каждому статическому IP-адресу уточнятся DNS-имя и при необходимости актуализируется в Nautobot;

  5. данные о привязке IP к MAC-адресу и порту коммутатора сохраняются в соответствующие модели учёта.

В результате данные по IP-адресам постоянно актуализируются, а админы не только могут посмотреть, какому устройству принадлежит этот адрес, но и к какому порту какого коммутатора это устройство было подключено последний раз.

Этап 5. Не забываем про виртуализацию

В Hoff Tech мы жить не можем без виртуальных машин: их легко создать, настроить, а удалить и того проще. Естественно, у каждой виртуальной машины есть интерфейс с IP-адресом, а то и не один. Хотя мы не ставили целью сделать Nautobot системой учёта виртуализации, но, как IPAM-система, Nautobot должен знать всё о кластерах, хостах, самих виртуальных машинах и их адресации.

Тут нам опять на помощь приходит PowerShell, но теперь уже вместе с модулем VMware PowerCLI для управления ESXi и vSphere. Алгоритм синхронизации незначительно отличается от вышеописанных:

  1. скрипт на PowerShell через API Nautobot получает список адресов ESXi и VSphere;

  2. PowerCLI используется для подключения к API ESXi и VSphere;

  3. экспортируются данные (установленная ОС, интерфейсы, IP-адреса) обо всех рабочих ВМ в JSON;

  4. через API Nautobot вызывается джоб, которому передаётся сформированный JSON;

  5. джоб анализирует изменения и по результатам добавляет новые ВМ, изменяет существующие, назначает выключенным и удалённым соответствующий статус.

Синхронизация выполняется по шедулеру каждый час, при любых изменениях, вносимых админами виртуальной инфраструктуры через консоль управления облаком, эти изменения зеркалируются в Nautobot. Синхронизируется всё необходимое: объём памяти и количество vCPU, интерфейсы с IP- и MAC-адресами, привязка интерфейсов к VLAN, описание серверов и теги.

Существует готовый плагин для Nautobot — Nautobot SSoT vSphere. Он умеет практически всё то же самое, но нам не подошёл по внутренним причинам. В другом окружении использовать его как способ синхронизации данных с VSphere вполне реально.

Ну и последний на сегодня лайфхак. Результаты многочисленных джобов копятся и копятся, страница с историей и логами запусков открывается всё медленнее. А ведь эта история не особо и нужна. Увы, встроенной очистки результатов по шедулеру в Nautobot ещё не завезли. Так что рекомендую написать простенький джоб-терминатор, который по заданному алгоритму будет аннигилировать лишние записи. В нашем насчитывается не больше 50 строчек кода:

from nautobot.extras.jobs import *
from nautobot.extras.models import JobResult

class ClearJobHistory(Job):
  class Meta:
    name = "Delete old results of jobs"
    description = "Удаляет устаревшие записи о выполненных джобах"
    commit_default = False
    hidden = True
  def run(self, data, commit):
    results = JobResult.objects.all()
    old_count = 0
    for result in results:
      # тут логика (зависит от: кто запустил, когда, название джоба, статус и результаты)
      if waste_result:
        old_count += 1
        result.delete()
    self.log_success(message=f'Удалено результатов {old_count} из {results.count()}')

Промежуточные итоги

Согласно официальной документации, Nautobot обеспечивает три ключевых варианта использования:

  1. Flexible Source of Truth for Networking. Это основной кейс, и мы постарались максимально его реализовать. Сейчас подавляющая часть данных о сети доступна в Nautobot, информация актуальна и автоматически поддерживается в таком состоянии. Не забываем и про уточнение Flexible — необходимые нам модели учёта мы добавляем с помощью плагинов.

  2. Extensible Data Platform for Automation. Вебхуки, REST API, GraphQL: всё это используется у нас для передачи данных во внешние системы автоматизации. Такие, например, как системы сканирования уязвимостей. А одной из дальнейших тем для рассказов может стать то, как мы готовим dynamic inventory для Ansible.

  3. Platform for Network Automation Apps. Nautobot обеспечивает лёгкое внедрение Python-скриптов сетевой автоматизации. Для этого у него есть готовые модули интерфейсов, доступные данные о сети, нативная синхронизация с Git, поддержка разных секретов для разных устройств/групп. И пусть наши джобы пока только собирают информацию из внешнего мира — в планах уже изменить вектор сетевой автоматизации и минимизировать действия сетевых инженеров напрямую на устройстве через CLI.

Сейчас могу смело сказать, что Nautobot отлично справляется с реализацией концепции Source of Truth. Но, конечно,  в основном это заслуга не выбранной системы, а людей, которые двигают автоматизацию. Уверен, что при наличии прямых рук и огонька в глазах абсолютно неважно, какую систему документирования сети вы выберете.

Комментарии (0)