Khóa SSH: cấu hình đăng nhập máy chủ không cần mật khẩu
Cấu hình khóa SSH gồm ba bước: tạo cặp khóa bằng ssh-keygen -t ed25519, sao chép khóa công khai lên máy chủ bằng ssh-copy-id user@host và kiểm tra đăng nhập. Sau đó tắt đăng nhập bằng mật khẩu trong /etc/ssh/sshd_config (PasswordAuthentication no), còn các kết nối thường dùng được khai báo trong ~/.ssh/config.
Khóa SSH là một cặp tệp: khóa riêng tư để ở máy bạn, khóa công khai đặt lên máy chủ. Khi kết nối, máy chủ kiểm tra bạn có khóa riêng tư tương ứng với một trong các khóa công khai được phép hay không, và nếu có thì cho vào mà không cần mật khẩu. Cách này tiện hơn và an toàn hơn nhiều so với mật khẩu: gần như không thể dò khóa bằng cách thử hết mọi tổ hợp. Dưới đây là hướng dẫn cấu hình khóa SSH từ lúc tạo đến khi tắt đăng nhập bằng mật khẩu, kèm các lỗi người ta hay gặp nhất.
Cơ chế xác thực bằng khóa
Khóa là bất đối xứng. Khóa công khai (id_ed25519.pub) có thể đưa cho bất kỳ ai — từ đó không thể suy ra khóa riêng tư. Khóa riêng tư (id_ed25519) không bao giờ rời khỏi máy bạn và không được gửi qua mạng.
Khi đăng nhập, client cho máy chủ biết mình muốn dùng khóa nào. Máy chủ tìm khóa công khai đó trong tệp ~/.ssh/authorized_keys của người dùng, và nếu tìm thấy thì yêu cầu client ký dữ liệu phiên bằng khóa riêng tư. Chữ ký được kiểm tra bằng khóa công khai, và đăng nhập được cho phép. Mật khẩu không hề được truyền đi.
Bước 1. Tạo khóa: ssh-keygen
Trên máy của bạn (Linux, macOS hoặc Windows 10/11 có sẵn OpenSSH), chạy:
ssh-keygen -t ed25519 -C "alena@laptop"
Tùy chọn -t chọn thuật toán, -C là chú thích sẽ nằm ở cuối khóa công khai để sau này dễ nhận ra khóa của ai. Ed25519 là thuật toán hiện đại được khuyến nghị: khóa ngắn, nhanh và an toàn. Nếu máy chủ rất cũ không hỗ trợ Ed25519, dùng RSA với độ dài ít nhất 3072 bit: ssh-keygen -t rsa -b 4096.
Generating public/private ed25519 key pair.
Enter file in which to save the key (/home/alena/.ssh/id_ed25519):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/alena/.ssh/id_ed25519
Your public key has been saved in /home/alena/.ssh/id_ed25519.pub
The key fingerprint is:
SHA256:Xq3v0m6c1y2pVv8m3N0uYv9yQm0e6dFv5gH2rZt1aBc alena@laptop
Có cần passphrase không
Passphrase mã hóa khóa riêng tư trên đĩa. Nếu laptop bị mất hoặc tệp bị rò rỉ, không có passphrase thì khóa vô dụng. Với khóa cá nhân nên đặt passphrase, và để khỏi phải nhập mỗi lần kết nối, dùng ssh-agent: nó giữ khóa đã giải mã trong bộ nhớ đến hết phiên làm việc.
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
ssh-add -l # danh sách khóa đã nạp
Khóa không có passphrase chỉ hợp lý cho tự động hóa — ví dụ CI hoặc script sao lưu. Khóa như vậy nên được giới hạn quyền trên máy chủ (xem bên dưới).
Bước 2. Sao chép khóa công khai lên máy chủ: ssh-copy-id
Cách đơn giản nhất là ssh-copy-id. Lệnh sẽ kết nối bằng mật khẩu lần cuối, thêm khóa công khai của bạn vào ~/.ssh/authorized_keys trên máy chủ và đặt quyền đúng.
ssh-copy-id -i ~/.ssh/id_ed25519.pub deploy@203.0.113.10
/usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/alena/.ssh/id_ed25519.pub"
/usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys
deploy@203.0.113.10's password:
Number of key(s) added: 1
Now try logging into the machine, with: "ssh 'deploy@203.0.113.10'"
and check to make sure that only the key(s) you wanted were added.
Nếu máy chủ dùng cổng không chuẩn, thêm -p 2222.
Khi không có ssh-copy-id
Trên Windows không có tiện ích ssh-copy-id. Có thể chuyển khóa bằng tay bằng một lệnh:
cat ~/.ssh/id_ed25519.pub | ssh deploy@203.0.113.10 "mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys"
Các nhà cung cấp đám mây thường cho phép khai báo khóa công khai ngay khi tạo máy chủ — khóa sẽ vào authorized_keys qua cloud-init.
Bước 3. Kiểm tra đăng nhập
ssh deploy@203.0.113.10
Nếu không còn hỏi mật khẩu (hoặc chỉ hỏi passphrase của khóa), mọi thứ đã hoạt động. Lần đầu kết nối tới máy chủ mới, SSH sẽ hiển thị dấu vân tay của khóa máy chủ và hỏi có tin tưởng không. Sau khi trả lời yes, dấu vân tay được lưu vào ~/.ssh/known_hosts, và từ đó SSH sẽ cảnh báo nếu khóa của máy chủ thay đổi.
Để xem client thử những khóa nào và vì sao máy chủ từ chối, chạy kết nối với chế độ chi tiết:
ssh -v deploy@203.0.113.10
Tệp ~/.ssh/config: tên ngắn cho máy chủ
Khi có nhiều máy chủ, việc gõ lại người dùng, IP, cổng và đường dẫn khóa mỗi lần rất mệt. Tất cả được khai báo trong ~/.ssh/config:
Host prod
HostName 203.0.113.10
User deploy
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host bastion
HostName bastion.example.com
User alena
Host db-internal
HostName 10.0.0.15
User admin
ProxyJump bastion
Host *
ServerAliveInterval 60
AddKeysToAgent yes
Giờ chỉ cần ssh prod, còn scp, rsync và Git cũng hiểu các tên này: rsync -av ./site/ prod:/var/www/.
IdentitiesOnly yes— chỉ dùng khóa được chỉ định. Không có dòng này, client sẽ thử mọi khóa trong agent, và máy chủ có thể ngắt kết nối vì quá số lần thử trước khi tới khóa đúng.ProxyJump— kết nối tới máy chủ nội bộ qua máy trung gian (bastion) chỉ bằng một lệnh.ServerAliveInterval— gửi "ping" mỗi 60 giây để kết nối không bị rớt khi nhàn rỗi.
Tệp này phải có quyền 600, nếu không SSH có thể từ chối đọc: chmod 600 ~/.ssh/config.
Agent forwarding: khi nào cần và nguy hiểm ở đâu
Đôi khi từ máy chủ cần kết nối tiếp — ví dụ thực hiện git pull từ kho riêng. Không được sao chép khóa riêng tư lên máy chủ. Thay vào đó dùng ssh -A hoặc ForwardAgent yes: máy chủ sẽ truy cập được agent của bạn trong thời gian phiên làm việc. Nhưng bất kỳ ai có quyền root trên máy chủ đó cũng có thể dùng agent trong lúc bạn đang kết nối. Vì vậy chỉ bật chuyển tiếp cho máy tin cậy, còn để đi qua máy trung gian nên dùng ProxyJump: nó không mở agent.
Bước 4. Tắt đăng nhập bằng mật khẩu
Khi còn cho phép đăng nhập bằng mật khẩu, máy chủ vẫn là mục tiêu của việc dò mật khẩu. Sau khi đã chắc chắn đăng nhập được bằng khóa, hãy tắt mật khẩu. Quan trọng: đừng đóng phiên hiện tại cho đến khi kiểm tra xong đăng nhập ở cửa sổ mới, nếu không bạn có thể mất quyền truy cập.
Mở /etc/ssh/sshd_config (hoặc tạo tệp trong /etc/ssh/sshd_config.d/ nếu cấu hình chính có chỉ thị Include) và đặt:
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitRootLogin no
PermitRootLogin no cấm đăng nhập bằng root hoàn toàn: quản trị viên đăng nhập bằng tài khoản của mình và nâng quyền qua sudo. Nếu không thể bỏ đăng nhập root, dùng PermitRootLogin prohibit-password — chỉ cho đăng nhập bằng khóa.
Kiểm tra cú pháp và khởi động lại dịch vụ:
sudo sshd -t
sudo systemctl reload ssh # trên Debian/Ubuntu; trên họ RHEL — sshd
Lệnh sshd -t không in gì nếu cấu hình đúng. Bây giờ, ở một terminal mới, kiểm tra đăng nhập bằng khóa vẫn hoạt động, còn đăng nhập bằng mật khẩu bị máy chủ từ chối:
$ ssh -o PubkeyAuthentication=no deploy@203.0.113.10
deploy@203.0.113.10: Permission denied (publickey).
Bảo vệ thêm
Tắt mật khẩu là biện pháp chính. Tiếp theo thường là giới hạn cổng 22 bằng tường lửa (ufw allow from 198.51.100.0/24 to any port 22) và cài fail2ban, công cụ chặn IP sau nhiều lần thử thất bại. Trạng thái bảo vệ SSH xem bằng sudo fail2ban-client status sshd.
Khóa dùng cho tự động hóa có thể bị giới hạn ngay trong authorized_keys bằng các tùy chọn đặt trước khóa: ví dụ from="198.51.100.7",no-port-forwarding,no-pty ssh-ed25519 AAAA... backup chỉ cho phép đăng nhập từ một địa chỉ và không mở shell tương tác.
Lỗi thường gặp và cách sửa
Permission denied (publickey)
Đây là lỗi phổ biến nhất. Nguyên nhân, từ thường gặp đến hiếm:
- Quyền sai trên máy chủ. sshd bỏ qua
authorized_keysnếu thư mục hoặc tệp cho phép người khác ghi. Cách sửa:chmod 700 ~/.ssh,chmod 600 ~/.ssh/authorized_keys, và thư mục home không được cho nhóm hoặc người khác quyền ghi. - Sai chủ sở hữu. Nếu bạn tạo tệp bằng
sudo, chúng sẽ thuộc về root. Cách sửa:sudo chown -R deploy:deploy /home/deploy/.ssh. - Khóa được đặt cho sai người dùng. Bạn đã sao chép khóa cho
rootnhưng đăng nhập bằngdeploy, hoặc ngược lại. - Client gửi sai khóa. Xem
ssh -v: dòngOffering public keycho biết khóa nào đang được thử. Chỉ định khóa đúng bằng-ihoặcIdentityFile. - Khóa bị hỏng khi sao chép. Khóa công khai phải nằm trên một dòng. Ngắt dòng khi dán từ clipboard sẽ làm hỏng khóa.
Nguyên nhân phía máy chủ thể hiện trong nhật ký: sudo journalctl -u ssh -n 30 (trên RHEL — -u sshd). Có thể gặp dòng kiểu Authentication refused: bad ownership or modes for directory /home/deploy/.ssh.
UNPROTECTED PRIVATE KEY FILE
Client từ chối dùng khóa riêng tư mà người khác có thể đọc. Cách sửa: chmod 600 ~/.ssh/id_ed25519.
REMOTE HOST IDENTIFICATION HAS CHANGED
Khóa của máy chủ không khớp với khóa đã lưu trong known_hosts. Điều này xảy ra sau khi cài lại máy chủ hoặc đổi IP, nhưng cũng giống hệt tình huống tấn công "người đứng giữa". Hãy chắc chắn máy chủ đã thật sự được cài lại, rồi xóa bản ghi cũ: ssh-keygen -R 203.0.113.10.
Too many authentication failures
Agent đã gửi quá nhiều khóa tới máy chủ, và máy chủ đóng kết nối theo MaxAuthTries. Giải pháp: IdentitiesOnly yes và IdentityFile rõ ràng trong ~/.ssh/config.
Tóm lại
Cấu hình khóa SSH mất khoảng năm phút: ssh-keygen -t ed25519, ssh-copy-id, kiểm tra đăng nhập, sau đó PasswordAuthentication no và khởi động lại sshd khi vẫn còn một phiên thứ hai đang mở. Tệp ~/.ssh/config giúp bạn khỏi gõ lệnh dài, còn quyền 700/600 giải quyết phần lớn lỗi "Permission denied". SSH, rsync và bảo vệ máy chủ bằng tường lửa và fail2ban đều được thực hành trong khóa học Linux.
Câu hỏi thường gặp
Có thể dùng một khóa SSH cho mọi máy chủ không?
Về kỹ thuật thì được, và nhiều người làm vậy. Nhưng với các phạm vi khác nhau (công việc, dự án cá nhân, CI) nên tạo khóa riêng: nếu một khóa bị lộ thì không mở được toàn bộ hệ thống.
Khóa SSH trên Windows được lưu ở đâu?
OpenSSH tích hợp lưu trong C:\Users\tên-bạn\.ssh\ — gồm id_ed25519, id_ed25519.pub, known_hosts và config. Tạo khóa bằng cùng lệnh ssh-keygen trong PowerShell.
Làm sao đổi passphrase của khóa đã có?
Chạy ssh-keygen -p -f ~/.ssh/id_ed25519: lệnh sẽ hỏi passphrase cũ và mới. Bản thân khóa không đổi, không cần đưa lại lên máy chủ.
Làm sao thu hồi quyền truy cập bằng khóa?
Xóa dòng chứa khóa công khai đó khỏi ~/.ssh/authorized_keys trên máy chủ. Chú thích ở cuối khóa giúp tìm đúng dòng.
Có khóa riêng tư nhưng không còn khóa công khai thì làm sao?
Lệnh ssh-keygen -y -f ~/.ssh/id_ed25519 sẽ in ra khóa công khai được tính từ khóa riêng tư.
Chủ đề này được giảng chi tiết kèm thực hành trong khóa học “Linux: с нуля до уверенного администрирования”.
- Удалённый доступ и сетевые хранилища: SSH, rsync, NFS и SMB
- Firewall и защита сервера: ufw, nftables, fail2ban и GPG