Fix Ansible git Module 'Host key verification failed' When Cloning via SSH

intermediate๐Ÿ”ง Ansible2026-06-19| Ansible 2.9+, Ubuntu 20.04/22.04, Debian, RHEL/CentOS โ€” remote hosts cloning from GitHub, GitLab, Bitbucket, or private Git server via SSH

Error Message

fatal: [remote-host]: FAILED! => {"changed": false, "cmd": "/usr/bin/git clone ...", "msg": "Host key verification failed.\r\nfatal: Could not read from remote repository."}
#ansible#git#ssh#clone

The Error

fatal: [remote-host]: FAILED! => {"changed": false, "cmd": "/usr/bin/git clone ...", "msg": "Host key verification failed.\r\nfatal: Could not read from remote repository."}

This pops up when the Ansible git module tries to clone via SSH (git@github.com:... or ssh://...) but the remote server's host key isn't in ~/.ssh/known_hosts. Specifically, it checks the user running the task on the target machine โ€” not your control node.

SSH blocks connections to unknown hosts. Ansible runs non-interactively, so there's no prompt to accept the key โ€” it just fails hard.

Why This Happens

Most people assume the problem is on the Ansible control node. It isn't. The known_hosts check happens on the remote host โ€” the machine being configured. That server has never SSH'd to your Git server before, so it has no record of the host key.

Four scenarios trigger this consistently:

  • Fresh server provisioning โ€” first clone it's ever done
  • Switching from HTTPS to SSH clone URLs
  • Git server IP or key changed (GitHub rotated its RSA key in March 2023)
  • Running the task as a different user like deploy, who has no known_hosts yet

Fix 1: Pre-populate known_hosts with ssh-keyscan (Recommended)

Drop a task before your git task to scan and register the host key:

- name: Add GitHub to known_hosts
  ansible.builtin.known_hosts:
    name: github.com
    key: "{{ lookup('pipe', 'ssh-keyscan github.com') }}"
    state: present

- name: Clone repository
  ansible.builtin.git:
    repo: git@github.com:yourorg/yourrepo.git
    dest: /opt/app
    version: main

For GitLab or a private server, swap out github.com for your host:

- name: Add GitLab to known_hosts
  ansible.builtin.known_hosts:
    name: gitlab.example.com
    key: "{{ lookup('pipe', 'ssh-keyscan gitlab.example.com') }}"
    path: /home/deploy/.ssh/known_hosts
    state: present

The path parameter is easy to overlook. Omit it and Ansible defaults to /etc/ssh/ssh_known_hosts. But if your git task runs as deploy, that user's SSH client checks /home/deploy/.ssh/known_hosts instead. Always set path explicitly to match the user running the clone.

Fix 2: Use accept_hostkey (Quick but Deprecated)

Older Ansible versions had an accept_hostkey parameter directly on the git module:

- name: Clone repository
  ansible.builtin.git:
    repo: git@github.com:yourorg/yourrepo.git
    dest: /opt/app
    version: main
    accept_hostkey: yes  # deprecated in Ansible 2.12+

Ansible removed this in 2.12. If you're already seeing [DEPRECATION WARNING]: The 'accept_hostkey' argument is deprecated, migrate to Fix 1 now โ€” it'll stop working entirely in a future release.

Fix 3: Hard-code the Known Host Key

Running ssh-keyscan at task time makes a live network call. If you'd rather pin a specific key โ€” or if your environment blocks outbound SSH on port 22 โ€” grab the key once from your control node:

# On your control node:
ssh-keyscan github.com 2>/dev/null

Copy the output and embed it directly in your playbook:

- name: Add GitHub host key
  ansible.builtin.known_hosts:
    name: github.com
    key: "github.com ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOMqqnkVzrm0SdG6UOoqKLsabgH5C9okWi0dh2l9GkZH"
    state: present

GitHub publishes its official fingerprints on their SSH key fingerprints docs page โ€” verify the key there before pinning it in production.

Fix 4: SSH Config on the Remote Host (Last Resort)

When you control the remote machine and need a quick unblock, you can disable strict host checking via SSH config:

- name: Disable StrictHostKeyChecking for git server
  ansible.builtin.blockinfile:
    path: /home/deploy/.ssh/config
    create: yes
    mode: '0600'
    owner: deploy
    block: |
      Host github.com
        StrictHostKeyChecking no
        UserKnownHostsFile /dev/null

Restrict this to internal networks or isolated CI environments. StrictHostKeyChecking no silently accepts any host key โ€” including one from a MITM attacker. Don't use this in production.

Verify the Fix

SSH into the remote host and confirm the key landed:

# Check system-wide known_hosts
grep github.com /etc/ssh/ssh_known_hosts

# Or check user-level
grep github.com ~/.ssh/known_hosts

# Test the SSH connection directly
ssh -T git@github.com
# Expected: Hi username! You've successfully authenticated...

Re-run your playbook. The git task should clear without the host key error.

Tips

  • known_hosts path mismatch: The path matters a lot. Tasks running as root need the key in /root/.ssh/known_hosts or /etc/ssh/ssh_known_hosts. Tasks running as deploy need it in /home/deploy/.ssh/known_hosts. Always specify path explicitly in the known_hosts task โ€” don't let Ansible guess.
  • GitHub's 2023 RSA key rotation: GitHub replaced its RSA host key in March 2023. Hardcoded RSA keys from before that date will fail. Switch to the ED25519 key โ€” it hasn't changed and is more secure anyway.
  • Multiple Git servers: Collect all your known_hosts tasks into a shared role or a pre_tasks block. Every host gets prepped before any git clone runs.
  • CI/CD pipelines: If GitHub Actions or GitLab CI runs your Ansible playbooks, the runner hits the same problem. Add an ssh-keyscan step to your pipeline setup before invoking Ansible.
  • Private servers on non-standard ports: Use ssh-keyscan -p 2222 git.example.com and set name: "[git.example.com]:2222" in the known_hosts task โ€” the bracket notation is required.

Related Error Notes