Bối cảnh & Tại sao cần
2 giờ sáng, chuông báo động réo liên hồi. File /var/log/auth.log phình to cả trăm MB với hơn 60.000 request brute-force SSH từ đủ dải IP lạ. Lúc đó mình mới thấm: chỉ đổi port SSH và tắt mật khẩu là chưa đủ.
Đổi cổng 22 sang một cổng ngẫu nhiên như 2222 hay 58222 chỉ là giải pháp che mắt tạm thời (security through obscurity). Masscan chỉ mất chưa đầy 3 phút để quét sạch 65.535 cổng của bạn. Ngay sau đó, botnet lại đổ xô vào spam gói tin rác, gây lãng phí băng thông và phình log hệ thống.
Khóa IP bằng Firewall (UFW/Iptables)? Giải pháp này chỉ hiệu quả khi bạn làm việc cố định tại văn phòng có IP tĩnh. Nhưng thực tế anh em DevOps thường xuyên ôm laptop ra quán cà phê, đổi mạng liên tục hoặc phát 4G/5G từ điện thoại. IP nhảy liên tục khiến việc whitelist thủ công trở thành cực hình.
Đó là lý do Port Knocking với daemon Knockd ra đời. Giải pháp này kết hợp hoàn hảo giữa độ an toàn tuyệt đối và tính linh hoạt.
Cơ chế hoạt động rất trực quan. Cổng SSH luôn ở trạng thái DROP trên tường lửa. Khi hacker hay botnet quét qua, cổng này hoàn toàn tàng hình như thể không có dịch vụ nào đang chạy.
Trong khi đó, Knockd chạy ngầm để lắng nghe card mạng. Khi máy bạn gửi một chuỗi gói tin (knock sequence) đúng thứ tự cổng và giao thức đã định sẵn — hệt như gõ mật mã Morse lên cửa — Knockd sẽ gọi Iptables mở cổng SSH riêng cho IP của bạn. Sau một khoảng thời gian ngắn (ví dụ 30 giây), cửa sẽ tự động đóng lại.
Sau 6 tháng chạy thực tế trên cụm production, log brute-force SSH giảm hẳn về mức 0. Thao tác kết nối của mình cũng chỉ tốn thêm đúng 1 giây cho bước gõ cửa.
Cài đặt
Knockd là daemon cực nhẹ, chỉ chiếm khoảng 3-4MB RAM và có sẵn trên hầu hết các bản phân phối Linux phổ biến.
Đối với Ubuntu hoặc Debian, bạn cài đặt gói knockd cùng công cụ lưu rule tường lửa iptables-persistent:
sudo apt update
sudo apt install knockd iptables-persistent -y
Đối với CentOS, RHEL hoặc AlmaLinux, bạn cài qua kho EPEL:
sudo dnf install epel-release -y
sudo dnf install knock-server -y
Trên máy cá nhân (client) dùng để truy cập server, hãy cài client knock:
# Trên Ubuntu/Debian client
sudo apt install knockd -y
# Trên macOS (dùng Homebrew)
brew install knock
Cấu hình chi tiết
Quy trình triển khai gồm 3 bước: thiết lập tường lửa baseline, định nghĩa kịch bản gõ cửa trong Knockd và khởi chạy service.
1. Thiết lập Iptables chặn cổng SSH
Đầu tiên, bạn cần giữ nguyên phiên SSH hiện tại đang mở. Tuyệt đối không thoát terminal ra vội để tránh tự khóa chính mình nếu cấu hình nhầm.
# Cho phép loopback và các kết nối đã thiết lập từ trước tiếp tục chạy
sudo iptables -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j ACCEPT
sudo iptables -A INPUT -i lo -j ACCEPT
# Chặn toàn bộ kết nối mới vào cổng 22
sudo iptables -A INPUT -p tcp --dport 22 -j DROP
# Lưu lại rule để không mất sau khi reboot server
sudo netfilter-persistent save
2. Cấu hình file /etc/knockd.conf
Mở file cấu hình chính của Knockd:
sudo nano /etc/knockd.conf
Thay thế toàn bộ nội dung mẫu bằng kịch bản sau:
[options]
UseSyslog
Interface = eth0
[opencloseSSH]
sequence = 7412:tcp,8523:tcp,9631:tcp
seq_timeout = 10
tcpflags = syn
start_command = /sbin/iptables -I INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
cmd_timeout = 30
stop_command = /sbin/iptables -D INPUT -s %IP% -p tcp --dport 22 -j ACCEPT
Ý nghĩa các thông số kỹ thuật:
- Interface: Tên card mạng Internet của server (dùng lệnh
ip -br ađể kiểm tra, thường làeth0hoặcens3). - sequence: Chuỗi cổng cần gõ. Bạn nên tự đổi sang chuỗi cổng ngẫu nhiên của riêng mình, có thể kết hợp cả TCP lẫn UDP (ví dụ:
7412:udp,8523:tcp,9631:tcp). - seq_timeout: Thời gian tối đa (tính bằng giây) để hoàn tất chuỗi gõ cửa. Ở đây quy định trong vòng 10 giây.
- tcpflags = syn: Chỉ bắt gói tin TCP SYN nhằm tránh các gói tin rác trôi nổi kích hoạt nhầm.
- start_command: Lệnh thực thi khi gõ đúng. Biến
%IP%sẽ tự động được thế bằng địa chỉ IP nguồn của bạn. - cmd_timeout: Sau 30 giây kể từ khi mở cửa, Knockd sẽ tự chạy
stop_commandđể xóa rule mở cổng. Phiên SSH bạn đã kết nối thành công trước đó vẫn duy trì liên tục nhờ ruleESTABLISHED,RELATEDở trên.
3. Kích hoạt Knockd service
Trên Ubuntu, bạn mở file /etc/default/knockd để cho phép daemon khởi chạy:
sudo nano /etc/default/knockd
Chỉnh lại hai dòng cấu hình:
START_KNOCKD=1
KNOCKD_OPTS="-i eth0"
Sau đó khởi động lại service và kích hoạt tự chạy cùng hệ thống:
sudo systemctl restart knockd
sudo systemctl enable knockd
sudo systemctl status knockd
Kiểm tra & Vận hành
Bây giờ hãy chuyển sang máy client cá nhân để kiểm tra kết quả.
Kiểm tra cổng đóng ban đầu
Quét thử cổng 22 của server bằng Nmap:
nmap -Pn -p 22 198.51.100.24
Kết quả trả về sẽ là filtered. Nếu bạn thử gõ ssh [email protected], terminal sẽ treo và báo Operation timed out.
Gõ cửa và kết nối
Chạy lệnh gõ cửa theo đúng chuỗi cổng đã đặt:
knock 198.51.100.24 7412:tcp 8523:tcp 9631:tcp
Lệnh chạy xong trong tích tắc (khoảng 0.3 giây). Bạn kết nối SSH ngay sau đó:
ssh [email protected]
Kết nối thành công ngay lập tức. Sau 30 giây, tường lửa tự động đóng cổng lại, nhưng phiên làm việc của bạn vẫn thông suốt, không hề bị ngắt kết nối.
Tự động hóa với ~/.ssh/config
Gõ lệnh knock thủ công mỗi lần kết nối rất mất thời gian. Bạn có thể gắn thẳng vào file ~/.ssh/config trên máy cá nhân:
Host my-server
HostName 198.51.100.24
User ubuntu
IdentityFile ~/.ssh/id_rsa
ProxyCommand knock %h 7412 8523 9631 && sleep 1 && nc %h %p
Từ giờ bạn chỉ cần gõ ssh my-server. Máy client sẽ tự động gửi chuỗi knock, đợi 1 giây rồi tự kết nối SSH.
Giám sát log Knockd trên server
Khi cần kiểm tra trạng thái hoặc debug trường hợp gõ cửa không mở, hãy xem log qua systemd journal:
sudo journalctl -u knockd -f
Một chuỗi knock hợp lệ sẽ hiển thị qua các bước rõ ràng:
knockd[1234]: 203.0.113.50: opencloseSSH: Stage 1
knockd[1234]: 203.0.113.50: opencloseSSH: Stage 2
knockd[1234]: 203.0.113.50: opencloseSSH: Stage 3
knockd[1234]: 203.0.113.50: opencloseSSH: OPEN SESAME
knockd[1234]: opencloseSSH: running command: /sbin/iptables -I INPUT -s 203.0.113.50 -p tcp --dport 22 -j ACCEPT
knockd[1234]: 203.0.113.50: opencloseSSH: command timeout
knockd[1234]: opencloseSSH: running command: /sbin/iptables -D INPUT -s 203.0.113.50 -p tcp --dport 22 -j ACCEPT
Trường hợp log bị đứng ở Stage 1 hoặc Stage 2 mà không ra OPEN SESAME, nguyên nhân thường do mạng Wi-Fi công cộng hoặc proxy trung gian làm thất lạc gói tin TCP SYN. Khi đó, bạn nên chuyển sang chuỗi UDP hoặc tăng seq_timeout lên 15 giây để đường truyền ổn định hơn.

