Một gateway công cộng đã chạy WireGuard trên UDP 51820, SSH trên 22 và một ứng dụng phải truy cập được từ internet. Quy tắc hấp dẫn chuyển tiếp mọi cổng cho peer và tuyên bố xong việc. Trên một gateway WireGuard, quy tắc đó có thể bắt lấy chính phần vận chuyển của tunnel và khóa bạn ra khỏi máy đang kết thúc nó. Công bố dịch vụ là một quyết định định tuyến với ngoại lệ dành cho mặt phẳng điều khiển, không phải một dòng DNAT.

Cổng vào công cộng hay cổng vào qua tunnel: chọn một

Công bố một dịch vụ tạo ra một điểm vào mới trên internet. Nó không giống với việc cấp tư cách thành viên VPN cho một peer, vì người truy cập không bao giờ vào tunnel và gateway trở thành bộ mặt công cộng của backend. Sự khác biệt đó quyết định đối tượng của quy tắc và chứng chỉ của nó.

Giao diện quản trị hiếm khi thuộc về vị trí đó. Một trang quản trị được các client VPN có quyền truy cập giữ bề mặt tấn công bên trong tunnel và tránh phơi bày biểu mẫu đăng nhập cho việc quét tùy tiện. Các endpoint ứng dụng công cộng vẫn cần chứng chỉ TLS riêng, xác thực và giới hạn tốc độ; chặng WireGuard được mã hóa không bảo vệ đoạn của người truy cập tới gateway.

Nếu dịch vụ thực sự phải công khai, hãy ghi lại tên máy chủ, chứng chỉ bao phủ nó và các dải người truy cập được phép tới nó. Ba dữ kiện đó về sau quyết định hình dạng quy tắc và chính sách lọc. Mọi thứ ngoài chúng là mở rộng phạm vi trên một listener công cộng.

Một cổng vào, một backend ra

Dùng một cổng công cộng và một dịch vụ backend. Trong ví dụ này eth0 mang địa chỉ công cộng 198.51.100.20, địa chỉ tunnel của gateway là 10.200.0.1, và peer chạy ứng dụng trên 10.200.0.7. Cổng công cộng TCP 9443 được ánh xạ tới TCP 8443 của peer:

iptables -t nat -A PREROUTING -i eth0 -d 198.51.100.20 -p tcp --dport 9443 -j DNAT --to-destination 10.200.0.7:8443
iptables -t nat -A POSTROUTING -o wg0 -d 10.200.0.7 -p tcp --dport 8443 -m conntrack --ctorigdst 198.51.100.20 --ctorigdstport 9443 -j SNAT --to-source 10.200.0.1

Quy tắc SNAT khớp với backend đã dịch và đích công cộng ban đầu, nên một kết nối khác tới cùng dịch vụ backend nằm ngoài ánh xạ này. Nó cũng giấu địa chỉ của người truy cập với peer, và đó là sự đánh đổi khiến đường trả về được định tuyến mà vẫn giữ nguồn trở thành một thiết kế riêng. Tài liệu tham chiếu phần mở rộng iptables ghi lại cả hai đích và các tùy chọn khớp của chúng.

Việc chuyển tiếp vẫn phải được bật, và chuỗi lọc cần một sự cho phép cho đích và cổng đã dịch cùng các phản hồi đã thiết lập. Chuỗi FORWARD thấy đích đã dịch sau DNAT, nên một quy tắc viết theo địa chỉ công cộng không khớp với gói được chuyển tiếp. Hãy viết sự cho phép theo bộ tuple backend, không phải theo bộ công cộng.

Peer phải chấp nhận kết nối dịch vụ từ địa chỉ tunnel của gateway và gửi phản hồi trở lại qua tunnel. AllowedIPs của nó phải cho phép nguồn mà nó thực sự nhận, mà dưới phép dịch nguồn chính là địa chỉ tunnel của gateway, và một mục 0.0.0.0/0 rộng trên mọi peer là không cần thiết cho thiết kế này. Thứ làm rơi lưu lượng trả về là một peer có danh sách bỏ sót địa chỉ đó, hoặc một thiết kế giữ nguyên nguồn chuyển tiếp địa chỉ của chính người truy cập, nên hãy kiểm tra nguồn mà peer thực sự thấy, không phải nguồn trong quy tắc của bạn.

Giữ listener của chính gateway ra ngoài quy tắc

Thay điều kiện khớp cổng bằng một quy tắc bao mọi đích TCP và UDP, và socket WireGuard của chính gateway rơi vào trong đó. Việc dịch đích diễn ra trước khi máy quyết định một gói là cục bộ, nên UDP 51820 có thể kết thúc ở peer thay vì ở tiến trình đang giữ mọi kết nối peer. Quy tắc nạp thành công và tunnel chết, một lỗi khó đọc từ phía peer.

SSH, các agent giám sát và bất kỳ dịch vụ nào khác chạy trên gateway đều có cùng mức phơi bày. Một quy tắc chuyển tiếp mọi thứ không phân biệt mặt phẳng điều khiển với ứng dụng đã công bố, và lần khởi động lại đầu tiên sau thay đổi là lúc việc khóa ngoài trở nên rõ ràng. Quy tắc bắt tất cả không cảnh báo về dịch vụ mà nó âm thầm chiếm lấy. Bạn phát hiện ra khi kết nối tiếp theo thất bại.

Nếu chuyển tiếp rộng thực sự cần thiết, hãy dành trước các cổng điều khiển trước quy tắc bắt tất cả hoặc dùng một địa chỉ công cộng riêng cho việc công bố. Lựa chọn thứ hai sạch hơn vì địa chỉ điều khiển giữ chính sách riêng, nhưng nhà cung cấp phải cấp địa chỉ đó; thêm một bản ghi DNS không cấp phát được địa chỉ nào.

Chuyển tiếp TCP và UDP rộng cũng không phải mọi giao thức. ICMP, IPv6, phản hồi path-MTU và phần vận chuyển VPN bên ngoài cần chính sách riêng, và một quy tắc bao TCP và UDP để những trường hợp đó lại cho chuỗi mặc định.

Chọn mô hình trước khi viết quy tắc

Bốn hình dạng bao phủ phần lớn các lần công bố từ một gateway, và lựa chọn phụ thuộc vào số dịch vụ bạn chạy và mức rủi ro mặt phẳng điều khiển bạn chịu được. Bảng dưới đây xếp chúng từ hẹp nhất đến rộng nhất.

ModelWhat it protectsCostUse when
Narrow port forwardEvery other listener, including the VPNOne rule per serviceFew services, stable ports
Catch-all with reserved portsPorts named in the exception listRule order becomes criticalMany services and disciplined review
Separate public addressControl address fully isolatedProvider must supply the addressHigh-value publication
VPN-only accessNo public entry at allVisitors need the tunnelAdmin interfaces and internal tools

Hãy bắt đầu với mô hình hẹp kể cả khi bạn dự kiến có thêm dịch vụ về sau. Nó dễ kiểm toán nhất, và chuyển một tập quy tắc hẹp thành một quy tắc bắt tất cả đã được xem xét thì đơn giản hơn là phát hiện ra quy tắc rộng đã bắt mất listener nào. Dù chọn mô hình nào, hãy giữ quy tắc ở người sở hữu tường lửa. Việc áp các dòng iptables bên cạnh một cấu hình UFW hoặc nftables cũng quản lý chính các chuỗi đó sẽ tạo ra một chính sách thay đổi tùy theo thứ tự khởi động.

Chứng minh cả việc công bố lẫn đường điều khiển

Kiểm tra từ một client bên ngoài được cấp quyền bằng tên máy chủ đã được phê duyệt và một chứng chỉ hợp lệ cho nó. Xác nhận backend nào đã trả lời, rồi kiểm tra rằng các cổng công cộng không liên quan vẫn bị từ chối. Một lần kiểm tra chứng chỉ bị tắt không phải là bài kiểm tra HTTPS đã đạt, và một kết nối tới sai backend còn tệ hơn một kết nối thất bại.

Sau đó hãy xác minh chính gateway: kết nối một peer WireGuard, mở một phiên SSH và xác nhận rằng giám sát vẫn báo cáo. Dịch vụ đã công bố có thể hoạt động trong khi mặt phẳng điều khiển bị hỏng, nên cả hai lần kiểm tra thuộc cùng một cửa sổ thay đổi. Khởi động lại một lần để chứng minh các quy tắc được áp lại theo thứ tự mong đợi, rồi gỡ bỏ việc công bố và xác nhận rằng việc gỡ bỏ thực sự khớp với việc thêm vào. Một tập lớn các phần thêm vào lúc khởi động cùng việc dọn dẹp không đầy đủ là cách một bài kiểm tra tạm thời trở thành một lỗ hổng vĩnh viễn.

Bài viết liên quan