OPNsense High Availability với CARP và pfsync: Hướng dẫn thiết lập dự phòng hai node

Networking tutorial - IT technology blog
Networking tutorial - IT technology blog

Điểm lỗi đơn lẻ (Single Point of Failure) tại vùng biên mạng

Năm ngoái, một sự cố sập hypervisor đột ngột trên gateway vùng biên đã khiến 240 kỹ sư bị ngắt kết nối khỏi mạng nội bộ doanh nghiệp suốt 40 phút. Việc bảo trì định kỳ dần trở thành một rủi ro vận hành: cập nhật nhân (kernel) FreeBSD, khởi động lại IPS engine, hay triển khai các gói rule Suricata đều đòi hỏi phải canh cửa sổ bảo trì lúc nửa đêm trong trạng thái thấp thỏm cầu may. Các đường hầm WireGuard và OpenVPN đang hoạt động bị ngắt kết nối ngay lập tức. Luồng đồng bộ bản sao PostgreSQL đứt gãy giữa chừng khi đang truy vấn, và những cuộc gọi VoIP đang diễn ra đều bị mất tín hiệu.

Vận hành một tường lửa duy nhất trong môi trường production là một canh bạc mà sớm muộn gì bạn cũng sẽ thua. Linh kiện phần cứng hao mòn theo thời gian, nâng cấp firmware đôi khi bị treo, và bộ phân phối nguồn (PDU) có thể sập bất ngờ. Chúng tôi đặt ra một mục tiêu tái thiết kế nghiêm ngặt: quá trình failover phải hoàn tất trong vòng dưới 2 giây, bảng state đang hoạt động phải được giữ nguyên mà không làm ngắt các kết nối mở, và mọi thay đổi về rule đều phải được đồng bộ hóa tự động.

OPNsense xử lý vấn đề này theo cách native (tích hợp sẵn) với các giao thức BSD đã qua thực chiến: CARP, pfsync và XMLRPC. Sau khi vận hành mô hình hai node này qua hai đợt nâng cấp vòng đời phần cứng và hàng chục bản vá firmware, vùng biên mạng của chúng tôi chưa từng ghi nhận bất kỳ sự cố gián đoạn ngoài kế hoạch (unplanned downtime) nào.

Các giao thức cốt lõi: CARP, pfsync và XMLRPC

Một cụm OPNsense có khả năng phục hồi cao dựa trên sự phối hợp nhịp nhàng của ba cơ chế BSD độc lập.

1. Common Address Redundancy Protocol (CARP)

CARP đảm nhiệm việc chia sẻ địa chỉ IP ở Layer 2 và Layer 3. Đây là giải pháp nguồn mở của BSD thay thế cho các giao thức độc quyền như HSRP của Cisco hoặc VRRP. Nhiều tường lửa cùng chia sẻ một Virtual IP (VIP) duy nhất.

Các node thành viên đàm phán vai trò thông qua giá trị advertisement skew (advskew). Node master sẽ chạy với giá trị skew thấp nhất (thường là 0) và định kỳ phát các gói tin heartbeat (advbase, thường được đặt là 1 giây). Nếu node secondary (được cấu hình với advskew 100) bị lỡ ba gói heartbeat liên tiếp, nó sẽ tự động thăng cấp thành master và gửi một gói gratuitous ARP để lập tức chuyển hướng lưu lượng trên switch.

2. Đồng bộ hóa State qua pfsync

Chuyển giao quyền sở hữu IP mới chỉ giải quyết được một nửa vấn đề. Các tường lửa stateful theo dõi quá trình bắt tay TCP (handshake), số thứ tự sequence number và các bản ghi dịch địa chỉ NAT. Nếu tường lửa backup tiếp quản mà không có bảng kết nối của node chính, nó sẽ coi mọi gói tin gửi đến là bất thường ngoài trạng thái (out-of-state) và drop ngay lập tức.

Driver pfsync sinh ra để giải quyết điều này. Nó truyền trực tiếp các thao tác thêm mới, cập nhật và hết hạn trong bảng state qua một đường truyền chuyên dụng bằng giao thức IP protocol 240. Khi quá trình failover được kích hoạt, node secondary đã nắm giữ một bảng state hoàn toàn giống hệt chứa tất cả các phiên TCP, UDP và ICMP đang hoạt động.

3. Đồng bộ cấu hình qua XMLRPC

Đồng bộ các rule tường lửa bằng tay vừa chậm chạp lại vừa dễ dẫn đến hiện tượng sai lệch cấu hình (configuration drift). OPNsense khắc phục điều này nhờ os-xmlrpc-sync. Bất cứ khi nào bạn nhấp vào Apply Changes trên node chính, một lệnh gọi XMLRPC được mã hóa qua HTTPS sẽ đẩy các rule, alias, DHCP reservation và chính sách NAT mới cập nhật trực tiếp sang node phụ.

Từng bước triển khai: Xây dựng cụm tường lửa kép

