Netmiko SSH 自動化
當您編寫或審查使用 Netmiko 連接到網路裝置的 Python 自動化腳本時,請使用此技能。保持預設路徑為唯讀;配置變更需要單獨的變更窗口、同儕審查和回滾計劃。
使用時機
- 收集路由器、交換機或防火牆的
show指令輸出。 - 為介面、路由或配置證據建立小型稽核腳本。
- 為網路 SSH 腳本添加超時處理和例外處理。
- 當範本存在時,使用 TextFSM 解析指令輸出。
- 在腳本接觸正式環境裝置之前進行審查。
安全預設
- 從唯讀的
send_command()收集開始。 - 保持庫存規模小且明確;不要掃描整個 IP 範圍。
- 使用環境變數、vault 或
getpass;絕不硬編碼憑證。 - 設定連線和讀取超時。
- 限制並發執行緒數,以免老舊裝置過載。
- 在
send_config_set()之前需要明確的操作者旗標。 - 在變更經過驗證和批准之前,不要呼叫
save_config()。
唯讀連線模式
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("使用者名稱: "),
"password": os.environ.get("NETMIKO_PASSWORD") or getpass("密碼: "),
"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("驗證失敗")
except NetmikoTimeoutException:
print("SSH 連線超時")
except ReadTimeout:
print("指令讀取超時")
在範例中使用文件範圍內的佔位位址。將真實庫存放於被忽略的本地檔案或機密管理系統中。
批次收集
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())
保持 max_workers 較低,除非已知裝置群和 AAA 系統能處理更高的連線數量。
結構化解析
Netmiko 可以要求 TextFSM、TTP 或 Genie 解析支援的指令輸出。將解析器輸出視為最佳化手段,而非唯一的證據路徑。
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("未匹配到解析器範本;存儲原始輸出以供審查")
else:
for row in parsed:
print(row)
如果解析結果驅動了關鍵決策,請將原始指令輸出與解析結果一同保留,以便操作者檢查不一致之處。
受保護的配置模式
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("僅乾執行。候選指令:")
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("在儲存啟動配置前,請先驗證行為。")
儲存配置是一個獨立的批准步驟。在正式環境中,請包含回滾片段,並在變更記錄中保留前後對比的證據。
審查檢查清單
- 腳本是否指明了明確的庫存來源?
- 憑證是否未出現在原始碼、日誌和例外訊息中?
- 是否設定了
conn_timeout、auth_timeout和指令read_timeout? - 是否針對每台裝置報告失敗,而不會停止整個批次?
- 腳本是否避免了廣泛掃描和無限制的並發?
- 配置變更是否位於乾執行模式或明確的操作者旗標之後?
save_config()是否與初始推送分離,並與驗證相關聯?
反模式
- 在原始碼中硬編碼密碼、啟用密碼或私鑰。
- 將發送配置指令作為預設程式碼路徑。
- 針對 CIDR 範圍而不是經過審查的庫存執行自動化。
- 將完整的執行配置日誌記錄到未經消毒的共享系統中。
- 將解析成功視為裝置狀態正確的證明。
另請參閱
- 技能:
cisco-ios-patterns - 技能:
network-config-validation - 技能:
network-interface-health