📜 ⬆️ ⬇️

Ansible and telnet: when you can not, but really want


Telnet is obviously a very insecure protocol, and we strongly want to discourage usage. MITM can arise.
- Michael DeHaan, creator of Ansible

Absolutely agree. Um, what can I do when I have 20 thousand legacy switches that reboot / hang because of an SSH connection, and some of the equipment doesn't support it at all?
I ask under the cat.
UPD: the guide is outdated because a separate telnet module was released in version 2.5
docs.ansible.com/ansible/latest/modules/telnet_module.html


Ansible Features


Ssh


At the moment (release 2.3.0), Ansible uses 3 types of connections:
')

In fact, SSH consists of 2 types and is distinguished by the use of transport - ssh and paramiko. The latter was used by default up to Ansible 1.3, modern distributions use the smart parameter (i.e., OpenSSH), significantly speeding up SSH operation using multiplexing (Control Master function). For compatibility with legacy equipment, it is better to use paramiko, setting the –c paramiko key when working with modules / playbooks.

Important: when authenticating by password, and not by keys, sshpass is used instead of ssh.

Install the package if necessary.

 sudo apt-get install sshpass 

For RHEL-based systems, you need to enable EPEL.

 yum --enablerepo=epel install sshpass 

For SSH, there is an excellent raw module that sends one command to the required number of hosts and displays the output from all the hosts. For Telnet, we will have to use a playbook with similar functionality.

Telnet


To work with Telnet, we are forced to use the local connection type. This means that playbook commands will be executed directly on the Ansible host (on remote switches, Python is hardly installed, heh).

To do this, install:

 sudo apt-get install telnet 

or

 yum install telnet 

You will also need pexpect , which is available through the pip add-on manager. Pip is installed with Ansible, so just run:

 pip install pexpect 

Environment preparation is complete.

Inventory setting


Let's use the standard / etc / ansible / hosts file


 [test_cluster] 192.168.0.[10:25] 

So, our switches are included in the test_cluster entity, have IP addresses from 192.168.0.10 to 192.168.0.25. It is assumed that they are configured with a single account with administrator rights, telnet access is allowed.

Create our playbook in .yml format


 --- - 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}}\r\nlogout\r\nexit\r\nquit" echo: yes register: telnet_output - name: Debug output debug: var=telnet_output.stdout_lines 

We go in order:


 hosts: test_cluster 

Hosts to connect to

 gather_facts: false 

Normally does not work with network equipment, you need to disable

 connection: local 

Pexpect is only available on Ansible.

 tasks: 

Getting started with modules

 ignore_errors: true 

It is not known what will be in the output - because of the limited functionality of the expect module, the result FAILED can be obtained. It is recommended to disable.

 command: telnet "{{ inventory_hostname }}" 

It is executed on the Ansible host, it connects to all remote hosts.

 responses: 

(?i) means that the case is ignored.
Before : we indicate what we expect, after - what we answer.
# - we check that authentication is successful, we are in privileged mode; We answer with the combination of the command variable with the output from the terminal (logout / exit / quit)

Working with expect implies a thorough knowledge of the CLI of the remote host, and the ability to handle regular python expressions. For example, adding the string #: "save" would be meaningless, because the mapping will occur only on the first condition #: "{{COMMAND}}\r\nlogout\r\nexit\r\nquit"

 register: telnet_output 

We collect output, we place in the telnet_output variable. Debug returns us the output in a convenient form.

Run the playbook with the necessary command:

 ansible-playbook raw_telnet.yml -e '{"COMMAND":"show stp"}' 

Result of performance:

  "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", 

If desired, almost everything can be replaced by variables and not edit the playbook at all. Of course, storing passwords in clear form is also not safe, for this, there are Vaults in Ansible.

Links:


Original documentation
Ansible Basics
Ansible + networks

UPD: the guide is outdated because a separate telnet module was released in version 2.5
docs.ansible.com/ansible/latest/modules/telnet_module.html

Source: https://habr.com/ru/post/328486/


All Articles