network-config-validation

network-config-validation

熱門

路由器與交換器設定檔的上線前檢查,涵蓋高風險指令、重複 IP 地址、子網路重疊、失效引用、管理面風險以及 IOS 風格的資安衛生檢查。

24萬星標
3.6萬分支
更新於 2026/8/3
SKILL.md
唯讀
名稱
network-config-validation
描述

路由器與交換器設定檔的上線前檢查,涵蓋高風險指令、重複 IP 地址、子網路重疊、失效引用、管理面風險以及 IOS 風格的資安衛生檢查。

網路設定檔驗證

在變更維護時段(change window)之前,或是自動化腳本準備套用到正式環境設備前,可使用此 Skill 審查網路設定檔。

適用時機

  • 在部署前審查 Cisco IOS 或 IOS-XE 風格的設定片段。
  • 稽核由腳本或範本自動產生的設定檔。
  • 排查高風險指令、重複的 IP 地址或子網路重疊問題。
  • 檢查 ACL、route-map、prefix-list 或 line policy 是否出現「有引用卻未定義」的情形。
  • 為網路自動化建置輕量級的上線前檢查(pre-flight)腳本。

運作原理

請將設定檔驗證視為多層次的事實查證,而非完整的解析器(parser)。正則表達式(Regex)檢查非常適合用於上線前的預警,但最終的核可仍需由網路工程師審查變更意圖、平台語法以及復原(rollback)步驟。

建議依以下順序進行驗證:

  1. 具破壞性的高風險指令。
  2. 憑證與管理面(management-plane)暴露風險。
  3. 重複的 IP 地址與重疊的子網路。
  4. 對 ACL、route-map、prefix-list 及介面(interface)的失效引用。
  5. 營運最佳實踐(Operational hygiene),例如 NTP、時間戳記、遠端日誌(remote logging)與登入 banner。

高風險指令檢測

import re

DANGEROUS_PATTERNS: list[tuple[re.Pattern[str], str]] = [
    (re.compile(r"\breload\b", re.I), "reload causes downtime"),
    (re.compile(r"\berase\s+(startup|nvram|flash)", re.I), "erases persistent storage"),
    (re.compile(r"\bformat\b", re.I), "formats a device filesystem"),
    (re.compile(r"\bno\s+router\s+(bgp|ospf|eigrp)\b", re.I), "removes a routing process"),
    (re.compile(r"\bno\s+interface\s+\S+", re.I), "removes interface configuration"),
    (re.compile(r"\baaa\s+new-model\b", re.I), "changes authentication behavior"),
    (re.compile(r"\bcrypto\s+key\s+(zeroize|generate)\b", re.I), "changes device SSH keys"),
]

def find_dangerous_commands(lines: list[str]) -> list[dict[str, str | int]]:
    findings = []
    for line_number, line in enumerate(lines, start=1):
        stripped = line.strip()
        for pattern, reason in DANGEROUS_PATTERNS:
            if pattern.search(stripped):
                findings.append({
                    "line": line_number,
                    "command": stripped,
                    "reason": reason,
                })
    return findings

重複 IP 與子網路重疊檢測

import ipaddress
import re
from collections import Counter

IP_ADDRESS_RE = re.compile(
    r"^\s*ip address\s+"
    r"(?P<ip>\d{1,3}(?:\.\d{1,3}){3})\s+"
    r"(?P<mask>\d{1,3}(?:\.\d{1,3}){3})\b",
    re.I | re.M,
)

def extract_interfaces(config: str) -> list[dict[str, str]]:
    results = []
    current = None
    for line in config.splitlines():
        if line.startswith("interface "):
            current = line.split(maxsplit=1)[1]
            continue
        match = IP_ADDRESS_RE.match(line)
        if current and match:
            ip = match.group("ip")
            mask = match.group("mask")
            network = ipaddress.ip_interface(f"{ip}/{mask}").network
            results.append({"interface": current, "ip": ip, "network": str(network)})
    return results

def find_duplicate_ips(config: str) -> list[str]:
    ips = [entry["ip"] for entry in extract_interfaces(config)]
    counts = Counter(ips)
    return sorted(ip for ip, count in counts.items() if count > 1)

def find_subnet_overlaps(config: str) -> list[tuple[str, str]]:
    networks = [ipaddress.ip_network(entry["network"]) for entry in extract_interfaces(config)]
    overlaps = []
    for index, left in enumerate(networks):
        for right in networks[index + 1:]:
            if left.overlaps(right):
                overlaps.append((str(left), str(right)))
    return overlaps

管理面檢查

按區塊解析 VTY 設定,避免 access-class 的檢查誤跨到不相干的行。

import re

def iter_blocks(config: str, starts_with: str) -> list[str]:
    blocks = []
    current: list[str] = []
    for line in config.splitlines():
        if line.startswith(starts_with):
            if current:
                blocks.append("\n".join(current))
            current = [line]
            continue
        if current:
            if line and not line.startswith(" "):
                blocks.append("\n".join(current))
                current = []
            else:
                current.append(line)
    if current:
        blocks.append("\n".join(current))
    return blocks

def check_vty_blocks(config: str) -> list[str]:
    issues = []
    for block in iter_blocks(config, "line vty"):
        if re.search(r"transport\s+input\s+.*telnet", block, re.I):
            issues.append("VTY allows Telnet; require SSH only.")
        if not re.search(r"\baccess-class\s+\S+\s+in\b", block, re.I):
            issues.append("VTY block has no inbound access-class source restriction.")
        if not re.search(r"\bexec-timeout\s+\d+\s+\d+\b", block, re.I):
            issues.append("VTY block has no explicit exec-timeout.")
    return issues

資安維護檢查

SECURITY_PATTERNS = [
    (re.compile(r"\bsnmp-server community\s+(public|private)\b", re.I),
     "default SNMP community configured"),
    (re.compile(r"\bsnmp-server community\s+\S+", re.I),
     "SNMPv2 community string configured; prefer SNMPv3 authPriv"),
    (re.compile(r"\bip ssh version 1\b", re.I),
     "SSH version 1 enabled"),
    (re.compile(r"\benable password\b", re.I),
     "enable password is present; use enable secret"),
    (re.compile(r"\busername\s+\S+\s+password\b", re.I),
     "local username uses password instead of secret"),
]

BEST_PRACTICE_PATTERNS = [
    (re.compile(r"\bntp server\b", re.I), "NTP server"),
    (re.compile(r"\bservice timestamps\b", re.I), "log timestamps"),
    (re.compile(r"\blogging\s+\S+", re.I), "logging destination or buffer"),
    (re.compile(r"\bsnmp-server group\s+\S+\s+v3\s+priv\b", re.I), "SNMPv3 authPriv group"),
    (re.compile(r"\bbanner\s+(login|motd)\b", re.I), "login banner"),
]

def check_security(config: str) -> list[str]:
    return [message for pattern, message in SECURITY_PATTERNS if pattern.search(config)]

def check_missing_hygiene(config: str) -> list[str]:
    return [
        f"Missing {description}"
        for pattern, description in BEST_PRACTICE_PATTERNS
        if not pattern.search(config)
    ]

範例

變更維護時段上線前檢查

  1. 針對即將貼上執行的設定片段,執行高風險指令檢查。
  2. 對完整的預計套用設定檔(candidate config)執行重複 IP 與子網路重疊檢查。
  3. 確認所有被引用的 ACL、route-map 及 prefix-list 皆已正確定義。
  4. 在變更任何管理面設定之前,先確認復原指令(rollback commands)與帶外管理(out-of-band)存取管道暢通。

自動化上線前檢查

在透過 Netmiko、NAPALM、Ansible 或原廠 API 等自動化工具推送產生的設定檔之前,將此驗證作為攔截關卡(blocking gate)。遇到高風險指令與憑證問題時直接擋下(fail closed);對於不在本次變更範圍內的最佳實踐落差,則給予警告即可。

反模式

  • 將 Regex 驗證當作完整的設備解析器使用。
  • 未先進行 dry-run 與比對差異(diff)就直接套用產生的設定檔。
  • 將 SNMPv2 community string 作為監控需求的建議做法。
  • 使用可能不小心跨越不相干區塊的 Regex 來檢查 VTY 區塊。
  • 透過停用 ACL 來測試防火牆行為,而非讀取計數器(counters)或日誌。

延伸參考

  • Agent: network-config-reviewer
  • Agent: network-troubleshooter
  • Skill: network-interface-health