SSD Nodes Learn
Hướng dẫn Matt ConnorBởi Matt Connor · Cập nhật ngày 2026-07-23

Cách quản lý SSH key an toàn và hiệu quả

Hướng dẫn cách dùng ed25519, thiết lập file config Host và phân quyền file cho sshd để bảo mật VPS. Cách thu hồi key ngay khi thiết bị bị mất.

Cách SSH key hoạt động

Một SSH key là một cặp file: một private key nằm trên thiết bị của bạn và một public key mà bạn copy sang mọi server mà bạn muốn đăng nhập. Khi bạn kết nối, server sử dụng public key để gửi một challenge mà chỉ có private key tương ứng mới có thể trả lời. Private key không bao giờ rời khỏi thiết bị của bạn, vì vậy không có bí mật nào được truyền qua mạng, và một server bị compromise cũng không có gì hữu ích để đánh cắp. Đó là lý do tại sao keys tốt hơn passwords. Quản lý SSH keys hiệu quả dựa trên bốn thói quen: một key cho mỗi thiết bị, đúng file permissions mà sshd yêu cầu, một file ~/.ssh/config để bạn không phải gõ lại các options, và biết cách xóa một key ngay khi laptop bị mất.

Hướng dẫn này bao gồm từng thói quen trên Ubuntu 24.04, mặc dù hầu hết mọi thứ ở đây đều áp dụng cho bất kỳ Linux server nào và bất kỳ OpenSSH gần đây nào.

Một lưu ý về thuật ngữ trước khi bắt đầu, để tránh những sai lầm thực tế. Public key không phải là bí mật. Bạn có thể paste nó vào một ticket, gửi qua email, hoặc công khai nó, và không ai có thể đăng nhập bằng nó. Private key mới là bí mật. Bất kỳ ai copy file đó, và biết passphrase của nó (nếu có), thì đối với các server của bạn, người đó chính là bạn.

Tạo một key: ed25519 là lựa chọn mặc định hợp lý

Trên máy tính cá nhân của bạn, không phải trên server, hãy chạy:

ssh-keygen -t ed25519 -C "laptop"

-t ed25519 chọn kiểu key. Ed25519 là mặc định hiện đại: các key ngắn, nhanh và được hỗ trợ bởi mọi bản phát hành OpenSSH từ năm 2014. Chỉ dùng fallback sang ssh-keygen -t rsa -b 4096 khi bạn bắt buộc phải kết nối với một thiết bị cũ không hiểu ed25519. -C "laptop" dùng để đặt một comment. Comment không có tác dụng mã hóa, nhưng đó là cách bạn nhận diện key này trong file authorized_keys của server hai năm sau, vì vậy hãy đặt tên thiết bị mà key đó lưu trữ.

ssh-keygen hỏi nơi lưu key. Chấp nhận mặc định là ~/.ssh/id_ed25519. Sau đó nó sẽ hỏi passphrase. Hãy thiết lập một cái; phần passphrase bên dưới sẽ giải thích tại sao nó không làm tốn thời gian hàng ngày của bạn. Bạn sẽ nhận được hai file: ~/.ssh/id_ed25519 là private key, và ~/.ssh/id_ed25519.pub là public key. Xem phần public:

cat ~/.ssh/id_ed25519.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptop

Nó chỉ gồm một dòng: kiểu key, nội dung key, và comment của bạn. Dòng đó chính là thứ sẽ nằm trên các server của bạn.

Một key cho mỗi thiết bị, không phải một key cho mỗi server

Câu hỏi mà mọi người luôn hỏi đầu tiên: tôi có cần một key mới cho mỗi server không? Không. Hãy tạo một key cho mỗi thiết bị mà bạn dùng để gõ lệnh, và đưa public key đó lên mọi server mà thiết bị đó cần truy cập. Key dùng để định danh thiết bị. File authorized_keys trên mỗi server là danh sách các thiết bị được phép truy cập.

Đây là mô hình có khả năng mở rộng, còn các phương án thay thế thường thất bại theo những cách có thể dự đoán được. Dùng một key cho mỗi server nghĩa là một laptop có hai mươi server sẽ phải mang theo hai mươi private keys, và bạn sẽ mất dấu cái nào là cái nào. Dùng một key chung cho tất cả thiết bị còn tệ hơn: khi laptop bị mất, bạn không thể revoke laptop mà không khóa luôn cả desktop, vì chúng giữ cùng một private key, do đó bạn phải thay thế key ở mọi nơi và phân phối lại cho mọi thiết bị cùng một lúc.

