Lỗi Xảy Ra
Bạn chạy lệnh SSH — kết nối đến server từ xa, clone repo Git, hoặc deploy code — và nhận được thông báo này:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for 'id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "/c/Users/YourName/.ssh/id_rsa": bad permissions
Permission denied (publickey).
SSH từ chối đọc key. Kết nối chết ngay lập tức.
OpenSSH kiểm tra quyền file trước khi nạp bất kỳ private key nào. Nếu một tài khoản khác có thể đọc được file đó, SSH coi key đã bị lộ và từ chối tiếp tục. Trên Linux, một lệnh là xong: chmod 600 ~/.ssh/id_rsa. Windows dùng NTFS ACL thay vì Unix permission bits, nên cách sửa có khác đôi chút.
Nguyên Nhân Trên Windows
Việc sao chép private key vào Windows thường là lúc mọi thứ đi sai hướng. Dù file đến từ download, USB hay máy khác, nó thường kế thừa quyền từ thư mục cha. Điều đó có nghĩa là nhóm Users, SYSTEM và Administrators đều có thể đọc file. OpenSSH nhìn thấy điều đó và từ chối nạp key.
Sửa Bằng icacls Trong PowerShell
icacls là công cụ phù hợp cho việc này. Mở PowerShell (không cần quyền admin) và chạy:
# Điều chỉnh đường dẫn nếu key của bạn ở nơi khác
$key = "$env:USERPROFILE\.ssh\id_rsa"
# Bước 1: Xóa tất cả quyền được kế thừa
icacls $key /inheritance:r
# Bước 2: Xóa quyền của các nhóm rộng
icacls $key /remove "NT AUTHORITY\SYSTEM"
icacls $key /remove "BUILTIN\Administrators"
icacls $key /remove "BUILTIN\Users"
# Bước 3: Cấp quyền đọc chỉ cho tài khoản của bạn
icacls $key /grant:r "${env:USERNAME}:R"
Chạy theo thứ tự. Mỗi lệnh loại bỏ một lớp quyền — lệnh cuối thêm lại quyền của bạn, chỉ đọc.
Phiên bản một dòng
Muốn gộp lại một dòng? Nối tất cả lại với nhau:
icacls "$env:USERPROFILE\.ssh\id_rsa" /inheritance:r /remove "NT AUTHORITY\SYSTEM" /remove "BUILTIN\Administrators" /remove "BUILTIN\Users" /grant:r "${env:USERNAME}:R"
Cách Thay Thế: Dùng PowerShell ACL Objects
icacls đủ dùng cho hầu hết trường hợp. Nếu bạn đang viết script thiết lập máy hoặc cần kiểm soát chi tiết hơn, bạn có thể dùng trực tiếp các lớp System.Security.AccessControl của .NET:
$key = "$env:USERPROFILE\.ssh\id_rsa"
# Nạp ACL hiện tại
$acl = Get-Acl $key
# Vô hiệu hóa kế thừa và xóa các mục được kế thừa
$acl.SetAccessRuleProtection($true, $false)
# Xóa tất cả quy tắc truy cập hiện có
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) }
# Thêm quy tắc: người dùng hiện tại chỉ được đọc
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
$env:USERNAME, "Read", "Allow"
)
$acl.AddAccessRule($rule)
# Áp dụng ACL đã cập nhật lại cho file
Set-Acl -Path $key -AclObject $acl
Write-Host "Đã cập nhật quyền cho $key"
Sửa Qua Giao Diện Đồ Họa (File Explorer)
Không muốn dùng dòng lệnh? File Explorer cũng làm được:
- Chuột phải vào
id_rsatrong File Explorer → Properties - Chuyển sang tab Security → nhấp Advanced
- Nhấp Disable inheritance → chọn Remove all inherited permissions
- Nhấp Add → Select a principal → nhập tên tài khoản Windows của bạn → OK
- Chỉ chọn Read → OK → Apply
Sau khi xong, chỉ tài khoản của bạn mới xuất hiện trong danh sách quyền.
Kiểm Tra Kết Quả
Trước khi thử SSH, xác nhận ACL trông đúng chưa:
icacls "$env:USERPROFILE\.ssh\id_rsa"
Bạn muốn chỉ thấy tên người dùng của mình:
C:\Users\YourName\.ssh\id_rsa YourName:(R)
Successfully processed 1 files; Failed processing 0 files
Giờ thử kết nối:
ssh -T git@github.com
Hoặc kết nối trực tiếp đến server của bạn:
ssh -i ~/.ssh/id_rsa user@your-server.com
Không còn cảnh báo nữa. Nếu SSH vẫn thất bại lúc này, đó sẽ là lỗi xác thực — không phải lỗi quyền — có nghĩa là key đã được nạp thành công.
Sửa Cho Người Dùng Git Bash / WSL
Bên trong WSL hoặc Git Bash, nếu key nằm trong filesystem WSL, chmod hoạt động bình thường:
# Bên trong WSL hoặc Git Bash
chmod 600 ~/.ssh/id_rsa
chmod 700 ~/.ssh
Truy cập key theo đường dẫn Windows từ WSL (như /mnt/c/Users/YourName/.ssh/id_rsa)? chmod sẽ không ảnh hưởng đến NTFS ACL. Dùng icacls từ cửa sổ PowerShell cho những trường hợp đó.
Áp Dụng Cho Tất Cả Key Cùng Lúc
Có nhiều private key trong thư mục .ssh? Sửa tất cả trong một lần:
Get-ChildItem "$env:USERPROFILE\.ssh" -File | Where-Object { $_.Name -notmatch '\.pub$|config|known_hosts' } | ForEach-Object {
$path = $_.FullName
icacls $path /inheritance:r /remove "NT AUTHORITY\SYSTEM" /remove "BUILTIN\Administrators" /remove "BUILTIN\Users" /grant:r "${env:USERNAME}:R"
Write-Host "Đã sửa: $path"
}
Lưu Ý
- Đặt quyền ngay khi tạo key. Chạy
ssh-keygentrên Windows sẽ tự động đặt ACL đúng. Vấn đề hầu như luôn xuất phát từ việc sao chép key giữa các máy. - Giữ key trong thư mục profile của bạn. Các thư mục dùng chung hoặc thư mục hệ thống liên tục kéo theo quyền rộng. Hãy dùng
C:\Users\YourName\.ssh\. - Chuyển đổi quyền giữa các nền tảng. Nếu bạn làm việc cả trên Windows lẫn Linux và cần hiểu
chmod 600tương ứng với ACL như thế nào, Unix Permissions Calculator trên ToolCraft trực quan hóa điều đó — chạy hoàn toàn trên trình duyệt, không gửi dữ liệu đi đâu. - Public key không cần quyền chặt.
id_rsa.pubđể đọc được là ổn. Nhưng nhân thể, hãy xác nhận toàn bộ thư mục.sshchỉ thuộc về tài khoản của bạn.

