身為一個網路工程師,我深知建構一個高效能的網路實驗室對於技術學習和驗證的重要性。本文將分享我如何結合 GNS3 和 EVE-NG(先前稱為 UNetLab),並運用 Python 指令碼開發一個自動化的網路實驗環境,著重於 Cisco IOS XE 的升級流程。

虛擬路由器建置與設定

首先,我會選擇 EVE-NG 作為主要的虛擬化平台,因為它對 Cisco 虛擬裝置的支援度相當出色。我會匯入 Catalyst 8000v 的 .ova 檔案,並建立兩個虛擬路由器,分別命名為 c8kv01c8kv02。網路介面卡設定為 NAT 模式,以利與主機網路溝通。

完成虛擬路由器建置後,我會進行基本設定,包含設定 IP 位址、啟用介面以及設定 enable secret,方便後續使用 Python 指令碼操作:

# c8kv01 設定
interface GigabitEthernet1
ip address 192.168.127.111 255.255.255.0
no shutdown
enable secret cisco123

# c8kv02 設定
interface GigabitEthernet1
ip address 192.168.127.222 255.255.255.0
no shutdown
enable secret cisco123

這些設定確保路由器介面正常運作,並允許透過密碼進行遠端登入。

接著,我會使用 PuTTY 連線至路由器進行測試,確認設定正確無誤。

路由器進階設定與快照

為了提升安全性並方便後續的自動化操作,我會進行一些進階設定:

# 產生 RSA 金鑰
crypto key generate rsa 2048

# 設定 VTY 線路
line vty 0 15
exec-timeout 0

產生 RSA 金鑰是為了強化 SSH 連線的安全性,而設定 VTY 線路則可以避免連線逾時中斷。

完成設定後,我會建立快照,以便在需要時快速還原路由器狀態:

copy running-config startup-config
# 建立快照指令,例如:snapshot create pre-upgrade

copy running-config startup-config 指令會將目前的執行組態儲存至啟動組態,確保設定永久生效。

IOS XE 升級流程與自動化

傳統的 IOS XE 升級流程相當繁瑣,包含許多步驟:

  graph LR
    A[預檢查] --> B(網路連線);
    B --> C(登入憑證);
    C --> D(IOS MD5 驗證);
    D --> E(Flash 空間);
    E --> F(組態備份);
    F --> G[IOS 上傳];
    G --> H(MD5 驗證);
    H --> I[設定啟動系統];
    I --> J(組態備份);
    J --> K[重新載入];
    K --> L(版本驗證);
    L --> M(網路連線);
    M --> N(服務狀態);

此流程圖清楚地展現了 IOS XE 升級的各個步驟,從預檢查到最終的服務狀態驗證。

為了提升效率,我會使用 Python 指令碼自動化這個流程。以下是一個簡化的程式碼範例:

import netmiko

# 連線至路由器
connection = netmiko.ConnectHandler(device_type='cisco_ios', ip=ip, username=username, password=password, secret=secret)

# 檢查 Flash 空間
output = connection.send_command('show flash:')
# ... 處理 Flash 空間資訊 ...

# 上傳 IOS 檔案
# ... 使用 SCP 或 TFTP 上傳 IOS 檔案 ...

# 設定啟動系統
connection.send_config_set(['boot system flash bootflash:new_ios.bin'])

# 重新載入路由器
connection.send_command_timing('reload', strip_prompt=False, strip_command=False)

# ... 驗證 IOS 版本和服務狀態 ...

connection.disconnect()

這段程式碼示範瞭如何使用 netmiko 函式庫連線至路由器、執行指令和設定,實作 IOS XE 升級的自動化。

透過結合 GNS3 和 EVE-NG,並搭配 Python 自動化指令碼,我成功開發了一個高效能的網路自動化實驗室。這不僅提升了我的學習效率,也讓我更深入地理解網路自動化的精髓。未來,我將持續探索更多進階的自動化技術,並將其應用於更複雜的網路場景。

在企業網路中,程式碼如何影回應用程式和裝置至關重要。人工智慧雖然能加速開發流程,但紮實的程式設計基礎知識仍然不可或缺。開發人員和工程師需對程式碼的效能和結果負責,無論使用何種工具。即使用人工智慧輔助編碼,也必須對編碼原則有深入的理解,並對程式碼的效能及其對企業系統的影響負責。基礎知識和人工智慧驅動的編碼在現今的編碼領域都扮演著關鍵角色。

本文將著重於使用 ICMP 和 Socket 程式設計,建構更強大的網路連線驗證工具。

工具開發:網路連線和 Socket 驗證工具

網路工程師的首要任務是維持網路中各種 IP 裝置、應用程式和使用者之間的連線穩定,盡可能減少或消除網路中斷。網路穩定性和安全性一直是網路管理的優先事項。

在撰寫網路自動化應用程式時,網路穩定性和安全性仍然是主要的考量,這要求開發人員遵守最佳網路和安全實務。同時具備網路和程式設計最佳實務的能力對於建立強大的網路自動化應用程式至關重要。

以下將探討開發網路工具片段的不同方法,這些片段最終將用於 Cisco 路由器升級。

ICMP 連線驗證

首先,我們將開發網路連線工具,透過重構程式碼來增強其功能。此工具將測試伺服器 (u22s1) 與兩台路由器 (c8kv01 和 c8kv02) 之間的通訊。ICMP (ping) 和 socket (port) 掃描是網路工程師的基本任務,我們的應用程式將使用 Python 程式碼來實作這些任務。

版本一:基本 ICMP 驗證

import os

device_list = ['192.168.127.111', '192.168.127.222']

for ip in device_list:
    if ip:  # 檢查 IP 是否為空字串
        print(f'正在傳送 ICMP 封包到 {ip}')
        resp = os.system(f'ping -c 3 {ip}')
        if resp == 0:
            print(f'{ip} 在網路上。')
            print('-' * 79)
        else:
            print(f'{ip} 無法連線。')
            print('-' * 79)
    else:
        exit()  # 如果 IP 為空,則結束程式

這段程式碼使用 os.system() 執行系統的 ping 命令,並根據傳回碼判斷裝置是否可連線。-c 3 引數限制只傳送三個 ICMP 封包。

版本二:區分可連線和不可連線 IP

import os

device_list = ['10.10.10.1', '192.168.127.111', '192.172.1.33', '192.168.127.222']
reachable_ips = []
unreachable_ips = []

for ip in device_list:
    if ip:
        print(f'正在傳送 ICMP 封包到 {ip}')
        resp = os.system(f'ping -c 3 {ip}')
        if resp == 0:
            reachable_ips.append(ip)
            print('-' * 79)
        else:
            unreachable_ips.append(ip)
            print('-' * 79)
    else:
        exit()

print("可連線的 IP:", reachable_ips)
print("不可連線的 IP:", unreachable_ips)

此版本新增了 reachable_ipsunreachable_ips 兩個列表,用於分別儲存可連線和不可連線的 IP 位址,方便後續處理。

  graph LR
    B[B]
    C[C]
    IP[IP]
    Ping[Ping]
    A[開始] --> B{迴圈遍歷 IP 列表};
    B -- IP 有效 --> C{執行 Ping 命令};
    C -- Ping 成功 --> D[加入 reachable_ips];
    C -- Ping 失敗 --> E[加入 unreachable_ips];
    D --> B;
    E --> B;
    B -- IP 列表結束 --> F[印出結果];
    F --> G[結束];

圖表説明: 此流程圖展示了 ICMP 驗證的邏輯流程,包含 IP 遍歷、Ping 命令執行、結果分類別以及最終輸出。

  sequenceDiagram
    participant 伺服器
    participant 目標裝置

    loop 遍歷 IP 列表
        伺服器->>目標裝置: Ping
        alt Ping 成功
            目標裝置-->>伺服器: 回應
            伺服器->>reachable_ips: 新增 IP
        else Ping 失敗
            伺服器->>unreachable_ips: 新增 IP
        end
    end

圖表説明: 此序列圖描述了伺服器與目標裝置之間的互動過程,以及如何根據 Ping 結果將 IP 加入不同的列表。

透過以上步驟,我們建構了一個更強大的網路連線驗證工具,它不僅可以驗證連線,還可以將可連線和不可連線的 IP 分類別,方便後續的網路自動化操作。

在後續的文章中,玄貓將繼續探討如何使用 Socket 程式設計來驗證網路連線,並分享更多網路自動化方面的實務經驗和技巧。敬請期待!

import getpass

def collect_credentials():
    """收集使用者憑證。"""

    username = input("請輸入使用者名稱:")
    password = getpass.getpass("請輸入密碼:")
    enable_password = getpass.getpass("請輸入啟用密碼(如有):")

    print(f"使用者名稱:{username}")  # 為了方便除錯,這裡顯示密碼,實際應用中不應顯示
    print(f"密碼:{password}")
    print(f"啟用密碼:{enable_password}")

    return username, password, enable_password


if __name__ == "__main__":
    credentials = collect_credentials()

這段程式碼定義了一個名為 collect_credentials 的函式,用於收集使用者憑證。它使用 input() 函式取得使用者名稱,並使用 getpass.getpass() 函式安全地取得密碼和啟用密碼(如果有的話)。為了方便除錯,程式碼會列印預收集到的憑證,但在實際應用中不應顯示密碼。最後,函式傳回收集到的憑證。

  graph LR
    B[B]
    C[C]
    D[D]
    E[E]
    A[開始] --> B{輸入使用者名稱};
    B --> C{輸入密碼};
    C --> D{輸入啟用密碼};
    D --> E{傳回憑證};
  sequenceDiagram
    participant 使用者
    participant 程式
    程式 ->> 使用者: 請求輸入使用者名稱
    使用者 -->> 程式: 提供使用者名稱
    程式 ->> 使用者: 請求輸入密碼
    使用者 -->> 程式: 提供密碼
    程式 ->> 使用者: 請求輸入啟用密碼
    使用者 -->> 程式: 提供啟用密碼
    程式 -->> 使用者: 傳回憑證

這個程式碼片段示範瞭如何使用 Python 的 getpass 模組安全地收集使用者憑證,為後續的 Cisco IOS-XE 升級工具的開發奠定了基礎。在實際應用中,切勿在程式碼中直接列印預密碼等敏感資訊。

接下來,我們可以將這些憑證儲存到檔案中,或直接用於與 Cisco 裝置的互動。在下一篇文章中,我們將探討如何使用 paramiko 模組與 Cisco 裝置建立 SSH 連線,並執行 IOS 升級操作。

身為一個網路自動化工作者,我經常需要處理一些敏感資訊,像是裝置的登入憑證。確保這些憑證的安全至關重要,同時也需要兼顧自動化指令碼的效率。今天,我想分享一些我在 Python 網路自動化方面的心得,特別是如何強化憑證驗證以及如何有效地管理大量的裝置資訊。

首先,讓我們來看看如何建立一個更安全的憑證取得流程。

強化憑證驗證功能

先前我曾設計一個簡單的憑證收集工具,但它存在一些安全隱患,例如使用者可以輸入任意資訊,與密碼輸入過程缺乏驗證。為了提升安全性,我加入了密碼和金鑰的驗證機制,要求使用者輸入兩次以確保一致性。此外,我也提供了一個選項,讓使用者決定是否使用與密碼相同的金鑰,以簡化操作。

以下程式碼片段展示了最佳化的憑證驗證功能:

from getpass import getpass

def get_secret():
    global secret
    resp = input("金鑰與密碼相同嗎? (y/n) : ")
    resp = resp.lower()
    if resp in ("yes", "y"):  # 金鑰與密碼相同
        secret = pwd
    elif resp in ("no", "n"):  # 金鑰與密碼不同
        secret = None
        while not secret:
            secret = getpass("請輸入金鑰 : ")  # 輸入金鑰
            secret_verify = getpass("請再次輸入金鑰 : ")  # 確認金鑰
            if secret != secret_verify:  # 檢查金鑰是否比對
                print("! 金鑰不比對,請重新輸入。")
                secret = None
    else:
        get_secret()  # 遞迴呼叫 get_secret()