Với mô hình một key cho mỗi thiết bị, việc mất laptop chỉ tốn của bạn một dòng trên mỗi server: xóa dòng của laptop khỏi authorized_keys, và mọi thiết bị khác vẫn hoạt động bình thường. Comment bạn đặt bằng -C chính là thứ giúp dòng đó dễ dàng được tìm thấy.

Quy tắc đằng sau mô hình này: một private key được tạo trên một thiết bị và sẽ "chết" cùng với thiết bị đó. Đừng bao giờ copy một private key sang máy thứ hai, và đừng bao giờ upload nó lên một server. Khi một thiết bị mới cần quyền truy cập, hãy generate một key mới ngay trên thiết bị đó.

Đưa public key lên server

Cách dễ nhất là dùng ssh-copy-id, đi kèm với OpenSSH:

ssh-copy-id matt@10.0.0.10

Nó sẽ đăng nhập bằng bất cứ thứ gì còn hoạt động (thường là password), append public key của bạn vào ~/.ssh/authorized_keys trên server, và tạo directory cũng như file với đúng permissions nếu chúng chưa tồn tại. Hãy kiểm tra bằng cách mở một session SSH mới: server sẽ cho bạn vào mà không hỏi password của account. Nếu key của bạn có passphrase, máy của bạn có thể hỏi passphrase đó; prompt đó là local và không phải là password của server.

Khi password login đã bị disable, ssh-copy-id không thể đăng nhập, vì vậy bạn phải thêm dòng đó bằng tay. Đăng nhập qua một session vẫn còn hoạt động, hoặc qua web console của nhà cung cấp, và chạy lệnh này trên server:

mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptop" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Paste public key thật của bạn vào trong dấu ngoặc kép, chính là dòng duy nhất đầy đủ từ id_ed25519.pub. authorized_keys là mỗi dòng một public key, và đó là toàn bộ database truy cập: thêm một thiết bị là append một dòng, và revoke một thiết bị là xóa một dòng. Trên một server mới, bước này thuộc về 10 phút đầu tiên trên một VPS mới, ngay trước khi bạn tắt password login.

Các permission gây lỗi đăng nhập bằng key

Đây là cách phổ biến nhất khiến key login thất bại, và nó thất bại một cách âm thầm từ phía client. sshd chạy với StrictModes yes mặc định trên Ubuntu 24.04, nghĩa là nó từ chối sử dụng một file authorized_keys mà các user khác có thể chỉnh sửa. Nếu file, directory ~/.ssh, hoặc home directory của bạn có thể bị write bởi bất kỳ ai khác ngoài bạn, sshd sẽ ignore key của bạn và fallback về hỏi password, mà không có giải thích gì ở client. (OpenSSH của Ubuntu chỉ chấp nhận duy nhất một trường hợp hẹp: một file group writable bởi chính private group của bạn, mà không ai khác có trong group đó. Đừng dựa dẫm vào nó; hãy giữ các mode bên dưới.) Lý do chỉ xuất hiện trong log của server:

sudo grep 'Authentication refused' /var/log/auth.log

Trên một image tối giản không có rsyslog thì sẽ không có auth.log; dòng tương tự sẽ nằm trong journal: sudo journalctl -u ssh | grep 'Authentication refused'.

Authentication refused: bad ownership or modes for file /home/matt/.ssh/authorized_keys

Cách khắc phục là hai thay đổi permission và một lệnh check ownership, chạy trên server với tư cách là user bị ảnh hưởng:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R matt:matt ~/.ssh

Quy tắc cần nhớ: 700 cho directory .ssh, và 600 cho mọi thứ bên trong nó. Các con số tương tự cũng áp dụng trên máy tính của chính bạn, vì client cũng có kiểm tra. Một private key có thể bị read bởi các user khác sẽ khiến ssh từ chối key ngay lập tức, và lần này lỗi sẽ hiển thị rõ ràng:

@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/matt/.ssh/id_ed25519' are too open.

chmod 600 ~/.ssh/id_ed25519 sẽ khắc phục nó.

~/.ssh/config: ngừng gõ các options

