Netmiko SSH Automation
Utilice esta habilidad al escribir o revisar automatización en Python que se conecta a dispositivos de red con Netmiko. Mantenga la ruta predeterminada de solo lectura; los cambios de configuración requieren una ventana de cambio separada, revisión por pares y un plan de retroceso.
Cuándo Usar
- Recopilar salida de comandos
showen routers, switches o cortafuegos. - Crear un pequeño script de auditoría para evidencia de interfaces, enrutamiento o configuración.
- Agregar tiempos de espera y manejo de excepciones a scripts SSH de red.
- Analizar la salida de comandos con TextFSM cuando exista una plantilla.
- Revisar la automatización antes de que toque dispositivos de producción.
Valores Predeterminados de Seguridad
- Comience con recolección de solo lectura usando
send_command(). - Mantenga el inventario pequeño y explícito; no escanee rangos completos de direcciones.
- Use variables de entorno, un gestor de secretos o
getpass; nunca codifique credenciales. - Establezca tiempos de espera de conexión y lectura.
- Limite la concurrencia para no sobrecargar dispositivos antiguos.
- Requiera una bandera explícita del operador antes de
send_config_set(). - No llame a
save_config()hasta que el cambio haya sido verificado y aprobado.
Patrón de Conexión de Solo Lectura
import os
from getpass import getpass
from netmiko import ConnectHandler
from netmiko.exceptions import (
NetmikoAuthenticationException,
NetmikoTimeoutException,
ReadTimeout,
)
device = {
"device_type": "cisco_ios",
"host": "192.0.2.10",
"username": os.environ.get("NETMIKO_USERNAME") or input("Usuario: "),
"password": os.environ.get("NETMIKO_PASSWORD") or getpass("Contraseña: "),
"secret": os.environ.get("NETMIKO_ENABLE_SECRET"),
"conn_timeout": 10,
"auth_timeout": 20,
"banner_timeout": 15,
"read_timeout_override": 30,
}
try:
with ConnectHandler(**device) as conn:
if device.get("secret") and not conn.check_enable_mode():
conn.enable()
output = conn.send_command("show ip interface brief", read_timeout=30)
print(output)
except NetmikoAuthenticationException:
print("Autenticación fallida")
except NetmikoTimeoutException:
print("La conexión SSH ha excedido el tiempo de espera")
except ReadTimeout:
print("La lectura del comando ha excedido el tiempo de espera")
Utilice direcciones de los rangos de documentación en los ejemplos. Mantenga el inventario real en un archivo local ignorado o en un sistema gestionado por secretos.
Recolección por Lotes
from concurrent.futures import ThreadPoolExecutor, as_completed
from typing import Any
def collect_show(device: dict[str, Any], command: str) -> dict[str, Any]:
host = device["host"]
try:
with ConnectHandler(**device) as conn:
output = conn.send_command(command, read_timeout=45)
return {"host": host, "ok": True, "output": output}
except (NetmikoAuthenticationException, NetmikoTimeoutException, ReadTimeout) as exc:
return {"host": host, "ok": False, "error": type(exc).__name__}
results = []
with ThreadPoolExecutor(max_workers=8) as pool:
futures = [pool.submit(collect_show, device, "show version") for device in devices]
for future in as_completed(futures):
results.append(future.result())
Mantenga max_workers bajo a menos que se sepa que el parque de dispositivos y los sistemas
AAA pueden manejar un mayor volumen de conexiones.
Análisis Estructurado
Netmiko puede pedirle a TextFSM, TTP o Genie que analicen la salida de comandos compatibles. Trate la salida del analizador como una optimización, no como la única vía de evidencia.
with ConnectHandler(**device) as conn:
parsed = conn.send_command(
"show ip interface brief",
use_textfsm=True,
raise_parsing_error=False,
read_timeout=30,
)
if isinstance(parsed, str):
print("No se encontró ninguna plantilla de analizador; guarde la salida sin procesar para revisión")
else:
for row in parsed:
print(row)
Si el análisis impulsa una decisión crítica, conserve la salida del comando sin procesar junto con el resultado analizado para que un operador pueda inspeccionar discrepancias.
Patrón de Cambio Protegido
import os
commands = [
"interface GigabitEthernet0/1",
"description CHANGE-1234 UPLINK-TO-CORE",
]
apply_changes = os.environ.get("APPLY_NETWORK_CHANGES") == "1"
if not apply_changes:
print("Solo simulación. Comandos candidatos:")
print("\n".join(commands))
else:
with ConnectHandler(**device) as conn:
conn.enable()
before = conn.send_command("show running-config interface GigabitEthernet0/1")
output = conn.send_config_set(commands)
after = conn.send_command("show running-config interface GigabitEthernet0/1")
print(before)
print(output)
print(after)
print("Verifique el comportamiento antes de guardar la configuración de inicio.")
Guardar la configuración es un paso de aprobación independiente. En producción, incluya un fragmento de retroceso y capture evidencia de antes/después en el registro de cambio.
Lista de Verificación de Revisión
- ¿El script identifica una fuente de inventario explícita?
- ¿Las credenciales están ausentes del código fuente, registros y mensajes de excepción?
- ¿Están configurados
conn_timeout,auth_timeoutyread_timeoutdel comando? - ¿Se reportan fallas por dispositivo sin detener todo el lote?
- ¿El script evita escaneos amplios y concurrencia ilimitada?
- ¿Los cambios de configuración están detrás de una simulación o bandera explícita del operador?
- ¿
save_config()está separado del envío inicial y vinculado a la verificación?
Anti-Patrones
- Codificar contraseñas, secretos de enable o claves privadas en el código fuente.
- Enviar comandos de configuración como la ruta de código predeterminada.
- Ejecutar automatización contra un rango CIDR en lugar de un inventario revisado.
- Registrar configuraciones completas en sistemas compartidos sin desinfección.
- Tratar el éxito del analizador como prueba de que el estado del dispositivo es correcto.
Véase También
- Habilidad:
cisco-ios-patterns - Habilidad:
network-config-validation - Habilidad:
network-interface-health