Hướng dẫn cấu hình Port Knocking với Knockd trên Linux: Kỹ thuật ẩn cổng SSH thực chiến

Security tutorial - IT technology blog
Security tutorial - IT technology blog

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à eth0 hoặc ens3).
  • 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ờ rule ESTABLISHED,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.

Share: