Ansible and telnet: when not, but really want


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, creator of Ansible I

absolutely agree. Um, what should I do when I have 20 thousand legacy switches that reboot / freeze due to SSH connection, and part of the equipment does not support it at all?
I ask for cat.
UPD: the guide is deprecated because in version 2.5 they released a separate telnet module
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:

  • Ssh
  • Local
  • Docker

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

Important: for password authentication, not key authentication, 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 output from all hosts. For Telnet, we will have to use a playbook that has 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 (Python, heh, are unlikely to be installed on remote switches).

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 along with Ansible, so just run:

pip install pexpect

Environment preparation is complete.

Inventory setup


We will use the standard file / etc / ansible / hosts


[test_cluster]
192.168.0.[10:25]

So, our switches are part of the test_cluster entity, they have IP addresses from 192.168.0.10 through 192.168.0.25. It is assumed that a single account with administrator rights is configured on them, 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

Let's go in order:


hosts: test_cluster

Hosts to which you are connecting

gather_facts: false

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

connection: local

Pexpect is only on the Ansible host.

tasks:

Getting started with modules

ignore_errors: true

It is not known what will happen in the output - due to the limited functionality of the expect module, the result may be FAILED. It is recommended to disable.

command: telnet "{{ inventory_hostname }}"

It runs on the Ansible host and connects to all remote hosts.

responses:

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

Working with expect requires a thorough knowledge of the CLI of the remote host, the presence of python regular expression skills. For example, adding a line #: "save"would be pointless because matching will occur only on the first condition#: "{{COMMAND}}\r\nlogout\r\nexit\r\nquit"

register: telnet_output

We collect the output, put it in the telnet_output variable. Debugreturns us the output in a convenient way.

We start the playbook with the necessary command:

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

Execution Result:

        "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 with variables and not edit the playbook at all. Of course, storing passwords in clear text is also unsafe, for this Vaults exist in Ansible.

REFERENCES:


Original documentation
Ansible basics
Ansible + UPD networks

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

Also popular now: