Skip to content
Latchkey

Ansible "Failed to connect to the host via ssh: Permission denied (publickey)" in CI

The SSH transport reached the host and offered keys, but none were accepted, so the server rejected the login with "Permission denied (publickey)". In CI this almost always means the deploy key is missing from the runner, unreadable, or sent for the wrong remote user.

What this error means

A task or the play setup fails with "fatal: [host]: UNREACHABLE!" or a connection error wrapping "Failed to connect to the host via ssh: ... Permission denied (publickey)". Public-key auth fails for every host in the play.

ansible
fatal: [web1]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the
host via ssh: ... Permission denied (publickey).", "unreachable": true}

Common causes

No private key loaded on the runner

The deploy key was never written to the job or added to an agent, so Ansible offers no key the host accepts.

Wrong remote_user for the key

The key authorizes one account but ansible_user or remote_user points at another, so the server denies the offered key.

How to fix it

Provide the key from a secret and set the user

  1. Store the private key as a CI secret, never in the repo.
  2. Write it to a file with 0600 perms and load it into ssh-agent, or pass --private-key.
  3. Set the matching ansible_user for the target inventory.
.github/workflows/ci.yml
- name: Load deploy key
  run: |
    install -m 600 /dev/stdin ~/.ssh/id_deploy <<< "${{ secrets.DEPLOY_KEY }}"
    eval "$(ssh-agent -s)" && ssh-add ~/.ssh/id_deploy
- run: ansible-playbook -i inventory site.yml -u deploy

Confirm the key and user against the host

Test the raw login first; if ssh -i key user@host is denied, Ansible will be too. Fix the user or authorized_keys before re-running the play.

Terminal
ssh -i ~/.ssh/id_deploy -o IdentitiesOnly=yes deploy@web1 true

How to prevent it

  • Keep deploy keys in CI secrets and write them with 0600 permissions.
  • Pin ansible_user per host group so the key matches the account.
  • Use IdentitiesOnly=yes so the agent does not offer unrelated keys.

Frequently asked questions

What causes ""Permission denied (publickey)""?
The deploy key was never written to the job or added to an agent, so Ansible offers no key the host accepts.
How do I fix "Permission denied (publickey)"?
Provide the key from a secret and set the user

Related guides

References

Latchkey auto-heals failures like this one - detected, fixed, and retried without you. Start free → 30-day trial · No credit card