Hardening SSH Server Linux: checklist bảo mật thực chiến cho SysAdmin

Hardening SSH server Linux là một trong những việc đầu tiên SysAdmin nên làm trước khi đưa máy chủ ra Internet. SSH là cửa ngõ quản trị production: chỉ cần cấu hình lỏng, mật khẩu yếu hoặc không có lớp chống brute force, toàn bộ hạ tầng phía sau có thể bị đe dọa.

Bài này đi theo hướng thực chiến: có bối cảnh lab/production, giải thích vì sao cần làm, lệnh cấu hình cụ thể, output mẫu, lỗi thường gặp, checklist nghiệm thu và bài tập cuối bài. Mục tiêu không phải “tắt hết cho an toàn”, mà là tạo một cấu hình SSH cân bằng giữa bảo mật, khả năng vận hành và khả năng khôi phục khi có sự cố.

1. Bối cảnh production: vì sao cần hardening SSH server Linux?

Trong môi trường doanh nghiệp nhỏ, VPS, máy chủ web hoặc node chạy dịch vụ nội bộ, SSH thường được mở để quản trị từ xa. Các bot quét Internet liên tục thử đăng nhập bằng tài khoản phổ biến như root, admin, ubuntu. Nếu server vẫn cho đăng nhập bằng mật khẩu, không giới hạn IP, không có rate limit và không có audit log, rủi ro tăng rất nhanh.

Một quy trình hardening SSH server Linux tốt thường giải quyết 5 nhóm vấn đề:

  • Giảm bề mặt tấn công: không cho root login trực tiếp, hạn chế user được phép SSH.
  • Tăng độ mạnh xác thực: ưu tiên SSH key, tắt password nếu có thể.
  • Giảm brute force: firewall, Fail2ban hoặc cơ chế rate limit tương đương.
  • Dễ audit: log rõ ai đăng nhập, từ đâu, thời điểm nào.
  • Không tự khóa chính mình: luôn có rollback, console hoặc session dự phòng.

2. Chuẩn bị an toàn trước khi sửa cấu hình SSH

Trước khi đụng vào /etc/ssh/sshd_config, hãy mở sẵn một phiên SSH đang hoạt động và không đóng phiên đó cho tới khi kiểm thử xong. Nếu là VPS/cloud, cần chắc chắn bạn có console web hoặc serial console để cứu máy nếu cấu hình sai.

2.1. Sao lưu cấu hình hiện tại

sudo cp -a /etc/ssh/sshd_config /etc/ssh/sshd_config.$(date +%F-%H%M%S).bak
sudo sshd -t

Giải thích:

  • cp -a giữ nguyên quyền file và metadata.
  • sshd -t kiểm tra syntax trước khi reload dịch vụ.

Output tốt là không in gì ra màn hình. Nếu có lỗi, ví dụ:

/etc/ssh/sshd_config line 98: Bad configuration option: PasswordAuthenticatio

thì nghĩa là có typo hoặc option không phù hợp phiên bản OpenSSH.

2.2. Kiểm tra phiên bản OpenSSH và distro

ssh -V
sshd -V 2>&1 | head -1
cat /etc/os-release

Việc này giúp tránh copy cấu hình không tương thích. Một số option mới có thể chưa có trên distro cũ. Tài liệu chính thống nên tham khảo là OpenSSH sshd_config manual và tài liệu bảo mật của distro bạn dùng.

3. Tạo user quản trị và SSH key đúng cách

Không nên vận hành production bằng root login trực tiếp. Tạo user quản trị riêng, cấp sudo có kiểm soát, sau đó dùng SSH key để đăng nhập.

3.1. Tạo user quản trị

sudo adduser opsadmin
sudo usermod -aG sudo opsadmin
id opsadmin

Output mẫu:

uid=1001(opsadmin) gid=1001(opsadmin) groups=1001(opsadmin),27(sudo)

Trên RHEL/CentOS/Rocky Linux, nhóm quản trị thường là wheel thay vì sudo:

sudo usermod -aG wheel opsadmin

3.2. Sinh SSH key trên máy cá nhân

ssh-keygen -t ed25519 -a 100 -C "opsadmin@production" -f ~/.ssh/opsadmin_prod_ed25519

ed25519 gọn, nhanh và an toàn cho đa số trường hợp hiện nay. Tham số -a 100 tăng số vòng KDF để bảo vệ private key tốt hơn nếu file bị lộ. Luôn đặt passphrase cho private key, đặc biệt với server production.

3.3. Cài public key lên server

ssh-copy-id -i ~/.ssh/opsadmin_prod_ed25519.pub opsadmin@SERVER_IP

Nếu chưa dùng được ssh-copy-id, có thể làm thủ công:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
nano ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Sau đó kiểm thử bằng một terminal mới:

ssh -i ~/.ssh/opsadmin_prod_ed25519 opsadmin@SERVER_IP
sudo -v

4. Cấu hình sshd_config an toàn nhưng vẫn vận hành được

Mở file cấu hình:

sudo nano /etc/ssh/sshd_config

Có thể bắt đầu với block cấu hình sau. Hãy điều chỉnh AllowUsers và port theo môi trường thực tế.

Port 22
Protocol 2
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
AuthenticationMethods publickey
PermitEmptyPasswords no
X11Forwarding no
AllowTcpForwarding no
ClientAliveInterval 300
ClientAliveCountMax 2
MaxAuthTries 3
LoginGraceTime 30
AllowUsers opsadmin

4.1. Giải thích các option quan trọng

  • PermitRootLogin no: chặn đăng nhập root trực tiếp. Khi cần quyền cao, user quản trị dùng sudo.
  • PasswordAuthentication no: tắt đăng nhập bằng mật khẩu, giảm đáng kể brute force.
  • AuthenticationMethods publickey: yêu cầu xác thực bằng public key.
  • MaxAuthTries 3: giảm số lần thử sai trong một kết nối.
  • AllowUsers opsadmin: chỉ user được liệt kê mới được SSH.
  • X11Forwarding noAllowTcpForwarding no: tắt tính năng không cần thiết nếu bạn không dùng tunnel.

Lưu ý: nếu hệ thống cần SFTP, Git over SSH, SSH tunnel hoặc automation từ CI/CD, đừng tắt vội các option liên quan khi chưa kiểm tra dependency.

5. Kiểm tra syntax và reload SSH không làm rớt phiên hiện tại

sudo sshd -t
sudo systemctl reload ssh
# hoặc trên một số distro:
sudo systemctl reload sshd

Nếu reload không lỗi, mở terminal mới và thử đăng nhập:

ssh -i ~/.ssh/opsadmin_prod_ed25519 opsadmin@SERVER_IP

Sau đó thử xác nhận password login đã bị chặn:

ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no opsadmin@SERVER_IP

Output mong muốn:

opsadmin@SERVER_IP: Permission denied (publickey).

6. Firewall: chỉ mở SSH theo nhu cầu thật

Hardening SSH không chỉ nằm trong sshd_config. Nếu IP quản trị cố định, nên giới hạn firewall chỉ cho phép IP đó truy cập SSH.

6.1. UFW trên Ubuntu/Debian

sudo ufw allow from YOUR_OFFICE_IP to any port 22 proto tcp
sudo ufw deny 22/tcp
sudo ufw status numbered

Nếu chưa thể cố định IP, ít nhất hãy bật UFW và chỉ mở các port cần thiết:

sudo ufw allow 22/tcp
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable
sudo ufw status verbose

6.2. firewalld trên RHEL/Rocky/AlmaLinux

sudo firewall-cmd --permanent --add-service=ssh
sudo firewall-cmd --reload
sudo firewall-cmd --list-all

Nếu cần giới hạn IP, dùng rich rule:

sudo firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="YOUR_OFFICE_IP/32" service name="ssh" accept'
sudo firewall-cmd --permanent --remove-service=ssh
sudo firewall-cmd --reload

7. Fail2ban: giảm brute force khi chưa giới hạn được IP

Fail2ban đọc log đăng nhập thất bại và tự động ban IP vi phạm trong một khoảng thời gian. Đây không phải thay thế cho SSH key và firewall, nhưng là lớp phòng thủ hữu ích.

sudo apt update
sudo apt install -y fail2ban
sudo systemctl enable --now fail2ban

Tạo file jail riêng:

sudo nano /etc/fail2ban/jail.d/sshd.local

Nội dung mẫu:

[sshd]
enabled = true
port = ssh
filter = sshd
logpath = %(sshd_log)s
maxretry = 5
findtime = 10m
bantime = 1h

Khởi động lại và kiểm tra:

sudo systemctl restart fail2ban
sudo fail2ban-client status sshd

Output mẫu:

