В один прекрасный день я решил перейти с обычного rsyslog собирающего логи со всех устройств на что-то другое, выбор и прочее к данной теме мало относится (выбрали Graylog2), но по итогу появилась задача заменить на всех устройства Juniper настройки syslog хоста.

В принципе пробежаться ручками (или накидать скрипт на perl) по сотне устройств и кликнуть команду не проблема, но в голове уже висела еще добрая пачка задач по автоматизации управления как сетевыми устройствами, так и еще парой сотней серверов. Если с Windows`ами проблем в моем окружении нет (используем SCCM), то с Linux окружением массовые операции обрастают либо ручными операциями, либо баш скриптами (можно и SCCM`ом управлять, но данный вариант мягко говоря неудобен).

А так как уже давно хотелось начать использовать Ansible, то он был выбран как старт для этой задачи (для Chef и Puppet все-таки задачи не такие крупные, а порог вхождения уже больше).

Установка Ansible


Установка Ansible проста, так как все из коробки (для этой задачи мы использовали ubuntu server 16.04.03):

sudo apt-add-repository ppa:ansible/ansible
sudo apt-get update
sudo apt-get install ansible

Изменим настройки в /etc/ansible/ansible.cfg
#Каталог для ролей по умолчанию
roles_path = /etc/ansible/roles
#Проверка при подключении, можно и оставить, но предварительно к хостам придется подключится по SSH и подтвердить отпечаток.
host_key_checking = False
#Журнал
log_path = /var/log/ansible.log
Данные настройки сугубо личные для меня, у себя вы можете использовать свои.


Модуль для Juniper


Juniper в теме и отличные парни, они разработали свой модуль. Информацию о нем можно найти на офф сайте: Ansible for JunOS. Начиная с версии Ansible 2.1 он нативно включен в core modules Ansible.

Установим данный модуль и проверим его в списке:

sudo ansible-galaxy install Juniper.junos
ansible-galaxy list

Так же для использования модуля нам понадобиться nccclient

sudo apt-get install python-pip
pip install ncclient

Подключение к устройствам


Подключаться Ansible к устройствам Juniper может несколькими способами, по умолчанию используется протокол Netconf и 830 порт. Так же можно использовать telnet и serial console connection, но telnet относительно не безопасен, а serial немного для специфичных задач, хотя первоначальную настройку «голого» железа при наличии подключения можно слихвой автоматизировать с его помощью.

Так же Netconf можно использовать и по-обычному 22 порту ssh, а в качестве транспорта использовать просто cli.

about Netconf
Что такое Netconf неплохо раскрыто в одной из старых публикаций на Хабре.

Для авторизации на устройствах хотелось бы сразу настроить авторизацию по ключу. Генерируем для удобства под root ключ RSA (почему не DSA будет понятно дальше). После копируем его в предварительно созданный /etc/ansible/.ssh для удобства использования.

ssh-keygen -t rsa
cp /root/.ssh/id_rsa.pub /etc/ansible/.ssh/ansible.pub
cp /root/.ssh/id_rsa /etc/ansible/.ssh/ansible

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

set system login user ansible class super-user authentication ssh-rsa "<SSH-key>"

Но мы это так же автоматизируем далее.

Hosts


К кому подключаться мы описываем в файле /etc/ansible/hosts.
В нем можно описать группы устройств и переменные, так как у меня используются разные устройства Juniper поэтому я сразу создам несколько групп:

/etc/ansible/hosts
[junex2200]
192.168.111.101
[junex3300]
192.168.111.51
[junexcore]
192.168.111.4
[junexdc]
192.168.111.11
[alljuniper:children]
junex2200
junex3300
junexcore
junexdc

[alljuniper:vars]
ansible_jun_username=ansible
ansible_jun_port=22
ansible_jun_timeout=60
ansible_ssh_private_key_file=/etc/ansible/.ssh/ansible


В данном файле я определил 4 группы, добавил в каждую группу по 1 устройству. После чего сделал общую группу и добавил переменные для авторизации, которые будут использоваться в playbook. Пользователь у нас будет «ansible», порт будем использовать 22, так как 830 по умолчанию не включен, а также увеличим timeout до 60, так как при commit время может легко быть больше стандартных 10 секунд.

если netconf хочется включить на juniper
set system services netconf ssh

Playbook первоначальной настройки