Một file ~/.ssh/config trên máy tính của bạn giúp mỗi server có một tên ngắn gọn và ghi nhớ các options mà bạn hay gõ. Hãy tạo nó với permission 600 và thêm một block Host cho mỗi server:

Host web1
    HostName 10.0.0.10
    User matt
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Host db1
    HostName 10.0.0.11
    User matt
    Port 2222
    IdentityFile ~/.ssh/id_ed25519
    IdentitiesOnly yes

Giờ đây ssh web1 thay thế cho ssh -p 22 matt@10.0.0.10, và cùng một tên ngắn gọn đó có thể dùng trong scp, rsync, và git, vì tất cả đều đọc file này. HostName là địa chỉ thật, User giúp bạn không phải gõ tên account, và IdentityFile chỉ định key nào sẽ được dùng.

IdentitiesOnly yes xứng đáng có một câu riêng, vì nó sửa một lỗi gây bối rối. Khi agent của bạn giữ nhiều keys, client sẽ offer chúng lần lượt từng cái một, và server sẽ tính mỗi lần offer là một lần đăng nhập thất bại. Với quá nhiều keys được load, bạn sẽ gặp lỗi Received disconnect: Too many authentication failures trước khi key đúng được thử đến. IdentitiesOnly yes bắt client chỉ offer duy nhất key được đặt tên trong IdentityFile, nhờ vậy lỗi này không thể xảy ra.

Passphrases và ssh-agent

Một passphrase mã hóa file private key trên disk. Nếu không có nó, bất kỳ ai copy được file đều có thể dùng nó ngay lập tức; nếu có nó, file bị mất sẽ vô dụng cho đến khi passphrase bị đoán ra. Đối với một key trên laptop, đó chính xác là sự bảo vệ bạn muốn, vì laptop rất dễ bị mất trộm và các bản backup laptop có thể bị rò rỉ.

Lý do passphrase không tốn gì trong thực tế là nhờ ssh-agent. Agent giữ key đã được decrypt trong bộ nhớ, vì vậy bạn chỉ cần gõ passphrase một lần cho mỗi session đăng nhập và mọi kết nối sau đó đều diễn ra tức thì. Hầu hết các bản phân phối Linux desktop và macOS đã chạy sẵn một agent cho bạn. Load key của bạn vào đó bằng:

ssh-add ~/.ssh/id_ed25519

ssh-add -l liệt kê các keys mà agent đang giữ. Một lưu ý: agent forwarding (ssh -A) cho phép server từ xa sử dụng agent của bạn để authenticate tiếp sang các server khác khi bạn đang kết nối, vì vậy chỉ enable nó cho các server mà bạn hoàn toàn tin tưởng, và hãy để nó tắt theo mặc định.

Rotation và revocation: bài tập khi mất laptop

Revoke một SSH key thông thường không gì khác hơn là xóa dòng của nó khỏi authorized_keys trên mọi server đang giữ nó. Không có certificate authority nào cần thông báo và không có ngày hết hạn nào để chờ đợi. Ngay khi dòng đó mất đi, các lần đăng nhập mới bằng key đó sẽ thất bại.

Hãy thực hành ngay bây giờ, khi chưa có tình huống khẩn cấp. Chọn một server, mở ~/.ssh/authorized_keys, và tìm key bằng comment của nó. Xóa dòng đó bằng một editor, hoặc filter nó ra theo comment:

grep -v ' laptop$' ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.tmp
mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keys

Sau đó xác nhận từ thiết bị bạn vừa revoke rằng đăng nhập hiện đã thất bại, và từ một thiết bị khác rằng đăng nhập vẫn hoạt động. Lưu ý một chi tiết: việc xóa một key không đóng các session đang mở, vì key chỉ được kiểm tra khi đăng nhập. Nếu bạn đang revoke một thiết bị bị mất trộm, hãy kiểm tra cả who trên server và kết thúc bất kỳ session nào mà bạn không nhận ra.

Rotation (xoay vòng key) cũng là cùng một thao tác nhưng theo thứ tự khác: generate một key mới trên thiết bị, cài đặt nó bằng ssh-copy-id, xác nhận key mới đăng nhập được, sau đó xóa dòng cũ. Hãy làm việc này khi một thiết bị được bàn giao cho người khác, khi một key có nguy cơ bị lộ, hoặc khi ai đó rời khỏi team. Làm thủ công trên hai server thì không sao; nhưng trên hai mươi server thì đó là việc của automation, và quản lý nhiều Linux server sẽ chỉ cho bạn cách đẩy cùng một trạng thái authorized_keys lên cả một hệ thống lớn.

