[Из песочницы] Установка и использование виртуальной сетевой лаборатории EVE-NG совместно с Ansible. Первый опыт

image


В данной статье приведен опыт инженера-сетевика по развертыванию виртуальной лаборатории EVE-NG в домашних условиях, для целей подготовки к экспертным экзаменам Cisco.


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


Все решения, приведенные в статье, не претендуют на оптимальность, но абсолютно точно работают.


Установка EVE-NG


Подготовка хоста


В качестве хостовой я использую следующую систему: Intel Xeon X3240, 32Gb RAM под управлением Gentoo. Настройка KVM на Gentoo дело достаточно тривиальное и, по правде сказать, я не помню с какими подводными камнями мне пришлось столкнуться при её развертывании. Дело было давно.


Основное, что катастрофически сказывается на производительности лабораторного стенда типа EVE-NG, — это параметр ядра, который запускает возможность использования nested virtualization (вложенную виртуальзацию).


Для процессоров Intel:


kvm-intel.nested=1

Подробнее можно прочесть по ссылке.


Подключение образов сетевых устройств


Образы сетевых устройств для подключения находятся в свободном доступе на самом cisco.com, для скачивания достаточно иметь учётную запись начального уровня. Нам понадобятся XRv и CSR.
Скачиваем по указанными ссылкам и следуем рекомендациям в how-to.


Проблема, с которой я столкнулся при добавлении образов — как называть директории, куда нужно складывать файлы hda.qcow2. Решение, как всегда, — реверс-инжиниринг. Список заголовков, обрабатываемых EVE-NG зашит в файле:


/opt/unetlab/html/includes/init.php

Приведу его здесь:


$node_templates = Array(
        'a10'           =>  'A10 vThunder',
        'clearpass'     =>  'Aruba ClearPass',
        'timos'         =>  'Alcatel 7750 SR',
        'veos'          =>  'Arista vEOS',
        'barracuda'     =>  'Barraccuda NGIPS',
        'brocadevadx'   =>  'Brocade vADX',
        'cpsg'          =>  'CheckPoint Security Gateway VE',
        'docker'        =>  'Docker.io',
        'acs'           =>  'Cisco ACS',
        'asa'           =>  'Cisco ASA',
        'asav'          =>  'Cisco ASAv',
        'cda'           =>  'Cisco Context Directory Agent',
        'csr1000v'      =>  'Cisco CSR 1000V',
        'csr1000vng'    =>  'Cisco CSR 1000V (Denali and Everest)',
        'cips'          =>  'Cisco IPS',
        'cucm'          =>  'Cisco CUCM',
        'ise'           =>  'Cisco ISE',
        'c1710'         =>  'Cisco IOS 1710 (Dynamips)',
        'c3725'         =>  'Cisco IOS 3725 (Dynamips)',
        'c7200'         =>  'Cisco IOS 7206VXR (Dynamips)',
        'iol'           =>  'Cisco IOL',
        'titanium'      =>  'Cisco NX-OSv (Titanium)',
        'nxosv9k'       =>  'Cisco NX-OSv 9K',
        'firepower'     =>  'Cisco FirePower',
        'firepower6'    =>  'Cisco FirePower 6',
        'ucspe'         =>  'Cisco UCS-PE',
        'vios'          =>  'Cisco vIOS',
        'viosl2'        =>  'Cisco vIOS L2',
        'vnam'          =>  'Cisco vNAM',
        'vwlc'          =>  'Cisco vWLC',
        'vwaas'         =>  'Cisco vWAAS',
        'phoebe'        =>  'Cisco Email Security Appliance (ESA)',
        'coeus'         =>  'Cisco Web Security Appliance (WSA)',
        'xrv'           =>  'Cisco XRv',
        'xrv9k'         =>  'Cisco XRv 9000',
        'nsvpx'         =>  'Citrix Netscaler',
        'sonicwall'     =>  'Dell SonicWall',
        'cumulus'       =>  'Cumulus VX',
        'extremexos'    =>  'ExtremeXOS',
        'bigip'         =>  'F5 BIG-IP LTM VE',
        'fortinet'      =>  'Fortinet FortiGate',
        //'radware'     =>  'Radware Alteon',
        'hpvsr'         =>  'HP VSR1000',
        'olive'         =>  'Juniper Olive',
        'vmx'           =>  'Juniper vMX',
        'vmxvcp'        =>  'Juniper vMX VCP',
        'vmxvfp'        =>  'Juniper vMX VFP',
                'vsrx'          =>  'Juniper vSRX',
        'vsrxng'        =>  'Juniper vSRX NextGen',
        'vqfxre'        =>  'Juniper vQFX RE',
        'vqfxpfe'       =>  'Juniper vQFX PFE',
        'linux'         =>  'Linux',
        'mikrotik'      =>  'MikroTik RouterOS',
        'ostinato'      =>  'Ostinato',
        'paloalto'      =>  'Palo Alto VM-100 Firewall',
        'pfsense'       =>  'pfSense Firewall',
        'riverbed'      =>  'Riverbed',
        'sterra'        =>  'S-Terra',
        'vyos'          =>  'VyOS',
        'win'           =>  'Windows (Legacy template)',
        'winstation'            =>  'Windows Workstation',
        'winserver'         =>  'Windows Server',
        'vpcs'          =>  'Virtual PC (VPCS)'
    );

То есть, если нам необходимо добавить образ с любым Linux, как мы будем делать ниже, то достаточно создать директорию /opt/unetlab/addons/qemu/linux-что-то-там/ и положить в неё файл образа hda.qcow2.


Настройка окружения


Под окружением будем понимать всё, что делает нашу жизнь удобнее.


Доступ к консоли маршрутизаторов


Несмотря на то, что в EVE-NG разработчики внедрили возможность доступа к консолям сетевых устройств по web с использованием HTML5, доступ со сторонних клиентов удобнее и привычнее. Основное удобство, которое предоставляется putty в моём случае, — это возможность использования буфера обмена. Не работает copy/paste в web-консоли.


Итак, процесс выглядит следующим образом:


Установка putty на машине, откуда будет осуществляться доступ. Я работаю на ПК c ubuntu, поэтому:


sudo apt-get install putty

Но этого мало, нужно еще рассказать браузеру, в моём случае это chrome, как реагировать на ссылки вида telnet://. Для этого необходимо создать файл ~/.local/share/applications/telnet.desktop следующего содержания:


[Desktop Entry]
Version=1.0
Name=Telnet
GenericName=Telnet
Comment=Telnet Client
Exec=/usr/bin/putty %U
TryExec=/usr/bin/putty
Terminal=false
Type=Application
Categories=TerminalEmulator;Network;Telnet;Internet;BBS;
MimeType=x-scheme/telnet
X-KDE-Protocols=telnet
Keywords=Terminal;Emulator;Network;Internet;BBS;Telnet;Client;

После этого консоли будут отлично открываться в putty. Задачу перехода на gnome-terminal с вкладками или его аналог оставлю на потом.


Запуск сниффера трафика


Wireshark — насущная необходимость при изучении сетевых технологий. Очень много написано про его использование. Не стану повторяться. Опишу процесс его настройки.


Установка на клиенте:


sudo apt-get install wireshark

Но снова браузер не понимает как обработать ссылку capture://


Объяснять ему это придется в три этапа:


Этап 1:
Как и в случае с консолями, файл ~/.local/share/applications/wireshark.desktop вида:


[Desktop Entry]
Name=Wireshark
Exec=capture_chrom.sh %u
MimeType=x-scheme-handler/capture;
Type=Application

Этап 2:
Обработчик в виде скрипта на bash на клиентской машине в любой директории из списка PATH:


#!/bin/bash
ip=`echo $@ | sed 's/.*\/\/\(.*\)\/\(.*\)/\1/g'`
interface=`echo $@ | sed 's/.*\/\/\(.*\)\/\(.*\)/\2/g'`
ssh root@$ip tcpdump -i $interface -U -w - | wireshark -k -i -

Этап 3:
Ключевой ssh-доступ между клиентской машиной и EVE-NG.


На клиентской машине (вместо ip_eve поставить адрес EVE-NG):


ssh-keygen -t rsa
ssh root@_ip_eve_ mkdir -p .ssh
cat ~/.ssh/id_eve_ng.pub | ssh root@ip_eve 'cat >> .ssh/authorized_keys2'

После этого будет работать захват трафика в wireshark на стороне клиента. Что нам и требовалось.


На этом непритязательный пользователь может остановиться, но нет предела совершенству и мы продолжаем…


Настройка инстанса сервера ansible


Необходимость ansible для виртуальных лабораторных топологий в начале пути была для меня неочевидна. Но со временем, на втором десятке лабораторных часов, приходит мысль —, а не автоматизировать ли загрузку стартовых топологий в устройства, не перегружая их, тем самым экономя время?


Итак, с чего начать? С ограничений ansible! Да, они действительно есть. Для меня, как достаточно далекого от программирования, слишком жестоким оказалось предложение на одном из форумов — дописать обработчик телнета самому. Телнет нужен был для решения в лоб — настроить ansible на виртуальной машине EVE-NG и телнетится на консольные порты виртуальных маршрутизаторов. Но не тут-то было — работает только ssh.


Но мы старые инженеры и не привыкли отступать! Если гора не идёт к Магомету, то двинем мы к ней — настроим отдельный инстанс с ububtu в самой топологии, благо для этого есть возможность.
Как разворачивать в KVM образ скаченный с ubuntu.com я приводить не буду. Делал я это на отдельной машине, настраивал и заливал в EVE-NG. После установки нам понадобятся пакеты с telnet-сервером и настройка статического IP-адреса.


Настройка telnet-сервера


У меня не вышло заставить EVE-NG показать мне консоль сервера стандартным способом через клик по девайсу. Чтобы не закапываться глубоко, я пошел в обход — настроил telnet-сервер. SSH v2, конечно, тоже имеется и работает с CSR, но уж очень медленно для интерактивной работы, да и бесполезно — у нас лабораторный стенд, а не продакшн.


Потом необходимость в сервере отпала, но запись в шпаргалке осталась, поэтому приведу и её.


Итак, приступим:


 sudo apt-get install xinetd telnetd

После автоматического запуска xinetd, конечно, ничего не произошло, как нам обещали в интернете.


Нужно добавить в /etc/xinetd.d файл telnet следующего содержания:


service telnet
  {
        disable         = no
        flags           = REUSE
        socket_type     = stream
        wait            = no
        user            = root
        server          = /usr/sbin/in.telnetd
  }

и перезапустить сервер xinetd:


sudo service xinetd restart

Проверяем телнет локально:


@ansible-server:~$ telnet 127.0.0.1
  Trying 127.0.0.1...
  Connected to 127.0.0.1.
  Escape character is '^]'.
  Ubuntu 16.04.2 LTS
  ansible-server login:

Работает!


Закачиваем полученный образ в виртуальную машину EVE-NG и пробуем собрать топологию.


Теперь мы можем, настроив на соседней цыске в топологии адрес из подсети сервера, до него достучаться по telnet. Всё работает быстро, не в пример SSH.


Сбор топологии


Здесь всё чрезвычайно просто. Моя топология выглядит следующим образом:


image


Развёртывание подсистемы аnsible


Настройка CSR для работы с ansible


Выделим на каждом маршрутизаторe отдельный порт для управления и подключим к общему хабу с сервером ansible портами Gi2. Выберем подсеть для управления, у меня это 192.168.0.0/24. И назначим IP-адреса на портах в соответствии с номером маршрутизатора.


Эту же информацию занесем в /etc/hosts сервера:


192.168.0.1 R1
192.168.0.2 R2
192.168.0.3 R3
192.168.0.4 R4
192.168.0.5 R5
192.168.0.6 R6
192.168.0.7 R7
192.168.0.8 R8
192.168.0.9 R9
192.168.0.10 R10
192.168.0.11    XR1
192.168.0.12    XR2
192.168.0.20    SW1

На каждом маршрутизаторе настроим SSH v2 согласно ссылки. Всё тривиально, скажу лишь то, что для запуска требумеого нам SSHv2 нужно генерировать ключ более 768 бит, я выбрал размер 2048.


Проверяем доступ с сервера до маршрутизаторов по SSH, заодно собирая в хранилище ключи.


Сохраняем конфигурацию на маршрутизаторе:


R1#wr
Building configuration...
[OK]

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


image


Эта фича в EVE-NG, как и Unetlab до неё, работает с переменным успехом. Но будем надеяться.


Создание первого воркбука


Как мы помним, структура ansible состоит из двух основных частей — описания девайсов (inventory), и воркбука, собственно с логикой работы системы.


В нашем случае inventory достаточно примитивен и файл его содержащий (/etc/ansible/hosts) принимает вид:


[ios]
R[1:10]

Что раскрывается списком хостнеймов от R1 до R10 (помним, что мы уже прописали /etc/hosts для разрешения имён).


А вот с ворбуком придется повозиться.


Первым этапом, для того, чтобы залить конфигурацию, представляющую для нас лабораторный интерес, на виртуальный маршрутизатор IOS, нам необходимо сделать откат на начальную нулевую, содержащую только IP управления и настройки VTY.


Для этого мы попытаемся использовать модуль ios_command.