Первоначальную настройку я вынес в отдельный playbook. Так как у меня на всех устройствах есть пользователь для подключения, то я буду использовать ввод логин/пароля в playbook для создания пользователя «ansible» с нашим ключом. Так же при желании можно включить Netconf на 830 порт, но я не заметил разницы, поэтому считаю это излишним.

Создадим каталог /etc/ansible/playbooks/juniper и в нем наш первый playbook init.yml

Разберем содержание:

---
- name: juniper initialization playbook #название PB
  hosts: alljuniper #на какие hosts будем его применять
#подключаем модуль juniper
  roles:
  - Juniper.junos 
  connection: local
  gather_facts: no
#далее объявим переменные логин/пароль для ввода, пароль скрытый
  vars_prompt:
    - name: "DEVICE_USERNAME"
      promt: "Device username"
      private: no
    - name: "DEVICE_PASSWORD"
      promt: "Device password"
      private: yes
#объявим переменную для определения настроек подключения
  vars:
    provider_info:
      host: "{{ inventory_hostname }}"
      username: "{{ DEVICE_USERNAME }}" 
      password: "{{ DEVICE_PASSWORD }}"
      port: "{{ ansible_jun_port }}"
      timeout: "{{ ansible_jun_timeout }}"
#дальше блок самих задач
  tasks:
#проверка доступности нашего порта
  - name: junos check connection 
    wait_for:
      host: "{{ inventory_hostname }}"
      port: "{{ ansible_jun_port }}"
      timeout: 10
#создание пользователя
  - name: junos create ansible user with key-auth
    junos_user:
      provider: "{{ provider_info }}"
      name: "{{ ansible_jun_username }}"
      role: super-user
      sshkey: "{{lookup('file', '/etc/ansible/.ssh/ansible.pub') }}"
      state: present

Для создания пользователя мы используем модуль junos_user. Модуль умеет создавать пользователя только с ключом rsa и поэтому мы и сгенерировали его. В принципе можно использовать junos_config и написать прям нашу строчку с указанием dsa ключа.

set system login user ansible class super-user authentication ssh-dsa "<SSH-key>"

Запуск playbook


Запускаем созданный нами playbook init.yml:

sudo ansible-playbook init.yml

Результат выполнения
DEVICE_USERNAME: megaswitchuser
DEVICE_PASSWORD:

PLAY [juniper initialization playbook] ********************************************************************************

TASK [junos check connection] ********************************************************************************
ok: [192.168.111.101]
ok: [192.168.111.51]
ok: [192.168.111.4]
ok: [192.168.111.11]

TASK [junos create ansible user with key-auth] ********************************************************************************
changed: [192.168.111.101]
changed: [192.168.111.51]
changed: [192.168.111.4]
changed: [192.168.111.11]

PLAY RECAP ********************************************************************************
192.168.111.101               : ok=2    changed=1    unreachable=0    failed=0
192.168.111.51              : ok=2    changed=1    unreachable=0    failed=0
192.168.111.4               : ok=2    changed=1    unreachable=0    failed=0
192.168.111.11               : ok=2    changed=1    unreachable=0    failed=0



changed=1
означает об успешном изменении, можно зайти на любое устройство и да пользователь там будет уже создан.

При повторном запуске playbook, изменения не будут вносится повторно, и он напишет
changed=0

Настройка syslog


У нас есть модуль junos_logging. В принципе в большинстве случаев можно воспользоваться им, но мне нужно ввести расширенные параметры для хоста, а они не поддерживаются в этом модуле. Поэтому воспользуемся универсальным средством, модулем junos_config для добавления нового хоста, а модулем junos_logging для удаления старого.

Создаем playbook syslog.yml, в нем мы уже будет использовать авторизацию по ключам для нашего пользователя ansible.

---
- name: juniper set syslog to graylog2 #название PB
  hosts: alljuniper #на какие hosts будем его применять
#подключаем модуль juniper
  roles:
  - Juniper.junos
  connection: local
  gather_facts: no
#объявим переменную для определения настроек подключения, уже используем параметр пользователя определенный в hosts, keyfile подтянется оттуда же сам
  vars:
    provider_info:
      host: "{{ inventory_hostname }}"
      username: "{{ ansible_jun_username }}"
      port: "{{ ansible_jun_port }}"
      timeout: "{{ ansible_jun_timeout }}"
#дальше блок самих задач
  tasks:
#проверка доступности нашего порта
  - name: junos check connection
    wait_for:
      host: "{{ inventory_hostname }}"
      port: "{{ ansible_jun_port }}"
      timeout: "{{ ansible_jun_timeout }}"
#настройка конфигурации
  - name: set juniper syslog host
    junos_config:
      provider: "{{ provider_info }}"
#дальше идет блок строк конфигурации
      lines:
        - set system syslog host 192.168.111.210 any any
        - set system syslog host 192.168.111.210 port 2514
        - set system syslog host 192.168.111.210 structured-data brief
#добавляем комментарий к коммиту
      comment: update config add syslog graylog2

#удаляем старый сислог с помощью модуля junos_logging
 - name: delete old syslog host
    junos_logging:
      provider: "{{ provider_info }}"
      dest: host
      name: 192.168.111.208
      facility: any
      level: any
      state: absent

Запускаем:

sudo ansible-playbook syslog.yml

Результат выполнения

PLAY [juniper set syslog to graylog2] ********************************************************************************

TASK [junos check connection] ********************************************************************************
ok: [192.168.111.101]
ok: [192.168.111.51]
ok: [192.168.111.4]
ok: [192.168.111.11]

TASK [set juniper syslog host] ********************************************************************************
changed: [192.168.111.101]
changed: [192.168.111.51]
changed: [192.168.111.4]
changed: [192.168.111.11]

TASK [delete old syslog host] ********************************************************************************
changed: [192.168.111.101]
changed: [192.168.111.51]
changed: [192.168.111.4]
changed: [192.168.111.11]

PLAY RECAP ********************************************************************************
192.168.111.4               : ok=3    changed=1    unreachable=0    failed=0
192.168.111.11               : ok=3    changed=1    unreachable=0    failed=0
192.168.111.51               : ok=3   changed=1    unreachable=0    failed=0
192.168.111.101               : ok=3    changed=1    unreachable=0    failed=0



Зайдя на любой из Juniper`ов увидимо, что в настройках прописался наш новый syslog сервер, а старый удалился.

Опционально можно увидеть историю commit`ов с комментарием из playbook:

show system commit

0   2018-03-07 15:12:49 KRAT by ansible via netconf
    update config add syslog graylog2

Повторный вызов playbook`а также не будет менять конфигурацию, а сообщит о том что все «ок» и нет изменений.

Итоги


Мы настроили окружение для автоматизации настроек в нашей сети, теперь можно с легкостью управлять нашей сетью. Задачи которые можно решить с помощью модуля Juniper для Ansible не ограничиваются только изменением конфигурации, мы так же может обновлять версию ПО, перезагружать устройства, делать бекап конфигурации и многое другое.

Планы


Следующие планы я выделил для себя по данной теме с Ansible на ближайшее время.

  • Привести настройки других параметров Juniper`ов в единый вид.
  • Привести версию ПО на всех устройствах Juniper к одному виду.
  • Добавить сервера Linux в Ansible с авторизацией по ключу.
  • Прописать настройки rsyslog на Linux сервера на новый коллектор.
  • Обновить/Установить свежие агенты Zabbix на Linux серверах.

Инструмент и в правду отличный и я очень жалею только о том, что не начал пользоваться им ранее. Будь у вас одна машинка с Linux или 100 разных свичей, никогда не поздно и не рано начать автоматизировать свои действия.

Список протестированного оборудования


Juniper: EX3300, EX2200, EX4550
JunOS: 12.2R6.4, 12.3R3.4, 12.3R4.6, 12.3R6.6, 12.3R6.6, 12.2R9.4, 12.2R12.4

P.S.: уже в процессе написания статьи я наткнулся на статью по этой же теме на Хабре, поэтому попытался более полно раскрыть тему.

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


  1. Slach
    13.03.2018 14:14

    Спасибо было интересно!


  1. shuron
    14.03.2018 17:14

    Каково состоянии плагина на данный момент?
    Могули я все правила моей Firewall провизионировать таким образом?


    1. brainfair Автор
      14.03.2018 17:33

      Меня все устроило, любую задачу можно реализовать через него.
      В принципе любое изменение конфига можно провижинить с помощью модуля junos_config. Если у вас много FW и вам надо разливать общий конфиг по ним, то это то что доктор прописал, остальные модули для упрощения общих действий. В статье не указал, но все так же работает на SRX100 и SRX240, в заявленных поддерживаемых платформах: ACX, EX, M, MX, NFX, PTX, QFX, SRX, T Series