SKILL.md
唯讀
名稱
netmiko-ssh-automation
描述
提供安全的 Python Netmiko 設計模式,涵蓋唯讀資料收集、受控的批次 SSH 連線、TextFSM 解析、具防護機制的組態變更、逾時設定以及網路自動化錯誤處理。
Netmiko SSH 自動化
在撰寫或審查使用 Netmiko 連線至網路設備的 Python 自動化腳本時,請使用此 Skill。預設流程應保持唯讀;變更組態需在獨立的變更視窗中執行,並具備同儕審查與復原計畫。
使用時機
- 收集路由器、交換器或防火牆上的
show指令輸出。 - 建立小型稽核腳本,以取得介面、路由或組態相關證據。
- 為網路 SSH 腳本新增逾時機制與例外處理。
- 當有對應範本時,使用 TextFSM 解析指令輸出。
- 在自動化腳本套用至正式環境設備前進行審查。
安全預設值
- 優先使用唯讀的
send_command()收集資料。 - 保持清冊(inventory)規模小且明確;切勿掃描整個 IP 位址範圍。
- 使用環境變數、金鑰管理系統(vault)或
getpass;絕不硬編碼(hardcode)憑證。 - 設定連線與讀取逾時。
- 限制併發數,避免舊型設備過載。
- 在執行
send_config_set()前,必須要求明確的操作員標籤(operator flag)。 - 變更未經確認與核准前,請勿呼叫
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("Username: "),
"password": os.environ.get("NETMIKO_PASSWORD") or getpass("Password: "),
"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("Authentication failed")
except NetmikoTimeoutException:
print("SSH connection timed out")
except ReadTimeout:
print("Command read timed out")
在範例中使用文件專用的占位符位址。請將實際清冊保存在被忽略的本機檔案或金鑰管理系統中。
批次收集
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())
除非已知網路設備總數與 AAA 系統機能可承受更高的連線量,否則請保持 max_workers 在較小數值。
結構化解析
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("No parser template matched; store raw output for review")
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("Dry run only. Candidate commands:")
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("Verify behavior before saving startup config.")
儲存組態是獨立的核准步驟。在正式環境中,變更紀錄應包含復原程式碼片段(rollback snippet)以及變更前後的對比證據。
審查檢核表
- 腳本是否指定了明確的清冊來源?
- 原始碼、日誌與例外訊息中是否均未包含憑證?
- 是否已設定
conn_timeout、auth_timeout以及指令read_timeout? - 失敗是否以單一設備為單位回報,且不會中止整個批次作業?
- 腳本是否避免了大範圍掃描與未加限制的併發?
- 組態變更是否具備試運行(dry-run)或明確的操作員標籤保護?
save_config()是否與初始推送分開,並與驗證步驟相連動?
反模式
- 在原始碼中硬編碼密碼、enable 密碼或私鑰。
- 將傳送組態指令設為預設執行路徑。
- 對 CIDR 區段直接執行自動化,而非使用經審核的清冊。
- 將完整的運行中組態(running config)記錄至未經去敏處理的共用系統。
- 將解析器的成功執行誤認為設備狀態正確的證明。
參見
- Skill:
cisco-ios-patterns - Skill:
network-config-validation - Skill:
network-interface-health