Status for the jail: sshd
|- Filter
|  |- Currently failed: 0
|  `- Total failed: 12
`- Actions
   |- Currently banned: 1
   `- Banned IP list: 203.0.113.10

8. Đổi port SSH có giúp bảo mật hơn không?

Đổi port từ 22 sang port khác có thể giảm log rác từ bot quét mặc định, nhưng không nên xem là biện pháp bảo mật chính. Nếu đổi port, vẫn phải dùng SSH key, tắt root login, firewall và monitoring. Với production có nhiều automation, đổi port còn có thể gây lỗi pipeline hoặc script vận hành.

Nếu quyết định đổi port, ví dụ sang 2222:

Port 2222

Đừng quên mở firewall trước khi reload SSH:

sudo ufw allow 2222/tcp
sudo sshd -t
sudo systemctl reload ssh
ssh -p 2222 -i ~/.ssh/opsadmin_prod_ed25519 opsadmin@SERVER_IP

9. Audit log: biết ai đã vào server và khi nào

Trên Ubuntu/Debian, log SSH thường nằm trong /var/log/auth.log. Trên RHEL/Rocky, thường là /var/log/secure.

sudo grep "Accepted publickey" /var/log/auth.log | tail -20
sudo grep "Failed password" /var/log/auth.log | tail -20
journalctl -u ssh --since "1 hour ago"

Output mẫu:

Accepted publickey for opsadmin from 198.51.100.20 port 54822 ssh2: ED25519 SHA256:...

Với server quan trọng, nên đẩy log về hệ thống tập trung như ELK, Loki, Graylog hoặc SIEM để tránh tình huống attacker xóa log cục bộ.

10. Troubleshooting các lỗi thường gặp sau khi hardening SSH

10.1. Lỗi Permission denied (publickey)

Nguyên nhân phổ biến:

  • Public key chưa nằm đúng trong ~/.ssh/authorized_keys.
  • Quyền thư mục sai: ~/.ssh không phải 700 hoặc authorized_keys không phải 600.
  • Dùng nhầm private key ở máy client.
  • User không nằm trong AllowUsers.

Kiểm tra nhanh:

ssh -vvv -i ~/.ssh/opsadmin_prod_ed25519 opsadmin@SERVER_IP
sudo tail -f /var/log/auth.log

10.2. Reload SSH báo lỗi cấu hình

Luôn chạy:

sudo sshd -t

Nếu lỗi option, kiểm tra lại chính tả và phiên bản OpenSSH. Có distro dùng KbdInteractiveAuthentication, có nơi vẫn thấy ChallengeResponseAuthentication trong cấu hình cũ.

10.3. Tự khóa khỏi server

Nếu còn phiên SSH cũ, sửa lại file từ phiên đó và reload. Nếu mất toàn bộ SSH, dùng console của nhà cung cấp cloud/VPS để đăng nhập, restore file backup:

sudo cp -a /etc/ssh/sshd_config.2026-05-30-1900.bak /etc/ssh/sshd_config
sudo sshd -t
sudo systemctl reload ssh

11. Checklist nghiệm thu sau hardening SSH server Linux

  • Đã backup /etc/ssh/sshd_config.
  • sshd -t không báo lỗi.
  • User quản trị riêng đăng nhập được bằng SSH key.
  • Root login trực tiếp bị chặn.
  • Password login bị chặn hoặc chỉ được bật có kiểm soát trong giai đoạn chuyển đổi.
  • Firewall chỉ mở SSH theo nhu cầu thật.
  • Fail2ban hoặc cơ chế rate limit tương đương hoạt động.
  • Log đăng nhập thành công/thất bại đọc được.
  • Có phương án cứu hộ: console, snapshot, backup config.
  • Automation, backup job, SFTP, Git deploy vẫn hoạt động sau thay đổi.

12. Lab thực hành: dựng một SSH baseline cho VPS mới

Bài tập đề xuất:

  1. Tạo một VPS test hoặc máy ảo Linux.
  2. Tạo user opsadmin, cấp sudo.
  3. Sinh SSH key ed25519 và đăng nhập bằng key.
  4. Tắt root login và password login.
  5. Bật UFW/firewalld chỉ mở SSH, HTTP, HTTPS.
  6. Cài Fail2ban và kiểm tra jail sshd.
  7. Viết lại checklist nghiệm thu riêng cho môi trường của bạn.

Kết luận

Hardening SSH server Linux không phải một lần chỉnh file rồi quên. Đây là baseline vận hành cần được kiểm tra định kỳ, đặc biệt sau khi thêm user mới, đổi IP quản trị, thay đổi pipeline deploy hoặc chuyển server sang môi trường cloud khác. Nếu làm đúng, bạn giảm đáng kể rủi ro brute force, hạn chế thiệt hại khi credential bị lộ và vẫn giữ được khả năng vận hành an toàn trong production.

Tác giả: Mạnh Hoàng

Tôi là Hoàng Mạnh, người sáng lập blog SysadminSkills.com. Tôi viết về quản trị hệ thống, bảo mật máy chủ, DevOps và cách ứng dụng AI để tự động hóa công việc IT. Blog này là nơi tôi chia sẻ những gì đã học được từ thực tế – đơn giản, ngắn gọn và áp dụng được ngay.