Python SSH

  • por
Contenido de la lección

Hay múltiples opciones para usar SSH en Python pero Paramiko es la más popular. Paramiko es una librería de protocolo SSHv2 para Python. En esta lección, te mostraré cómo usar Paramiko para conectarte a un router Cisco IOS, ejecutar un comando show y devolvernos la salida.

Configuración

Aquí está la topología:

Python H1 R1

Utilizaré un router Cisco IOS que ejecuta la versión 15 del IOS.7(3)M3 y ejecutaré el código Python desde mi ordenador.

Router

En el router, tenemos que habilitar SSH:

R1(config)#ip domain-name networklessons.localR1(config)#crypto key generate rsa general-keys modulus 1024R1(config)#ip ssh version 2R1(config)#username admin privilege 15 secret adminR1(config)#line vty 0 4R1(config-line)#transport input sshR1(config-line)#login local

He configurado un usuario «admin» con nivel de privilegio 15 para que tengamos acceso completo al router una vez que iniciemos sesión.

Python

Necesitamos instalar Paramiko, lo cual es fácil con PIP:

pip install paramiko

Ya estamos listos para probar algo de código.

Código de ejemplo

En nuestro primer ejemplo, esto es lo que intentamos conseguir:

  • Conectarse al router con autenticación de nombre de usuario/contraseña.
  • Ejecutar el comando show ip route.
  • Buscar la ruta por defecto en la salida y mostrárnosla.

Aquí está mi código:

import paramikorouter_ip = "172.16.1.100"router_username = "admin"router_password = "admin"ssh = paramiko.SSHClient()# Load SSH host keys.ssh.load_system_host_keys()# Add SSH host key automatically if needed.ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())# Connect to router using username/password authentication.ssh.connect(router_ip, username=router_username, password=router_password, look_for_keys=False )# Run command.ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command("show ip route")output = ssh_stdout.readlines()# Close connection.ssh.close()# Analyze show ip route outputfor line in output: if "0.0.0.0/0" in line: print("Found default route:") print(line)

Cuando ejecutamos este código, esto es lo que obtenemos:

Found default route:S* 0.0.0.0/0 via 172.16.1.254

Esto está bien. Hemos conseguido conectarnos al router, ejecutar el comando show ip route y buscar la ruta por defecto.

Código de ejemplo mejorado

¿Cómo podríamos mejorar este script con algunas de las cosas que hemos aprendido? Por ejemplo:

  • Nuestro código ejecuta un único comando. Qué tal si usamos una función para poder usar nuestro código para conectarse a diferentes dispositivos y ejecutar diferentes comandos?
  • ¿Qué pasa si nuestra conexión SSH falla? Estaría bien tratar esto con un bloque try/except. ¿Qué tal si intentamos conectarnos varias veces?
    • Veamos qué podemos hacer. Aquí está mi código mejorado:

import paramikorouter_ip = "172.16.1.100"router_username = "admin"router_password = "admin1"ssh = paramiko.SSHClient()def run_command_on_device(ip_address, username, password, command): """ Connect to a device, run a command, and return the output.""" # Load SSH host keys. ssh.load_system_host_keys() # Add SSH host key when missing. ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) total_attempts = 3 for attempt in range(total_attempts): try: print("Attempt to connect: %s" % attempt) # Connect to router using username/password authentication. ssh.connect(router_ip, username=router_username, password=router_password, look_for_keys=False ) # Run command. ssh_stdin, ssh_stdout, ssh_stderr = ssh.exec_command(command) # Read output from command. output = ssh_stdout.readlines() # Close connection. ssh.close() return output except Exception as error_message: print("Unable to connect") print(error_message)# Run functionrouter_output = run_command_on_device(router_ip, router_username, router_password, "show ip route")# Analyze show ip route output# Make sure we didn't receive empty output.if router_output != None: for line in router_output: if "0.0.0.0/0" in line: print("Found default route:") print(line)

¿Qué he cambiado?

  • He creado una función para contener el código que se utiliza para conectarse al router.
  • He añadido un bloque try/except para la conexión con múltiples intentos. Cuando la conexión falla, muestra el motivo.
  • Una comprobación extra para ver si la salida del router contiene alguna información.
    • Verificación

      Volvamos a ejecutar nuestro código para ver si funciona.

      Contraseña incorrecta

      Cuando se suministra una contraseña incorrecta, se obtiene esta salida:

Attempt to connect: 0Unable to connectAuthentication failed.Attempt to connect: 1Unable to connectAuthentication failed.Attempt to connect: 2Unable to connectAuthentication failed.

Esto se ve bien. Nuestro código intentó conectarse tres veces y mostró la razón por la que no pudo conectarse.

Host no disponible

Cuando tu host no está disponible, obtienes esta salida:

Attempt to connect: 0Unable to connect A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respondAttempt to connect: 1Unable to connect A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respondAttempt to connect: 2Unable to connect A connection attempt failed because the connected party did not properly respond after a period of time, or established connection failed because connected host has failed to respond

Una vez más, tres intentos de conexión y muestra la razón por la que nuestro script falló.

Conclusión

Ahora has aprendido cómo puedes conectarte a un dispositivo usando SSH y Python. Aunque esto funciona, puede que no sea la mejor solución. En este ejemplo, ejecuté el comando show ip route y busqué la ruta por defecto. Esto es sencillo, pero ¿qué pasa si quieres analizar los comandos de show que tienen mucha información?

Es posible analizar la salida de los comandos de show como este usando expresiones regulares, pero es un dolor. En su lugar, si es posible, es mejor utilizar una API REST donde el dispositivo devuelve la salida en formato JSON. Analizar JSON en Python es mucho más fácil.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *