Sự chuyển dịch từ CLI thủ công sang Network-as-Code
Tôi đã từng dành quá nhiều đêm trực bảo trì lúc 2 giờ sáng, nhìn chằm chằm vào con trỏ nhấp nháy, hy vọng rằng một thay đổi ACL 10 dòng sẽ không gây ra sự cố SEV-1. Tất cả chúng ta đều đã từng như vậy: gõ show ip bgp summary lần thứ mười, cầu nguyện rằng bản cập nhật prefix-list đơn giản không làm mất kết nối của một chi nhánh khu vực. Các phòng lab tiêu chuẩn như GNS3 hay EVE-NG rất tốt để học tập, nhưng chúng lại cực kỳ ngốn tài nguyên. Việc cố gắng mô phỏng một trục mạng sản xuất (production backbone) với 500 router trong một lab ảo là cách nhanh nhất để làm treo máy trạm của bạn.
Sau sáu tháng chạy Batfish trên một hệ thống backbone 200 node, tôi đã không còn phải “cầu may” nữa. Batfish không phải là một trình mô phỏng (simulator) hay trình giả lập (emulator). Nó là một công cụ phân tích cấu hình. Nó phân tích các cấu hình thiết bị thô của bạn—Cisco IOS-XE, Juniper JunOS, Arista EOS, hoặc Palo Alto—và xây dựng một mô hình toán học chặt chẽ cho toàn bộ mạng. Bạn có thể truy vấn trạng thái mạng của mình giống như một cơ sở dữ liệu SQL mà không cần khởi chạy bất kỳ máy ảo nào.
Việc chuyển đổi từ một Kỹ sư Mạng truyền thống sang một chuyên gia NetDevOps đòi hỏi sự thay đổi trong tư duy này. Trong quy trình làm việc Network-as-Code (NaC), các cấu hình của bạn chính là mã nguồn. Chúng phải vượt qua các bài kiểm tra đơn vị (unit tests) tự động trước khi được áp dụng lên thiết bị thật.
Thiết lập môi trường Batfish
Batfish sử dụng kiến trúc client-server. Các tác vụ nặng được xử lý bên trong một Docker container (engine), trong khi bạn tương tác với nó bằng Pybatfish, một thư viện Python. Thiết lập này rất gọn nhẹ và tích hợp hoàn hảo vào các đường ống CI/CD hiện đại.
1. Khởi chạy dịch vụ Batfish
Tải Docker image chính thức để bắt đầu. Nó nặng khoảng 1GB, nhẹ hơn nhiều so với một bộ máy ảo đầy đủ từ các nhà cung cấp.
docker pull batfish/allinone
docker run -d --name batfish -p 9997:9997 -p 9996:9996 batfish/allinone
2. Cài đặt Pybatfish
Cài đặt Python client trên máy cục bộ của bạn. Hãy sử dụng môi trường ảo (virtual environment) để tránh xung đột phiên bản với các công cụ tự động hóa khác.
python3 -m venv batfish-env
source batfish-env/bin/activate
pip install pybatfish
Cấu hình Snapshot và Tích hợp Python
Batfish tổ chức dữ liệu thành các “snapshot”. Một snapshot chỉ đơn giản là một thư mục chứa các tệp cấu hình của bạn. Bạn không cần phải khai báo cho Batfish biết các thiết bị kết nối với nhau như thế nào. Nó tự tìm ra cấu trúc liên kết (topology) bằng cách phân tích IP interface và các giao thức định tuyến trong các tệp văn bản đó.
Tổ chức thư mục của bạn như sau:
network_snapshot/
├── configs/
│ ├── border-router-01.cfg
│ ├── leaf-01.cfg
│ └── fw-dmz-01.cfg
└── hosts/ (tùy chọn để mô phỏng server)
Bây giờ, hãy sử dụng một đoạn mã Python để khởi tạo môi trường. Bước này sẽ tải cấu hình của bạn lên Docker container để phân tích.
from pybatfish.client.commands import bf_session, bf_init_snapshot
from pybatfish.question import bfq
# Kết nối tới Batfish engine cục bộ
bf_session.host = "localhost"
# Khởi tạo snapshot
SNAPSHOT_PATH = './network_snapshot'
bf_init_snapshot(SNAPSHOT_PATH, name='prod-network', overwrite=True)
Xác thực các chính sách định tuyến và bảo mật
Sau khi mô hình được xây dựng, Batfish hiểu rõ topology của bạn. Nó biết interface nào là láng giềng của nhau dựa trên dữ liệu LLDP hoặc khớp subnet. Giờ đây, bạn có thể chạy các truy vấn mà bình thường sẽ mất hàng giờ thực hiện các lệnh show thủ công.
Tìm kiếm các lỗi tiềm ẩn
Cấu hình của bạn có “sạch” không? Bạn có thể kiểm tra các “tham chiếu không xác định” (undefined references), chẳng hạn như một BGP neighbor tham chiếu đến một route-map không thực sự tồn tại. Trong một tệp cấu hình lớn với hơn 5.000 dòng, những lỗi đánh máy này rất dễ bị bỏ sót nhưng có thể gây ra lỗi ngầm.
# Tìm các lỗi đánh máy như thiếu prefix-list hoặc route-map
undefined_refs = bfq.undefinedReferences().answer().frame()
print(undefined_refs)
Kiểm tra khả năng thông suốt của Firewall
Đây là tính năng giúp nhóm của tôi tiết kiệm được nhiều thời gian nhất. Thay vì phỏng đoán xem một ACL có hoạt động hay không, bạn có thể mô phỏng một luồng gói tin cụ thể. Giả sử bạn cần xác thực rằng VLAN 100 (10.10.1.0/24) có thể truy cập Postgres_DB (192.168.50.10) qua cổng 5432.
# Định nghĩa truy vấn khả năng thông suốt của luồng
reachability = bfq.reachability(
pathConstraints=bfq.pathConstraints(startLocation="leaf-01"),
headers=bfq.headerConstraints(
srcIps="10.10.1.0/24",
dstIps="192.168.50.10",
ipProtocols=["tcp"],
dstPorts="5432"
)
).answer().frame()
print(reachability)
Nếu luồng bị chặn, Batfish sẽ không chỉ báo “Deny”. Nó sẽ chỉ cho bạn chính xác dòng nào trong ACL hoặc chính sách firewall đã chặn lưu lượng đó. Không còn phải dùng lệnh packet-tracer trên mười thiết bị khác nhau nữa.
Mô phỏng các thay đổi bằng Phân tích tác động
Sức mạnh thực sự của Network-as-Code là “Phân tích vi sai” (Differential Analysis). Trước khi đẩy một thay đổi lên Arista spine, tôi tạo một snapshot tạm thời với các chỉnh sửa đề xuất. Sau đó, tôi so sánh nó với snapshot production hiện tại.
Kiểm tra “Bán kính ảnh hưởng”
Câu hỏi differentialReachability cho biết chính xác những luồng nào sẽ được thêm mới hoặc bị gián đoạn. Nếu bạn đang gỡ bỏ một subnet cũ, bài kiểm tra này đảm bảo bạn không vô tình làm ngắt lưu lượng của một dịch vụ mà bạn đã quên mất sự tồn tại của nó.
# So sánh snapshot 'hiện tại' với 'đề xuất'
comparison = bfq.differentialReachability(
baseSnapshot='prod-network',
snapshot='proposed-change'
).answer().frame()
if not comparison.empty:
print("Cảnh báo: Thay đổi này ảnh hưởng đến các luồng lưu lượng hiện có!")
print(comparison)
Xác thực liên tục trong GitLab
Trong thiết lập hiện tại của tôi, các script này chạy bên trong GitLab CI pipeline. Mỗi khi một đồng nghiệp mở một Merge Request cho một thay đổi cấu hình, pipeline sẽ tự động kích hoạt. Nó khởi chạy Batfish, tải cấu hình mới và chạy một loạt các bài kiểm tra: không có vòng lặp định tuyến (routing loops), không để lộ các tuyến nội bộ ra ISP và quyền truy cập SSH chỉ giới hạn trong subnet quản trị.
Quy trình làm việc này đã loại bỏ hiệu quả các sự cố do lỗi con người trong trung tâm dữ liệu của chúng tôi. Chúng tôi không còn phỏng đoán xem một thay đổi có an toàn hay không; chúng tôi sử dụng toán học để chứng minh điều đó. Mặc dù Pybatfish có một chút khó khăn khi mới bắt đầu—đặc biệt nếu bạn không quen với Pandas DataFrames—nhưng sự an tâm mà nó mang lại trong suốt quá trình bảo trì là hoàn toàn xứng đáng.
Nếu mạng của bạn có hơn 20 thiết bị, việc xác thực thủ công là không còn đủ. Hãy xây dựng một mô hình Batfish và để công cụ này thực hiện việc kiểm tra giúp bạn.