Những điều không nên làm

  • Đừng dùng chung một private key cho tất cả các thiết bị của bạn. Nó khiến việc revoke một thiết bị bị mất trở nên bất khả thi nếu không phải thay thế key ở mọi nơi.
  • Đừng commit một private key vào git repository, kể cả repo private. Các scanner tự động luôn theo dõi các public repository và sẽ thử các key bị rò rỉ chỉ trong vài phút sau khi push, và một repository sau này bị công khai sẽ làm lộ toàn bộ lịch sử của nó.
  • Đừng upload private key của laptop lên một server để server đó có thể kết nối tới một server khác. Hãy generate một key riêng ngay trên chính server đó, và authorize key đó đúng nơi cần thiết.
  • Đừng paste một private key vào chat, email, hoặc một ticket. Public key, hay file .pub, là phần duy nhất được phép chia sẻ.

Khi key của bạn đã đăng nhập ổn định, hãy thực hiện bước tiếp theo là tắt password authentication, để các nỗ lực đoán password liên tục vào server của bạn không thể thành công. Cấu hình mẫu cho việc đó nằm trong SSH hardening trên một VPS.

FAQ

SSH keys hoạt động thế nào mà không cần gửi password?

Server giữ public key của bạn trong ~/.ssh/authorized_keys. Khi đăng nhập, nó gửi một challenge, client của bạn ký vào challenge đó bằng private key, và server xác minh chữ ký bằng public key. Private key không bao giờ rời khỏi thiết bị của bạn, vì vậy không có gì để bị chặn trên đường truyền và không có gì có thể tái sử dụng để đánh cắp từ server. Một server bị breach chỉ làm lộ các public keys, thứ mà không thể dùng để đăng nhập ở bất cứ đâu.

Tôi có nên dùng cùng một SSH key cho tất cả các server không?

Dùng một key cho nhiều server là đúng, miễn là key đó chỉ nằm trên một thiết bị duy nhất. Quy tắc là một key cho mỗi thiết bị, không phải một key cho mỗi server: public key của laptop sẽ nằm trên mọi server mà laptop cần, và desktop của bạn sẽ có key riêng. Điều này giữ cho việc revocation đơn giản, vì mất một thiết bị chỉ có nghĩa là xóa một dòng định danh khỏi mỗi server, và các thiết bị khác vẫn hoạt động bình thường.

.ssh directory và authorized_keys nên có permission thế nào?

Hãy set 700 cho ~/.ssh600 cho authorized_keys và cho mọi private key, thuộc sở hữu của account sử dụng chúng. sshd chạy với StrictModes yes mặc định, vì vậy một file hoặc home directory mà bất kỳ ai khác ngoài bạn có thể write sẽ khiến nó âm thầm ignore key của bạn, và dấu vết duy nhất là Authentication refused: bad ownership or modes trong auth log hoặc journal của server.

Làm thế nào để xóa một SSH key khỏi server?

Xóa dòng của key đó khỏi ~/.ssh/authorized_keys trong account mà nó được authorize. Tìm đúng dòng bằng comment của nó, nhãn nằm sau nội dung key. Các lần đăng nhập mới bằng key đó sẽ thất bại ngay lập tức, nhưng các session đang mở sẽ vẫn tiếp tục, vì vậy hãy kết thúc bất kỳ session trực tiếp nào của thiết bị đó nếu nó bị mất trộm. Lặp lại việc này trên mọi server mà key đó đã được copy sang.

Tôi có cần passphrase cho SSH key không?

Đối với một key trên laptop hoặc desktop, câu trả lời là có. Passphrase mã hóa file key, vì vậy một bản copy bị mất hoặc bị rò rỉ sẽ vô dụng, và ssh-agent có nghĩa là bạn chỉ cần gõ nó một lần cho mỗi session thay vì mỗi lần kết nối. Các key được dùng bởi automation không cần người can thiệp trên server thường không có passphrase, vì không có con người ở đó để gõ; hãy bảo vệ chúng bằng cách giới hạn những gì account mục tiêu có thể làm.