Dưới đây là cấu hình đã qua kiểm thử thực tế của chúng tôi cho hai thiết bị—có thể là máy chủ vật lý bare-metal Dell PowerEdge hoặc máy ảo trên các hypervisor tách biệt.

Phân bổ Interface và IP

Cả hai thiết bị đều cần ba interface mạng chuyên dụng với tên driver trùng khớp nhau:

  • WAN (vtnet0): Node chính: 198.51.100.2/24 | Node phụ: 198.51.100.3/24 | CARP VIP dùng chung: 198.51.100.1/24
  • LAN (vtnet1): Node chính: 10.0.10.2/24 | Node phụ: 10.0.10.3/24 | CARP VIP dùng chung: 10.0.10.1/24 (default gateway cho client)
  • SYNC (vtnet2): Node chính: 172.16.99.1/30 | Node phụ: 172.16.99.2/30 (kết nối trực tiếp qua cáp DAC hoặc VLAN cô lập trên switch)

Bước 1: Thiết lập Interface SYNC và quy tắc lọc

Cắm một sợi cáp mạng trực tiếp hoặc cáp DAC 10GbE nối giữa vtnet2 trên cả hai thiết bị. Hãy giữ cho liên kết này hoàn toàn cách ly khỏi lưu lượng mạng văn phòng thông thường.

Trên cả hai thiết bị, truy cập vào Interfaces > Assignments, gán vtnet2 thành SYNC và đặt địa chỉ IPv4 tĩnh (172.16.99.1/30 và 172.16.99.2/30). Tiếp theo, điều hướng đến Firewall > Rules > SYNC trên cả hai node và cho phép lưu lượng của cụm cluster đi qua:

# Các quy tắc pass bắt buộc trên interface SYNC (cả hai node):
# Action: Pass | Direction: In | Interface: SYNC
# Quy tắc 1: Protocol CARP (giao thức IP 112) từ SYNC net đến any
# Quy tắc 2: Protocol PFSYNC (giao thức IP 240) từ SYNC net đến any
# Quy tắc 3: Protocol TCP, Cổng 443 (HTTPS) từ SYNC net đến địa chỉ SYNC

Bước 2: Cấu hình CARP VIP trên Node chính

