Sửa lỗi 'Permission denied (publickey)' SSH trong Ansible khi kết nối đến Remote Hosts

beginner🔧 Ansible2026-05-20| Ansible 2.9+, Ubuntu/Debian/CentOS/RHEL, OpenSSH, Linux control node

Error Message

Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic)
#ssh#publickey#xác thực#private-key#ansible-ssh

Chuyện gì đang xảy ra

Bạn chạy một playbook hoặc ansible -m ping và nhận được thông báo này:

fatal: [192.168.1.10]: UNREACHABLE! => {
    "changed": false,
    "msg": "Failed to connect to the host via ssh: Permission denied (publickey,gssapi-keyex,gssapi-with-mic)",
    "unreachable": true
}

Ansible đã gửi SSH key của mình. Máy chủ từ chối. Không có gì được thực thi.

Lưu ý rằng đây không phải là lỗi timeout — máy chủ từ xa vẫn đang hoạt động, nó chỉ từ chối key. Trong khoảng 90% trường hợp, nguyên nhân là một trong bốn thứ: sai đường dẫn key, key không có trong authorized_keys, sai remote user, hoặc quyền truy cập file bị lỗi trên key hoặc thư mục .ssh.

Quy trình debug

Bước 1: Kiểm tra SSH thủ công trước

Tạm gác Ansible sang một bên và kiểm tra kết nối SSH trực tiếp:

ssh -i /path/to/private_key ansible_user@192.168.1.10

Nếu lệnh này cũng thất bại, vấn đề nằm ở SSH chứ không phải Ansible. Hãy sửa SSH trước và Ansible sẽ tự hoạt động được.

Vẫn bí? Thêm -v để xem chính xác xác thực bị lỗi ở đâu:

ssh -v -i /path/to/private_key ansible_user@192.168.1.10

Tìm trong output những dòng như sau:

debug1: Offering public key: /path/to/private_key
debug1: Authentications that can continue: publickey
Permission denied (publickey).

Bước 2: Chạy Ansible với output chi tiết

ansible all -m ping -vvv

-vvv in ra chính xác lệnh SSH mà Ansible tạo ra nội bộ. Bạn sẽ thấy nó đang tải key nào, kết nối với user nào, và đang dùng port nào.

Bước 3: Kiểm tra inventory của bạn

cat inventory.ini

Xác nhận rằng các biến này đã được thiết lập:

[webservers]
192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=~/.ssh/id_rsa

Nguyên nhân phổ biến và cách khắc phục

Nguyên nhân 1: Sai hoặc thiếu đường dẫn private key

Ansible không thể tìm thấy — hoặc không thể đọc — private key mà bạn đã chỉ định.

Khắc phục: Xác nhận key tồn tại và có quyền sở hữu đúng:

ls -la ~/.ssh/id_rsa
# Should show: -rw------- 1 youruser youruser

Sau đó thiết lập đường dẫn trong ansible.cfg:

# ansible.cfg
[defaults]
private_key_file = ~/.ssh/id_rsa

Hoặc theo từng host trong inventory:

192.168.1.10 ansible_user=ubuntu ansible_ssh_private_key_file=/home/youruser/.ssh/deploy_key

Nguyên nhân 2: Public key không có trong authorized_keys trên máy chủ từ xa

Public key của bạn đơn giản là không có ở đó. Máy chủ từ xa không biết bạn là ai.

Khắc phục: Đẩy key lên bằng một lệnh duy nhất:

ssh-copy-id -i ~/.ssh/id_rsa.pub ansible_user@192.168.1.10

Chưa có quyền truy cập bằng mật khẩu? Thêm thủ công trên máy từ xa:

mkdir -p ~/.ssh
chmod 700 ~/.ssh
echo "your-public-key-content" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keys

Nguyên nhân 3: Quyền file sai trên key hoặc thư mục .ssh

SSH âm thầm loại bỏ các key có quyền truy cập quá rộng. Nó sẽ không thông báo "bị bỏ qua do quyền truy cập" — mà chỉ nói "permission denied" rồi tiếp tục. Rất khó chịu.

Khắc phục: Giới hạn quyền truy cập trên control node:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/id_rsa
chmod 644 ~/.ssh/id_rsa.pub

Làm tương tự trên máy từ xa:

chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys

Nếu bạn hay nhầm lẫn giữa 600 và 644, Unix Permissions Calculator tại ToolCraft cho phép bạn click vào các bit quyền và nhận ngay giá trị số chính xác.

Nguyên nhân 4: Sai remote user

Mặc định Ansible kết nối bằng tên người dùng local của bạn. Trên máy chủ Ubuntu mới thì user đó là ubuntu, trên Amazon Linux là ec2-user, trên CentOS là centos — tên người dùng local của bạn gần như chắc chắn không phải bất kỳ cái nào trong số đó.

Khắc phục: Thiết lập user một cách tường minh. Chọn cấp độ phù hợp với bạn:

# In inventory
192.168.1.10 ansible_user=ubuntu

# Or in ansible.cfg
[defaults]
remote_user = ubuntu

# Or per-play in the playbook
- hosts: webservers
  remote_user: ubuntu

Nguyên nhân 5: SELinux hoặc StrictModes chặn key

Trên RHEL/CentOS, SELinux có thể ngăn SSH đọc authorized_keys ngay cả khi quyền file trông có vẻ đúng. Nhãn bị sai, không phải các bit mode.

Khắc phục: Khôi phục SELinux context:

restorecon -Rv ~/.ssh

Cũng kiểm tra /etc/ssh/sshd_config trên máy từ xa xem có StrictModes yes không — cài đặt đó áp dụng kiểm tra quyền truy cập cho ~/.ssh và mọi thứ bên trong.

Nguyên nhân 6: SSH agent chưa được tải hoặc có key sai

Khi bạn không chỉ định file key, Ansible lấy bất kỳ key nào hiện đang có trong SSH agent của bạn. Nếu bạn đã tải personal key nhưng máy chủ lại mong đợi deploy key, xác thực sẽ thất bại — và lỗi trông y hệt nhau.

Khắc phục: Xem những gì đang thực sự được tải:

ssh-add -l

Tải đúng key:

ssh-add ~/.ssh/deploy_key

Hoặc yêu cầu Ansible bỏ qua agent hoàn toàn và dùng một key cụ thể:

[ssh_connection]
ssh_args = -o ForwardAgent=no

Ví dụ hoàn chỉnh

Đây là thiết lập tối giản từ đầu đến khi có kết nối Ansible hoạt động:

# 1. Generate a new ed25519 key pair
ssh-keygen -t ed25519 -f ~/.ssh/ansible_key -N ""

# 2. Push the public key to the remote host
ssh-copy-id -i ~/.ssh/ansible_key.pub ubuntu@192.168.1.10

# 3. Verify raw SSH works before involving Ansible
ssh -i ~/.ssh/ansible_key ubuntu@192.168.1.10 exit
echo "Exit code: $?"  # Must be 0

# 4. Write the inventory
cat > inventory.ini  {
    "changed": false,
    "ping": "pong"
}

Đang quản lý nhiều máy chủ? Kiểm tra tất cả cùng lúc với lệnh gọn hơn:

ansible all -i inventory.ini -m ping --one-line

Bài học rút ra

  • Kiểm tra SSH trước khi động vào Ansible. ssh -v -i key user@host cho bạn biết mọi thứ trong 3 giây. Nếu lệnh đó thất bại, Ansible không có cơ hội nào.
  • Quyền truy cập thất bại trong im lặng. SSH loại bỏ các key có quyền sai mà không thông báo gì hữu ích. Luôn chạy chmod 600 trên private key và chmod 700 trên thư mục .ssh — cả trên control node lẫn máy từ xa.
  • Khai báo tường minh trong inventory. Khai báo ansible_useransible_ssh_private_key_file cho mọi nhóm host. Dựa vào giá trị mặc định là cách lỗi này xuất hiện ba tháng sau khi ai đó chạy Ansible từ máy khác.
  • Dùng ed25519 cho key mới. Ngắn hơn, nhanh hơn, và không có vấn đề tương thích so với RSA-1024 hay RSA-2048.

Related Error Notes