Khi chúng ta vận hành hệ thống, đặc biệt là các môi trường trên cloud, việc để server production, database hay các tài nguyên nhạy cảm có thể truy cập thẳng từ internet là điều tối kỵ chắc mọi người làm lâu năm đã biết rồi.
Chúng ta luôn cần gateway, relay point được kiểm soát chặt chẽ. Nó thường được gọi là Bastion Host hoặc Jumpbox. Bastion Host là con server duy nhất trong một private network mà bạn cho phép truy cập từ bên ngoài, thường là qua SSH. Từ con bastion này, admin mới có thể jump tiếp vào các server nội bộ khác như web-app, database…

Các cấp độ bảo mật Bastion Host
Trước khi vào chi tiết, dành cho bạn nào chưa vận hành thực tế trên production biết các cấp độ (cái này mỗi người chia một kiểu nên không có chuẩn đâu) tham khảo và cơ bản là hiểu bản chất các mức độ nguy hiểm và dễ dàng tấn công của các cấp độ nhé.
Cấp độ 1: Bastion truyền thống (mở SSH, harden kỹ)
Đây là cách tôi sẽ hướng dẫn trong bài này:
- Bastion nằm ở subnet public.
- Có public IP.
- Mở port SSH (thường là 22 hoặc 2222).
- Dùng key-based auth, fail2ban, firewall hạn chế IP.
Đặc điểm:
- Ưu điểm: đơn giản, dễ hiểu, deploy nhanh.
- Nhược điểm: vẫn có nguy cơ bị scan, brute-force, và cần bảo trì (rotate key, patch OS, giám sát log, v.v).
Với mô hình này, bạn nên chỉ cho phép SSH từ một số IP cố định (VPN office, IP admin) bằng security group hoặc firewall rules. Nếu bạn có nhiều admin, việc quản lý IP cố định bắt đầu khó đó là lúc nên chuyển cấp độ 2.
Cấp độ 2: Bastion qua VPN hoặc IAP (không mở SSH public)
Ở cấp độ này, bastion không còn port SSH public nữa, chỉ cho phép kết nối từ mạng nội bộ (VPN hoặc Cloud Proxy).
1. Bastion + WireGuard / OpenVPN
- Bạn dựng một con VPN gateway riêng (VD: WireGuard).
- Admin phải kết nối VPN => nhận IP nội bộ (10.x.x.x) => từ đó mới SSH vào bastion.
- Bastion nằm trong subnet private, chỉ mở SSH cho IP nội bộ VPN.
Điều này loại bỏ hoàn toàn scan từ Internet, và giúp bạn audit VPN connection dễ hơn nhiều. Một bản WireGuard cấu hình nhỏ, 5-10 user, chi phí gần như bằng 0, và setup nhanh hơn cả fail2ban.
2. Bastion qua Cloud IAP / Identity-Aware Proxy
Nếu bạn dùng cloud, có sẵn giải pháp an toàn hơn:
- AWS Systems Manager (Session Manager):
Không cần mở port SSH, không cần public IP.
Admin dùng
aws ssm start-session --target instance-id
, mọi traffic đi qua AWS API, có audit log sẵn. - GCP IAP SSH: Google tự tạo tunnel an toàn qua OAuth token, chỉ người được cấp IAM role mới vào được.
- Azure Bastion: Giao diện web-based RDP/SSH trực tiếp trên Azure Portal, không hở port.
Ưu điểm của mô hình này:
- Không hề có port 22 nào mở ra Internet.
- Log truy cập (ai vào, lúc nào, máy nào) có sẵn ở control plane (AWS CloudTrail, GCP Audit Logs).
- Dễ dàng integrate với SSO, MFA.
Thực tế, hầu hết công ty lớn đã bỏ hoàn toàn kiểu bastion “mở SSH public” để tránh audit rườm rà và risk quản lý key.
Cấp độ 3: Bastion Zero-Trust (Không SSH, không VPN)
Đây là level nâng cao hơn, thường thấy ở hệ thống có compliance (ISO 27001, SOC2).
Mô hình này thay vì SSH, bạn truy cập qua agent + ephemeral session:
- Mỗi server chạy một agent (VD: Teleport, Tailscale SSH, HashiCorp Boundary, StrongDM…).
- Khi admin muốn SSH vào server, họ phải xác thực qua SSO (Google Workspace, Okta…) => hệ thống cấp tạm session (valid 10–15 phút).
- Mọi session được ghi log, replay được.
- Không có static SSH key, không có port mở.
Ví dụ: Teleport là công cụ nổi tiếng kiểu này. Nó tạo “bastion cluster” qua TLS + certificate-based access, tất cả session đều có audit trail (kể cả command replay).
Tailscale SSH cũng rất đơn giản:
Chỉ cần cài Tailscale agent, bật SSH, bạn SSH qua identity (ssh user@hostname.tailnet
) không mở port, không VPN, xác thực bằng SSO.
Tóm lại
Mức độ | SSH public | Bảo mật | Triển khai | Ghi log / audit |
---|---|---|---|---|
1. Bastion truyền thống | Có (hạn chế IP, harden) | Trung bình | Dễ | Tự cấu hình |
2. Bastion qua VPN/IAP | Không public | Cao | Trung bình | Có log qua VPN/IAM |
3. Zero-Trust (Teleport, Tailscale, Boundary) | Không cần SSH port | Rất cao | Phức tạp hơn | Tự động audit, replay |
Nếu bạn đang làm môi trường thực tế thì
- Nếu hạ tầng on-prem hoặc hybrid, chọn VPN + Bastion private subnet là hợp lý nhất.
- Nếu thuần cloud, dùng AWS SSM Session Manager là hướng hiện đại, không phải mở SSH.
- Nếu bạn muốn làm bài viết nâng cao cho devops.vn, tôi có thể viết tiếp bài “Không cần mở SSH: 3 cách hiện đại để vận hành Bastion Host an toàn hơn”, mở rộng trực tiếp từ bài này.
Các bước làm ở cấp độ 1
Trong bài này như tôi nói tôi sẽ hướng dẫn cấp độ 1 và tôi dùng RHEL/CentOS/Fedora là distribution của Linux.
Luôn cập nhật hệ thống
Nhiều người cài xong bastion là để yên luôn vài tháng, đến khi bị quét exploit kernel hoặc log4j kiểu cũ mới tá hỏa. Bastion là cửa ngõ, nên bất kỳ CVE nào bị khai thác qua SSH, PAM, systemd… đều có thể là đường vào đầu tiên.
Bạn phải đảm bảo hệ điều hành và các package được patch lỗi bảo mật mới nhất.
#!/bin/bash
# Script cập nhật hệ thống cho RHEL/Fedora
echo "Bắt đầu cập nhật package lists và nâng cấp hệ thống..."
# -y để tự động đồng ý
sudo dnf upgrade -y
echo "Dọn dẹp các package không còn cần thiết..."
sudo dnf autoremove -y
echo "Hệ thống đã được cập nhật và dọn dẹp."
Thực tế trong các môi trường cloud, nhiều team để cron tự update (vd dnf-automatic
), nhưng nên kiểm soát bằng hệ thống quản lý trung tâm như Ansible/AWS SSM để đảm bảo version đồng nhất. Bastion mà lỗi libssl khác version với các node khác đôi khi còn không SSH được nội bộ.
Configuring dịch vụ SSH
Đây là bước quan trọng vì SSH là cổng vào duy nhất. Chúng ta cần tắt hết các tính năng không an toàn.
- Tắt login bằng password, chỉ dùng SSH key.
- Tắt login của user
root
. - Đổi port SSH từ 22 sang một port khác (ví dụ: 2222). Việc này không giúp bạn chống lại hacker có chủ đích, nhưng nó giảm tải đáng kể các bot quét tự động.
- Nên tạo user riêng cho từng admin (ví dụ:
devops_admin1
,devops_admin2
) và dùngsudo
thay vì share chung key.
#!/bin/bash
# Đường dẫn file config
SSH_CONFIG_FILE="/etc/ssh/sshd_config"
echo "Thay đổi Port SSH sang 2222..."
# Tìm dòng Port 22 (kể cả có dấu #) và đổi thành Port 2222
sudo sed -i 's/^#\?Port 22/Port 2222/' $SSH_CONFIG_FILE
echo "Tắt PasswordAuthentication..."
sudo sed -i 's/^#\?PasswordAuthentication yes/PasswordAuthentication no/' $SSH_CONFIG_FILE
echo "Bật PubkeyAuthentication..."
sudo sed -i 's/^#\?PubkeyAuthentication no/PubkeyAuthentication yes/' $SSH_CONFIG_FILE
echo "Cấm PermitRootLogin..."
# Đổi bất cứ giá trị nào của PermitRootLogin thành no
sudo sed -i 's/^#\?PermitRootLogin .*/PermitRootLogin no/' $SSH_CONFIG_FILE
echo "Khởi động lại dịch vụ SSH..."
# Trên RHEL/CentOS dùng sshd, Ubuntu/Debian dùng ssh
sudo systemctl restart sshd
echo "Hardening SSH hoàn tất."
echo "QUAN TRỌNG: Hãy mở port 2222 trên firewall trước khi bạn thoát session này."
Thực tế ở môi trường production, bạn nên test script này trước trên một node staging. Tôi từng thấy vài team áp dụng lệnh sed
xong restart là SSH die luôn vì config trùng dòng hoặc file bị comment nhiều lớp. Kiểm tra lại bằng sshd -t
trước khi restart là cách an toàn nhất.
Chống Brute-force với Fail2ban
Sau khi đổi port, có thể vẫn có kẻ tìm ra port mới và thử brute-force. Fail2ban sẽ theo dõi log và tự động ban IP của kẻ tấn công.
Một ví dụ thực tế: có một lần (công ty cũ lúc đó khá thiếu rule cụ thể) tôi quên đổi port SSH của bastion trên AWS. Trong vòng 1 tiếng đã có gần 15.000 lần thử login từ hơn 900 IP khác nhau, toàn botnet tự động. Sau đó cài Fail2ban là log sạch hẳn.
#!/bin/bash
# Cài đặt Fail2ban trên RHEL/CentOS
echo "Cài đặt Fail2ban..."
sudo dnf install fail2ban -y
# Tạo file jail.local tùy chỉnh
echo "Tạo file /etc/fail2ban/jail.local..."
cat <<EOF | sudo tee /etc/fail2ban/jail.local
[sshd]
enabled = true
port = 2222
filter = sshd
logpath = /var/log/secure
maxretry = 5
bantime = 600
findtime = 600
EOF
echo "Khởi động và bật fail2ban..."
sudo systemctl enable --now fail2ban
echo "Kiểm tra trạng thái..."
sudo fail2ban-client status sshd
Một số kinh nghiệm nhỏ khi dùng Bastion thực tế
- Nên bật auditd hoặc chuyển toàn bộ log SSH sang một hệ thống logging riêng như ELK hoặc Vector. Mọi hành động trên bastion đều nên có trace.
- Nếu bạn dùng cloud (AWS, GCP, Azure), nên cân nhắc dùng Session Manager, IAP SSH hoặc Azure Bastion để loại bỏ hẳn việc mở port SSH ra internet.
- Bastion không phải để dùng cho mọi người SSH lung tung vào bạn nên quy định rõ “ai được vào, làm gì, log ở đâu”, và kiểm soát key lifecycle (thay key định kỳ, revoke khi offboard nhân sự).
- Luôn nhớ: Bastion mà bị compromise thì coi như toàn bộ private subnet lộ (cái này căng đấy).
Xây dựng một bastion host tốt là bước không thể thiếu để bảo vệ hạ tầng. Nó là tuyến phòng thủ đầu tiên và quan trọng nhất của bạn. Đừng chỉ dựng một con VM rồi mở port 22 là xong. Những script tôi chia sẻ là những bước cơ bản, bạn nên điều chỉnh cho phù hợp với môi trường và các chính sách bảo mật của công ty mình là sẽ giảm đi được kha khá.
Tôi nghĩ cũng nói khá rõ ràng về các cấp độ và cách làm nếu bạn cần các chi tiết hơn ở cấp độ 2 và cấp độ 3 thì có thể yêu cầu tôi sẽ lên bài chi tiết tiếp nhé.