Automatisation SSH avec Netmiko
Utilisez cette compétence lors de l'écriture ou de la révision d'automatisations Python qui se connectent à des équipements réseau avec Netmiko. Gardez le chemin par défaut en lecture seule ; les modifications de configuration nécessitent une fenêtre de changement distincte, une relecture par un pair et un plan de retour arrière.
Quand l'utiliser
- Collecter la sortie de commandes
showsur des routeurs, commutateurs ou pare-feux. - Construire un petit script d'audit pour les interfaces, le routage ou les preuves de configuration.
- Ajouter des délais d'attente et une gestion des exceptions aux scripts SSH réseau.
- Analyser la sortie de commandes avec TextFSM lorsqu'un modèle existe.
- Réviser une automatisation avant qu'elle ne touche les équipements de production.
Réglages de sécurité par défaut
- Commencez par la collecte en lecture seule avec
send_command(). - Gardez l'inventaire petit et explicite ; ne balayez pas des plages d'adresses entières.
- Utilisez des variables d'environnement, un coffre-fort ou
getpass; ne codez jamais les identifiants en dur. - Définissez des délais d'attente de connexion et de lecture.
- Limitez la concurrence pour ne pas surcharger les équipements plus anciens.
- Exigez un indicateur explicite pour l'opérateur avant
send_config_set(). - N'appelez pas
save_config()tant que le changement n'a pas été vérifié et approuvé.
Modèle de connexion en lecture seule
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("Utilisateur : "),
"password": os.environ.get("NETMIKO_PASSWORD") or getpass("Mot de passe : "),
"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("Authentification échouée")
except NetmikoTimeoutException:
print("Connexion SSH expirée")
except ReadTimeout:
print("Lecture de la commande expirée")
Utilisez des adresses de documentation dans les exemples. Conservez l'inventaire réel dans un fichier local ignoré ou un système de gestion des secrets.
Collecte par lots
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())
Gardez max_workers bas à moins que le parc d'équipements et les systèmes AAA ne soient connus pour gérer un volume de connexions plus élevé.
Analyse structurée
Netmiko peut demander à TextFSM, TTP ou Genie d'analyser la sortie de commandes prises en charge. Considérez la sortie de l'analyseur comme une optimisation, pas comme la seule source de preuve.
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("Aucun modèle d'analyse trouvé ; conservez la sortie brute pour examen")
else:
for row in parsed:
print(row)
Si l'analyse guide une décision bloquante, conservez la sortie brute de la commande à côté du résultat analysé afin qu'un opérateur puisse inspecter les divergences.
Modèle de configuration protégée
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("Simulation uniquement. Commandes candidates :")
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("Vérifiez le comportement avant de sauvegarder la configuration de démarrage.")
Sauvegarder la configuration est une étape d'approbation distincte. En production, incluez un extrait de retour arrière et capturez les preuves avant/après dans l'enregistrement de changement.
Liste de vérification pour la révision
- Le script identifie-t-il une source d'inventaire explicite ?
- Les identifiants sont-ils absents du code source, des journaux et des messages d'exception ?
- Les délais
conn_timeout,auth_timeoutetread_timeoutde la commande sont-ils définis ? - Les échecs sont-ils signalés par équipement sans arrêter tout le lot ?
- Le script évite-t-il les analyses larges et la concurrence illimitée ?
- Les modifications de configuration sont-elles protégées par un indicateur de simulation ou un indicateur explicite pour l'opérateur ?
save_config()est-elle séparée du push initial et liée à une vérification ?
Anti-patrons
- Coder en dur les mots de passe, les secrets enable ou les clés privées dans le code source.
- Envoyer des commandes de configuration comme chemin de code par défaut.
- Exécuter l'automatisation sur une plage CIDR au lieu d'un inventaire examiné.
- Journaliser les configurations complètes en cours d'exécution vers des systèmes partagés sans anonymisation.
- Considérer le succès de l'analyse comme une preuve que l'état de l'équipement est correct.
Voir aussi
- Compétence :
cisco-ios-patterns - Compétence :
network-config-validation - Compétence :
network-interface-health