Telnet is a obviously a very insecure protocol, completely insecure in fact, and we strongly want to discourage usage. We would likely refuse the pull request, to be honest — it is just asking for a world of hurt should MITM possibilities arise.
— Michael DeHaan, создатель Ansible
Абсолютно согласен. Эм, а как мне быть, когда у меня 20 тысяч legacy свитчей, которые перезагружаются/зависают из-за подключения по SSH, а часть оборудования его вообще не поддерживает?
Прошу под кат.
Особенности Ansible
SSH
В данный момент (релиз 2.3.0) в Ansible используется 3 вида соединений:
- SSH
- Local
- Docker
На самом деле SSH состоит из 2 типов и отличается использованием транспорта – ssh и paramiko. Последний использовался по умолчанию до версии Ansible 1.3, современные дистрибутивы используют параметр smart (т.е. OpenSSH), значительно ускоряя работу SSH с помощью мультиплексирования (функция Control Master). Для совместимости с legacy оборудованием лучше использовать paramiko, устанавливая ключ –c paramiko
при работе с модулями/плейбуками.
Важно: при аутентификации по паролю, а не по ключам вместо ssh используется sshpass.
Если необходимо, установите пакет.
sudo apt-get install sshpass
Для RHEL-based систем нужно включить EPEL
yum --enablerepo=epel install sshpass
Для SSH есть прекрасный модуль raw, отправляющий одну команду требуемому количеству хостов и отображающий вывод со всех хостов. Для Telnet нам придется воспользоваться playbook, имеющим схожий функционал.
Telnet
Для работы с Telnet мы вынуждены использовать тип соединения local. Это означает, что команды playbook будут исполняться непосредственно на хосте Ansible (на удаленных свитчах вряд ли установлен Python, хех).
Для этого устанавливаем:
sudo apt-get install telnet
или
yum install telnet
Еще понадобится pexpect, который доступен через менеджер дополнений pip. Pip устанавливается вместе с Ansible, поэтому достаточно выполнить:
pip install pexpect
Подготовка окружения завершена.
Настройка inventory
Воспользуемся стандартным файлом /etc/ansible/hosts
[test_cluster]
192.168.0.[10:25]
Итак, наши коммутаторы входят в сущность test_cluster, имеют IP-адреса со 192.168.0.10 по 192.168.0.25. Предполагается, что на них настроен единый аккаунт с правами администратора, разрешен доступ по telnet.
Создаем наш playbook в формате .yml
---
- hosts: test_cluster
gather_facts: false
connection: local
tasks:
- name: telnet,login and execute command
ignore_errors: true
expect:
command: telnet "{{ inventory_hostname }}"
responses:
(?i)username: "admin"
(?i)password: "12345"
(?i)#: "{{COMMAND}}rnlogoutrnexitrnquit"
echo: yes
register: telnet_output
- name: Debug output
debug: var=telnet_output.stdout_lines
Идем по порядку:
hosts: test_cluster
Хосты, к которым выполняется подключение
gather_facts: false
Нормально не работает с сетевым оборудованием, нужно отключить
connection: local
Pexpect есть только на хосте Ansible.
tasks:
Начинаем работу с модулями
ignore_errors: true
Неизвестно, что будет в выводе – из-за ограниченного функционала модуля expect может получиться результат FAILED. Рекомендуется отключить.
command: telnet "{{ inventory_hostname }}"
Исполняется на хосте Ansible, происходит подключение ко всем удаленным хостам.
responses:
(?i)
означает, что игнорируется регистр.
До :
мы указываем, что ожидаем, после – чем отвечаем.
#
— проверяем, что аутентификация успешна, мы находимся в привилегированном режиме; отвечаем комбинацией переменной команды с выходом из терминала (logout/exit/quit)
Работа с expect предполагает доскональное знание CLI удаленного хоста, наличие навыков обращения с регулярными выражениями python. Например, добавление строки #: "save"
будет бессмысленно, т.к. сопоставление будет происходить только по первому условию #: "{{COMMAND}}rnlogoutrnexitrnquit"
register: telnet_output
Собираем вывод, помещаем в переменную telnet_output. Debug
возвращает нам вывод в удобном виде.
Запускаем playbook c нужной командой:
ansible-playbook raw_telnet.yml -e '{"COMMAND":"show stp"}'
Результат выполнения:
"Command: show stp",
"",
"",
"",
"STP Bridge Global Settings",
"",
"---------------------------",
"",
"STP Status : Enabled",
"",
"STP Version : RSTP",
"",
"Max Age : 20 ",
"",
"Hello Time : 2 ",
"",
"Forward Delay : 15 ",
"",
"Max Hops : 20 ",
"",
"TX Hold Count : 3 ",
"",
"Forwarding BPDU : Enabled",
При желании практически все можно заменить переменными и не править playbook вообще. Конечно, хранить пароли в открытом виде тоже небезопасно, для этого в Ansible существуют Vaults.
Cсылки:
→ Оригинальная документация
→ Основы Ansible
→ Ansible+сети
Автор: Necron