Tóm tắt: Đưa key lên trước, giữ một phiên SSH đang mở, đặt cấu hình trong /etc/ssh/sshd_config.d/ (tắt password, tắt root, AllowGroups), kiểm tra bằng sshd -t / sshd -T, reload, mở phiên mới để xác nhận. Thêm fail2ban hoặc chỉ mở cổng 22 cho dải quản trị bằng nftables.
Luồng hoạt động
flowchart TD A["ssh-copy-id: đưa public key lên"] --> B["Giữ 1 phiên SSH đang mở"] B --> C["Ghi sshd_config.d/10-hardening.conf"] C --> D{"sshd -t OK?"} D -->|không| C D -->|có| E["systemctl reload ssh"] E --> F["Mở phiên mới để test"] F -->|lỗi| G["Sửa từ phiên cũ"] F -->|OK| H["fail2ban / firewall"]
Cấu hình
Đưa key lên trước
# Trên máy quản trị: key ed25519, có passphrase
ssh-keygen -t ed25519 -C "ops@example.com"
ssh-copy-id -i ~/.ssh/id_ed25519.pub ops@203.0.113.30
ssh -o PasswordAuthentication=no ops@203.0.113.30 true && echo "key OK"sshd_config
Trên Ubuntu/Debian, sshd_config có Include /etc/ssh/sshd_config.d/*.conf ở đầu file, và sshd lấy giá trị xuất hiện đầu tiên của mỗi directive. Vì vậy file drop-in có tên sắp xếp trước sẽ thắng, kể cả file do cloud-init sinh ra (vd 50-cloud-init.conf bật PasswordAuthentication yes). Đặt tên 10-... để chắc chắn.
# Xác thực
PermitRootLogin no
PubkeyAuthentication yes
PasswordAuthentication no
KbdInteractiveAuthentication no
PermitEmptyPasswords no
AuthenticationMethods publickey
# Giới hạn ai được vào (tạo group trước: groupadd ssh-users)
AllowGroups ssh-users
# Chống brute-force / phiên treo
MaxAuthTries 3
LoginGraceTime 30
MaxStartups 10:30:60
ClientAliveInterval 300
ClientAliveCountMax 2
# Tắt tính năng không dùng (jump host thì giữ AllowTcpForwarding)
X11Forwarding no
AllowAgentForwarding no
AllowTcpForwarding no
LogLevel VERBOSEJump host cần ProxyJump thì phải để AllowTcpForwarding yes (ít nhất cho group dùng jump). Có thể nới riêng bằng Match Group netops ở cuối file. Cấu hình phía client xem SSH config và jump host.
Chỉ cho phép thuật toán hiện đại (tuỳ chọn, kiểm tra client cũ và thiết bị mạng trước khi áp):
KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org
Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com
MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.comÁp dụng
sudo groupadd -f ssh-users && sudo usermod -aG ssh-users ops
sudo sshd -t # kiểm tra cú pháp, không in gì = OK
sudo sshd -T | grep -Ei 'passwordauth|permitroot|allowgroups|authenticationmethods'
sudo systemctl reload ssh # RHEL: sshd
# Mở terminal MỚI và ssh vào, chỉ đóng phiên cũ khi phiên mới vào đượcUbuntu 24.04 dùng socket activation (ssh.socket): đổi Port/ListenAddress trong sshd_config cần systemctl daemon-reload && systemctl restart ssh.socket, không chỉ reload service.
fail2ban
sudo apt install fail2ban[sshd]
enabled = true
backend = systemd
maxretry = 5
findtime = 10m
bantime = 1h
ignoreip = 127.0.0.1/8 ::1 198.51.100.0/24sudo systemctl enable --now fail2ban
sudo fail2ban-client status sshd
sudo fail2ban-client set sshd unbanip 203.0.113.50ignoreip là dải mạng quản trị, tránh tự ban chính mình. OpenSSH ≥ 9.8 có thêm PerSourcePenalties tích hợp sẵn, nhưng fail2ban vẫn hữu ích cho bản cũ và để chặn ở firewall.
Kiểm tra
| Mục đích | Lệnh |
|---|---|
| Cấu hình hiệu lực cho một user/host cụ thể | sudo sshd -T -C user=ops,host=client.example.com,addr=198.51.100.5 |
| Server chấp nhận phương thức nào | ssh -v ops@203.0.113.30 2>&1 | grep 'Authentications that can continue' |
| Thử ép password (phải bị từ chối) | ssh -o PubkeyAuthentication=no ops@203.0.113.30 |
| Log đăng nhập | journalctl -u ssh --since "1 hour ago" |
| Phiên đang mở | who, ss -tnp state established '( sport = :22 )' |
| Fingerprint host key (so với lần đầu kết nối) | ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub |
Lỗi thường gặp
| Triệu chứng | Nguyên nhân | Cách xử lý |
|---|---|---|
| Vẫn đăng nhập được bằng password | File drop-in khác (cloud-init) có PasswordAuthentication yes được đọc trước |
sshd -T | grep passwordauth; đổi tên file của bạn thành 10-... hoặc sửa file kia |
Permission denied (publickey) sau khi bật key-only |
User không thuộc AllowGroups, hoặc quyền ~/.ssh sai |
chmod 700 ~/.ssh; chmod 600 ~/.ssh/authorized_keys; xem journalctl -u ssh |
Authentication refused: bad ownership or modes |
Home hoặc ~/.ssh cho group/other ghi |
Sửa quyền, owner đúng user |
| Ansible/automation hỏng sau hardening | Tắt AllowTcpForwarding/agent forwarding hoặc giới hạn cipher |
Nới bằng Match User <automation> |
Thiết bị/tool cũ báo no matching key exchange method |
Đã bỏ KEX/cipher cũ | Giữ thuật toán cũ chỉ trong Match Address của dải đó, hoặc nâng cấp client |
| Sau reload không SSH vào được | Lỗi cú pháp (bỏ qua sshd -t) hoặc tự khoá mình |
Dùng phiên cũ còn mở / console để sửa |
Tham khảo
man sshd_config,man sshd(mục-T,-C)- OpenSSH release notes
- fail2ban