- PVSM.RU - https://www.pvsm.ru -

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

image

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

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

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

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

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

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

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

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

kvm-intel.nested=1

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

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

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

Проблема, с которой я столкнулся при добавлении образов — как называть директории, куда нужно складывать файлы 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 согласно ссылки [6]. Всё тривиально, скажу лишь то, что для запуска требумеого нам SSHv2 нужно генерировать ключ более 768 бит, я выбрал размер 2048.

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

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

R1#wr
Building configuration...
[OK]

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

image

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

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

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

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

[ios]
R[1:10]

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

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

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

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

Основой всей работы по смене конфигураций в устройствах 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 [9]и передача права ему интерпретировать те команды, которые необходимо выполнить на устройствах.

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

Автор: sfinks777

Источник [10]


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/virtualizatsiya/247092

Ссылки в тексте:

[1] EVE-NG: http://www.unetlab.com/

[2] ссылке: https://fedoraproject.org/wiki/How_to_enable_nested_virtualization_in_KVM

[3] XRv: https://upload.cisco.com/cgi-bin/swc/fileexg/main.cgi?CONTYPES=Cisco-IOS-XRv&msg=Download+complete

[4] CSR: https://software.cisco.com/download/release.html?mdfid=284364978&softwareid=282046477&release=3.16.5S&relind=AVAILABLE&rellifecycle=ED&reltype=latest

[5] how-to: http://www.unetlab.com/2014/11/adding-cisco-xrv-images/#main

[6] ссылки: http://xgu.ru/wiki/Cisco_SSH

[7] помним: https://habrahabr.ru/post/195048/

[8] ios_command.: https://docs.ansible.com/ansible/ios_command_module.html

[9] ios_config : https://docs.ansible.com/ansible/ios_config_module.html

[10] Источник: https://habrahabr.ru/post/323014/?utm_source=habrahabr&utm_medium=rss&utm_campaign=sandbox