def get_credentials():
    global uid
    uid = input("請輸入網路管理員 ID : ")  # 輸入管理員 ID
    global pwd
    pwd = None
    while not pwd:
        pwd = getpass("請輸入網路管理員密碼 : ")  # 輸入管理員密碼
        pwd_verify = getpass("請再次輸入網路管理員密碼 : ")  # 確認管理員密碼
        if pwd != pwd_verify:  # 檢查密碼是否比對
            print("! 網路管理員密碼不比對,請重新輸入。")
            pwd = None
    get_secret()  # 取得用於密碼加密的金鑰
    return uid, pwd, secret  # 傳回憑證

get_credentials()  # 呼叫函式以取得憑證
print(uid, pwd, secret)  # 顯示取得的憑證

這段程式碼定義了兩個函式:get_secret()get_credentials()get_credentials() 函式負責取得使用者 ID 和密碼,並確認兩次輸入的密碼是否一致。get_secret() 函式則負責取得金鑰,並提供一個選項,讓使用者決定是否使用與密碼相同的金鑰。如果使用者選擇不同的金鑰,則需要輸入兩次以確認。程式碼使用了 getpass 模組來隱藏密碼輸入,並使用迴圈和條件陳述式來確保使用者輸入有效。最後,程式碼列印取得的使用者 ID、密碼和金鑰。

  graph LR
    B[B]
    C[C]
    D[D]
    F[F]
    G[G]
    H[H]
    A[開始] --> B{輸入使用者 ID};
    B --> C{輸入密碼};
    C --> D{確認密碼};
    D -- 密碼比對 --> E{詢問金鑰是否與密碼相同};
    E -- 是 --> F{設定金鑰與密碼相同};
    E -- 否 --> G{輸入金鑰};
    G --> H{確認金鑰};
    H -- 金鑰比對 --> F;
    F --> I[結束];

加入正規表示式限制輸入

為了進一步提升安全性,我加入了正規表示式來限制使用者輸入。在實際的 IT 環境中,通常會對使用者名稱和密碼的格式有所規定。透過正規表示式,我們可以強制執行這些規則,例如使用者名稱長度、允許的字元以及密碼的複雜度等,從而有效降低安全風險。

以下將示範如何使用正規表示式來限制使用者名稱和密碼的輸入格式:

import re
# ... (先前的程式碼)

def get_credentials():
    global uid
    while True:
        uid = input("請輸入網路管理員 ID : ")
        if re.match(r"^[a-zA-Z][a-zA-Z0-9_-]{4,29}$", uid):
            break
        else:
            print("! 無效的使用者名稱格式。請重新輸入。")

    # ... (後續的程式碼,包含密碼和金鑰的驗證)

這段程式碼使用了 re.match() 函式來驗證使用者名稱的格式。正規表示式 ^[a-zA-Z][a-zA-Z0-9_-]{4,29}$ 規定使用者名稱必須以字母開頭,後續可以包含字母、數字、底線和連字號,與總長度必須在 5 到 30 個字元之間。

使用 Pandas 讀取 CSV 檔案

在網路自動化任務中,我們常常需要處理大量的裝置資訊。為了提升效率,我使用 Pandas 模組從 CSV 檔案讀取資料。Pandas 提供了強大的資料處理能力,可以輕鬆地讀取、處理和分析大量的裝置資訊。

以下是一個簡單的範例,示範如何使用 Pandas 讀取 CSV 檔案中的裝置資訊:

import pandas as pd

def read_devices_from_csv(filename):
    try:
        df = pd.read_csv(filename)
        return df
    except FileNotFoundError:
        print(f"找不到檔案:{filename}")
        return None

# 使用範例
devices_df = read_devices_from_csv("devices.csv")
if devices_df is not None:
    print(devices_df)

這段程式碼定義了一個 read_devices_from_csv() 函式,它接受 CSV 檔案的名稱作為引數,並使用 pd.read_csv() 函式讀取檔案內容。如果檔案不存在,則會印出錯誤訊息並傳回 None

透過結合以上技巧,我們可以建立更安全、更有效率的 Python 網路自動化工具。