Основой всей работы по смене конфигураций в устройствах IOS для нас будет служить функционал команды привилегированного режима маршрутизатора:


configure replace scp://[PATH] force

Нулевые конфигурации будем хранить на сервере в домашнем каталоге нового пользователя под именем router в директории /home/router/default_configs/. Забегая вперед, скажу, что файлы будут иметь имена такие же, как и в inventory, т.е. в нашем случае это R1, R2 и т.д.


Создадим в /opt/ansible файл rollback.yml вида:


- name: rollback
  hosts: ios
  serial: 1
  connection: local
  gather_facts: false
  remote_user: cisco
  tasks:
    - name: Performing rollback to default configuration.
      ios_command:
        commands: configure replace scp://router:cisco@192.168.0.101:~/default_configs/{{ inventory_hostname }} force
        timeout: 30

Итак, по порядку:


Название плейбука:


- name: rollback

Название используемого инвентори:


hosts: ios

Количество параллельно конфигурируемых устройств из инвентори. Важная часть последующей оптимизации производительности.


  serial: 1

Как я понял, это говорит о соединении с локальным обработчиком заданий. Могу ошибаться.


 connection: local

Отключение сбора информации о хостах:


gather_facts: false

Имя пользователя для соединения с устройствами:


remote_user: cisco

Вызов модуля:


ios_command:

Передача команды в устройство из инвентори:


 commands: configure replace scp://router:cisco@192.168.0.101:~/default_configs/{{ inventory_hostname }} force

Время ожидания отклика в секундах:


timeout: 30

Ничего особо сложного, как мы видим, но есть одно но!


Попытаемся запустить…


ansible-playbook ./rollover.yml -k -vvvv

Получаем ошибку!


"msg": "ios_command does not support running config mode commands.  Please use ios_config instead"

Гугл нам об этом не особо много расскажет, поэтому вооружаемся смекалкой и пытаемся найти кто же нам это заявил. И находим файл самого используемого нами модуля: /usr/local/lib/python2.7/dist-packages/ansible-2.3.0-py2.7.egg/ansible/modules/network/ios/ios_command.py, содержащий вот такой код:


        if module.check_mode and not item['command'].startswith('show'):
            warnings.append(
                'only show commands are supported when using check mode, not '
                'executing `%s`' % item['command']
            )
        elif item['command'].startswith('conf'):
            module.fail_json(
                msg='ios_command does not support running config mode '
                    'commands.  Please use ios_config instead'
            )

Явно, что разработчики немного перегнули палку, отнеся все параметры configure к конфигурационному режиму, поэтому дописываем в соответсвующую строку:


elif item['command'].startswith('configure terminal'):

Заработало!


root@ansible-server:/opt/ansible# ansible-playbook ./rollback.yml -k
SSH password: 
PLAY RECAP ******************************************************
R1                         : ok=1    changed=0    unreachable=0    failed=0   
R10                        : ok=1    changed=0    unreachable=0    failed=0   
R2                         : ok=1    changed=0    unreachable=0    failed=0   
R3                         : ok=1    changed=0    unreachable=0    failed=0   
R4                         : ok=1    changed=0    unreachable=0    failed=0   
R5                         : ok=1    changed=0    unreachable=0    failed=0   
R6                         : ok=1    changed=0    unreachable=0    failed=0   
R7                         : ok=1    changed=0    unreachable=0    failed=0   
R8                         : ok=1    changed=0    unreachable=0    failed=0   
R9                         : ok=1    changed=0    unreachable=0    failed=

Создание второго воркбука


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


/etc/ansible/hosts


[ios]
R[1:10]

[ios.base.ipv4]
R[1:6]

/opt/ansible/base.ipv4.yml


- name: base.ipv4
  hosts: ios.base.ipv4
  connection: local
  gather_facts: false
  remote_user: cisco
  serial: 1
  tasks:
    - name: base.ipv4 configuration load
      ios_config: 
        src: ./IOS-XE-initials/base.ipv4/{{ inventory_hostname }}

Файлы начальных конфигурации лежат в /opt/ansible/IOS-XE-initials/base.ipv4, соответственно. Основное отличие данного сценария — это использование функционала модуля ios_config и передача права ему интерпретировать те команды, которые необходимо выполнить на устройствах.


На этом всё, спасибо за внимание. Если статья достойна продолжения, то следующей темой станет настройка взаимодействия IOS XR и ansible.

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

  • 2 марта 2017 в 04:54

    0

    Спасибо, познавательно.

© Habrahabr.ru