Đăng nhập vào giao diện web của node chính (Primary) và mở Interfaces > Virtual IPs > Settings. Nhấp vào + để định nghĩa gateway cho LAN:

  • Type: CARP
  • Interface: LAN
  • IP Address: 10.0.10.1/24
  • Virtual IP Password: Nhập mật khẩu cụm có độ phức tạp cao (ví dụ: K8sSyncCluster#941!)
  • VHID Group: 1
  • Advertising Frequency: Base: 1, Skew: 0

Lặp lại bước này cho interface WAN. Gán VHID Group là 2, địa chỉ 198.51.100.1/24, Base 1 và Skew 0.

Bước 3: Cấu hình CARP VIP trên Node phụ

Chuyển sang giao diện web của node phụ (Secondary). Tạo các Virtual IP tương ứng, nhưng tăng giá trị advertisement skew lên để hạ cấp node này:

  • LAN VIP: 10.0.10.1/24 | VHID: 1 | Base: 1 | Skew: 100 | Mật khẩu giống hệt
  • WAN VIP: 198.51.100.1/24 | VHID: 2 | Base: 1 | Skew: 100 | Mật khẩu giống hệt

Với advertisement skew là 100, node phụ sẽ hoàn toàn giữ im lặng miễn là gói tin heartbeat của node chính (skew 0) vẫn gửi đến đều đặn mỗi giây.

Bước 4: Bật đồng bộ State (pfsync) và nhân bản cấu hình qua XMLRPC

Trên node chính, mở System > High Availability > Settings:

  • Tích chọn Synchronize States.
  • Synchronize Interface: Chọn SYNC.
  • pfsync IP: Đặt thành 172.16.99.2 (node phụ).
  • Synchronize Config to IP: Nhập 172.16.99.2.
  • Remote System User: root (hoặc tài khoản dịch vụ đồng bộ chuyên dụng).
  • Remote System Password: Nhập mật khẩu của node phụ.
  • Tích chọn các mục cần nhân bản: Firewall Rules, Aliases, Outbound NAT, Virtual IPs và DHCP Server.

Trên node phụ, cấu hình pfsync để lắng nghe từ node chính (172.16.99.1). Để trống hoàn toàn mục Synchronize Config to IP. Việc để trống này giúp ngăn chặn các vòng lặp cấu hình nguy hiểm giữa hai node.

Bước 5: Kiểm tra tình trạng cụm từ CLI

SSH vào cả hai thiết bị để kiểm tra trạng thái interface và số lượng bản ghi state được đồng bộ.

# Node chính - Xác minh trạng thái CARP master
root@opnsense-primary:~ # ifconfig vtnet1_vhid1
vtnet1_vhid1: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 10.0.10.1 netmask 0xffffff00
        carp: MASTER vhid 1 advbase 1 advskew 0

# Node chính - Kiểm tra dung lượng bảng state đang hoạt động
root@opnsense-primary:~ # pfctl -si | grep -i state
current entries                      1428
searches                           942810
inserts                            120491
removals                           119063

# Node phụ - Xác nhận trạng thái backup và số lượng state đã đồng bộ
root@opnsense-secondary:~ # ifconfig vtnet1_vhid1
vtnet1_vhid1: flags=49<UP,LOOPBACK,RUNNING> metric 0 mtu 1500
        inet 10.0.10.1 netmask 0xffffff00
        carp: BACKUP vhid 1 advbase 1 advskew 100

root@opnsense-secondary:~ # pfctl -si | grep "current entries"
current entries                      1428

Bước 6: Kiểm thử Failover trong thực tế

Thực hiện lệnh ping liên tục song song với một phiên SSH kết nối kéo dài từ một máy trạm trong mạng LAN (10.0.10.50) ra một địa chỉ đích bên ngoài:

ping -c 30 1.1.1.1

Trong khi lệnh ping đang chạy, hãy chủ động kích hoạt hạ cấp CARP thủ công trên tường lửa chính:

# Hạ cấp node chính bằng cách tăng bộ đếm carp demotion
root@opnsense-primary:~ # sysctl net.inet.carp.demotion=240

Kiểm tra kết quả ping trên máy trạm của bạn:

64 bytes from 1.1.1.1: icmp_seq=12 ttl=57 time=14.2 ms
64 bytes from 1.1.1.1: icmp_seq=13 ttl=57 time=14.8 ms
# Quá trình failover diễn ra tại đây
64 bytes from 1.1.1.1: icmp_seq=14 ttl=57 time=31.6 ms
64 bytes from 1.1.1.1: icmp_seq=15 ttl=57 time=14.3 ms

Quá trình failover diễn ra hoàn toàn liền mạch. Chúng tôi không ghi nhận bất kỳ gói tin nào bị rớt và chỉ có độ trễ tăng nhẹ thêm 17 ms trong lúc gói gratuitous ARP của node backup làm mới bảng CAM trên switch. Phiên SSH đang hoạt động vẫn phản hồi bình thường mà không cần đàm phán lại khóa TCP.

Để đưa node chính trở lại hoạt động, hãy đặt lại bộ đếm demotion:

root@opnsense-primary:~ # sysctl net.inet.carp.demotion=-240

Ba vấn đề cần lưu ý khi triển khai trong môi trường Production

Sáu tháng vận hành với mức lưu lượng duy trì liên tục 450 Mbps trên cụm này đã chỉ ra ba điểm đặc thù cực kỳ quan trọng:

  • Bảo mật cổng Switch và MAC Spoofing: Các mô hình ảo hóa (Proxmox VE, VMware ESXi hoặc Hyper-V) rất hay làm rớt các gói tin CARP. CARP liên kết với các địa chỉ MAC ảo theo định dạng 00:00:5e:00:01:VHID (ví dụ: 00:00:5e:00:01:01 cho VHID 1). Nếu vSwitch hoặc switch phần cứng được quản lý (managed switch) của bạn chặn các địa chỉ MAC chưa đăng ký, node phụ sẽ không bao giờ nhận được lưu lượng sau khi tiếp quản. Hãy bật tính năng MAC address spoofing và promiscuous mode trên các port group của bạn.
  • Ràng buộc Gateway cho Outbound NAT: Theo mặc định, OPNsense sẽ ánh xạ Outbound NAT vào địa chỉ IP vật lý của interface (198.51.100.2). Hãy chuyển Outbound NAT sang chế độ Hybrid hoặc Manual. Cập nhật mục tiêu của rule dịch địa chỉ thành WAN CARP VIP (198.51.100.1). Nếu bỏ qua bước này, các gói tin phản hồi sẽ cố gắng gửi về node chính đã chết sau khi failover xảy ra.
  • Đường truyền SYNC không được mã hóa: Giao thức pfsync truyền các gói tin state trên đường dây dưới dạng văn bản thuần túy (plaintext) mà không có xác thực. Bất kỳ ai bắt gói tin (sniff) trên liên kết đó đều có thể thấy các địa chỉ IP nội bộ đang hoạt động, cổng đích và siêu dữ liệu ánh xạ NAT. Luôn cô lập interface này trên một sợi cáp vật lý riêng biệt hoặc một VLAN nội bộ không định tuyến (non-routed VLAN).

Một khi CARP, pfsync và XMLRPC được tinh chỉnh đúng chuẩn, OPNsense sẽ mang lại độ tin cậy tương đương cấp độ nhà mạng viễn thông (carrier-grade). Bạn hoàn toàn có thể cập nhật bản vá firmware ngay giữa ngày làm việc mà không làm ngắt kết nối của bất kỳ người dùng nào.

Share: