В один прекрасный день я решил перейти с обычного 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)
shuron
14.03.2018 17:14Каково состоянии плагина на данный момент?
Могули я все правила моей Firewall провизионировать таким образом?brainfair Автор
14.03.2018 17:33Меня все устроило, любую задачу можно реализовать через него.
В принципе любое изменение конфига можно провижинить с помощью модуля junos_config. Если у вас много FW и вам надо разливать общий конфиг по ним, то это то что доктор прописал, остальные модули для упрощения общих действий. В статье не указал, но все так же работает на SRX100 и SRX240, в заявленных поддерживаемых платформах: ACX, EX, M, MX, NFX, PTX, QFX, SRX, T Series
Slach
Спасибо было интересно!