Một firewall tốt không bắt đầu bằng thật nhiều luật, mà bằng một mô hình rõ ràng: máy chủ được phép nhận dịch vụ nào, từ đâu, và kết nối nào đã được kernel theo dõi. Với nftables, một bảng inet nhỏ có thể lọc đồng thời IPv4 và IPv6, dùng connection tracking để giữ lưu lượng hợp lệ, rồi mặc định từ chối phần còn lại.
Bài viết xây một stateful firewall cho máy chủ Linux độc lập, có SSH quản trị và web HTTP/HTTPS. Cấu hình, cú pháp và hành vi được đối chiếu với tài liệu chính thức của dự án về ruleset máy chủ, connection tracking và nft(8).
1. Chốt phạm vi trước khi viết luật
Ví dụ này dành cho một host trực tiếp nhận traffic, không phải router, NAT gateway hay Kubernetes node. Chính sách đầu vào là deny-by-default; đầu ra tạm thời được phép. Các dịch vụ công khai là TCP 80/443, còn SSH chỉ đến từ mạng quản trị.
Trước khi thay đổi, hãy lập inventory bằng ss -lntup, xác định cổng SSH thật, nguồn quản trị, IPv6, VPN và mọi agent giám sát. Chạy nft list ruleset để phát hiện firewalld, Docker, libvirt hoặc phần mềm khác đang sở hữu rule. Không được coi firewall là file cấu hình riêng lẻ nếu nhiều hệ thống cùng thay đổi Netfilter.
2. Ruleset nền tảng
#!/usr/sbin/nft -f
flush ruleset
define SSH_PORT = 22
define WEB_PORTS = { 80, 443 }
table inet host_firewall {
set admin_ipv4 {
type ipv4_addr
flags interval
elements = { 203.0.113.0/24 }
}
chain input {
type filter hook input priority filter; policy drop;
ct state invalid counter drop
ct state established,related counter accept
iifname "lo" counter accept
meta l4proto ipv6-icmp counter accept
ip protocol icmp counter accept
ip saddr @admin_ipv4 tcp dport $SSH_PORT ct state new counter accept
tcp dport $WEB_PORTS ct state new counter accept
limit rate 5/second burst 10 packets counter \
log prefix "nft-input-drop " level warning
counter drop
}
chain forward {
type filter hook forward priority filter; policy drop;
}
chain output {
type filter hook output priority filter; policy accept;
}
}
flush ruleset chỉ phù hợp khi file này là chủ sở hữu duy nhất của firewall. Nó xóa cả luật do container runtime hoặc firewall manager tạo. Nếu cần cùng tồn tại, hãy quản lý riêng bảng inet host_firewall, phối hợp lifecycle với các owner khác và tuyệt đối không global-flush.
3. Vì sao thứ tự luật quan trọng?
Packet đi từ trên xuống trong chain. Trạng thái invalid bị loại trước; established,related giữ các kết nối đã được chấp nhận và luồng phụ liên quan. Loopback được phép cho giao tiếp nội bộ. Chỉ sau đó firewall mới xét kết nối new đến SSH hoặc web.
Policy drop là lưới an toàn nếu packet không khớp luật nào. Tuy vậy, một verdict accept trong base chain không nhất thiết kết thúc toàn bộ quá trình nếu còn base chain khác ở hook sau hoặc cùng hook với priority khác. Vì thế cần kiểm kê toàn bộ ruleset, không chỉ bảng của mình.
4. Đừng làm hỏng IPv6
Family inet giúp dùng chung chain cho IPv4 và IPv6, nhưng expression ip và ip6 vẫn có kiểu địa chỉ riêng. Named set ipv4_addr ở trên không chứa được IPv6; nếu quản trị qua IPv6, hãy tạo thêm set ipv6_addr và luật ip6 saddr.
Không chặn mù ICMPv6: Neighbor Discovery, router discovery và Path MTU Discovery phụ thuộc vào nó. Baseline cho host thường chấp nhận ipv6-icmp; việc thu hẹp type chỉ nên làm khi đội vận hành hiểu đầy đủ các dependency và đã test dual-stack.
5. Set làm chính sách dễ đọc và dễ đổi
Named set tách dữ liệu như CIDR quản trị khỏi logic lọc. Cờ interval cho phép biểu diễn prefix/range hiệu quả. Khi thêm hoặc xóa một địa chỉ, automation có thể cập nhật phần tử thay vì dựng lại hàng loạt luật:
sudo nft add element inet host_firewall admin_ipv4 \
{ 198.51.100.24 }
sudo nft delete element inet host_firewall admin_ipv4 \
{ 198.51.100.24 }
Đây là thay đổi runtime; nó mất sau reboot nếu nguồn cấu hình khai báo không được cập nhật. Hãy coi repository/config management là source of truth và mọi sửa trực tiếp chỉ là biện pháp khẩn cấp có thời hạn.
6. Triển khai mà không tự khóa SSH
- Giữ nguyên phiên SSH đang hoạt động và chuẩn bị console ngoài băng nếu nhà cung cấp hỗ trợ.
- Lưu ruleset hiện tại bằng
nft list ruleset > /root/nftables.last-known-good.nftvới quyền truy cập chặt. - Xác nhận IP nguồn mà server thực sự nhìn thấy, cổng SSH và cả đường IPv4/IPv6.
- Chuẩn bị rollback có hẹn giờ bằng công cụ vận hành sẵn có; chỉ hủy lịch sau khi một phiên SSH mới kết nối thành công.
- Kiểm tra cú pháp rồi nạp nguyên file theo một transaction.
sudo nft -c -f /etc/nftables.conf
sudo nft -f /etc/nftables.conf
sudo nft list ruleset
ssh -p 22 admin@server-from-a-new-terminal
Tùy chọn -c chỉ kiểm tra, không áp dụng. Khi đọc file với -f, nft gửi batch để thay đổi ruleset theo transaction nguyên tử: nếu một lệnh lỗi, batch không nên để lại trạng thái nửa cũ nửa mới. Đừng thay nó bằng một chuỗi shell gồm nhiều lệnh nft add rule độc lập.
7. Logging phải có giới hạn
Luật log cuối chain được rate-limit để tránh một đợt scan làm ngập journal. counter vẫn đếm packet/byte, còn rule drop cuối cùng bảo đảm packet vượt giới hạn log vẫn bị chặn.
Rate limit log không phải cơ chế chống brute-force SSH. Authentication bằng key, tắt đăng nhập root/password khi phù hợp, MFA hoặc VPN, và công cụ ban động mới giải quyết lớp đó. Log prefix không nên chứa dữ liệu nhạy cảm; retention và forwarding cũng phải có hạn mức.
8. Chính sách output nên là dự án riêng
Đổi output sang default-drop ngay từ đầu thường làm hỏng DNS, NTP, package update, certificate renewal, telemetry và backup. Baseline giữ policy accept để giảm blast radius. Nếu cần egress control, hãy inventory destination/protocol, thiết kế DNS và endpoint động, đo traffic thực tế rồi rollout theo từng dịch vụ.
Stateful không có nghĩa mọi reply tự động được phép ở mọi hướng. Chain output vẫn có chính sách riêng; container, namespace và bridge còn đưa packet qua hook khác.
9. Container và firewall manager là điểm va chạm lớn
Docker, Kubernetes, libvirt và firewalld có thể tạo table/chain của chúng. Global flush có thể làm mất publish port, NAT hoặc isolation; ngược lại, một chain của runtime có thể thay đổi kết quả mà bạn không thấy khi chỉ đọc file host.
Chọn một mô hình sở hữu rõ ràng: firewall manager quản lý toàn bộ, hoặc automation nftables quản lý bảng riêng có contract với runtime. Kiểm tra backend iptables-nft và iptables-legacy trong quá trình migration; không chỉnh hai backend rồi giả định chúng chia sẻ cùng state.
10. Lưu cấu hình qua reboot
Trên nhiều hệ Debian/Ubuntu, dịch vụ nftables.service đọc /etc/nftables.conf. Đường dẫn và cơ chế có thể khác theo distribution, nên kiểm tra unit thật:
systemctl cat nftables.service
sudo systemctl enable nftables.service
sudo systemctl restart nftables.service
systemctl status nftables.service
Test reboot trên staging hoặc cửa sổ bảo trì. Runtime đúng nhưng boot fail vẫn là một deployment lỗi; ngược lại, file đúng nhưng chưa được service nạp cũng tạo cảm giác an toàn giả.
11. Quan sát và debug có kiểm soát
sudo nft list ruleset
sudo nft list chain inet host_firewall input
sudo journalctl -k -g nft-input-drop --since today
sudo ss -lntup
Counter trả lời rule nào đang khớp. Với case khó, nftables hỗ trợ packet tracing: thêm một rule thật hẹp đặt meta nftrace set 1, chạy nft monitor trace, tái hiện một flow rồi xóa rule debug. Không bật trace rộng trên host bận vì output có thể rất lớn.
Test từ một máy bên ngoài: 80/443 phải mở, SSH chỉ mở từ mạng quản trị, một cổng đóng phải timeout/reject đúng kỳ vọng. Test localhost không chứng minh đường ingress công cộng hoạt động.
12. Rollback và thay đổi hằng ngày
Mỗi thay đổi cần owner, ticket, snapshot trước đó, cửa sổ quan sát và tiêu chí rollback. Rollback bằng một ruleset đã biết tốt đáng tin hơn cố gắng đảo từng command. Sau rollout, đối chiếu counter, log, health check ứng dụng và một kết nối quản trị mới trước khi hủy rollback timer.
Luật tạm thời phải có comment hoặc metadata ngoài hệ thống, ngày hết hạn và người chịu trách nhiệm. Một allow rule khẩn cấp không có lifecycle sẽ trở thành lỗ hổng vĩnh viễn.
Checklist production
- Đã inventory listener, SSH source/port, VPN, IPv6, container và firewall manager.
- Quyền sở hữu ruleset rõ ràng; không dùng
flush rulesetkhi có owner khác. invalidbị drop;established,related, loopback và ICMP cần thiết được xử lý.- Inbound dùng default-drop; từng dịch vụ mới được allow có chủ đích.
- Có console/phiên SSH cũ, bản known-good và rollback hẹn giờ.
- Đã chạy
nft -c -ftrước khi load transaction. - Test bằng phiên SSH mới và máy ngoài mạng cho cả IPv4/IPv6.
- Logging có rate limit; counters và cảnh báo được theo dõi.
- Cấu hình nguồn và runtime đồng bộ, đã test cơ chế boot persistence.
- Mọi ngoại lệ có owner và ngày hết hạn.
Kết luận
Một nftables firewall production đáng tin không cần dài: stateful rule đúng thứ tự, service allowlist, default-drop và xử lý IPv6 chuẩn đã tạo nền tảng tốt. Phần khó nằm ở ownership, rollout và quan sát. Khi toàn bộ thay đổi đi qua file được kiểm tra, nạp theo transaction, có rollback hẹn giờ và được test từ bên ngoài, firewall trở thành một policy có thể vận hành thay vì một tập lệnh dễ tự khóa máy chủ.




Chưa có bình luận. Hãy là người đầu tiên chia sẻ ý kiến.