Bootstrap FreeKB - Ansible - Resolve "UNREACHABLE failed to connect to the host via ssh permission denied"
Ansible - Resolve "UNREACHABLE failed to connect to the host via ssh permission denied"

Updated:   |  Ansible articles

If you attempt to make a connection to a target system and the SSH connection fails, the following will most likely be displayed. If you are not familiar with SSH, check out my article on Getting Started with SSH.

server1.example.com | UNREACHABLE! => {	
    "changed": false,
    "msg": "john.doe@server1.example.com Failed to connect to the host via ssh: Permission denied (publickey, password).",
    "unreachable": true 
}

 

SSH has a different authentication method, such as

  • Password authentication
  • Public/Private key authentication
  • gssapi

It's important to recognize that the SSH connection will be made as a certain user. In this example, since remote_user: john.doe is included, then the SSH authentication will be as john.doe.

---
- hosts: all
  remote_user: john.doe
  tasks:
  - file:
      path: /tmp/foo.txt
      state: touch
...

 

Or using --user. The --user option will take precedence over remote_user.

ansible-playbook example.yml --inventory hosts.yml --user jane.doe

 

Notice in this example that the SSH server can accept john.doe SSH key (publickey) or john.doe SSH password.

server1.example.com | UNREACHABLE! => {	
    "changed": false,
    "msg": "john.doe@server1.example.com Failed to connect to the host via ssh: Permission denied (publickey, password).",
    "unreachable": true 
}

 

Password authentication

If the SSH server is configured to accept password authentication, the following options can be used.

SSH key authentication

If the target servers are Linux systems, and OpenSSH is being used on the target servers, and OpenSSH on each target server is configured to allow PubkeyAuthentication, like this.

PubkeyAuthentication   yes
AuthorizedKeysFile     .ssh/authorized_keys

 

Then you should be able to make the SSH connection to the target using your SSH public key. In this scenario, the SSH public key being used will almost always reside in your /home/username/.ssh directory on the Ansible controller, something like this.

~]$ cat /home/john.doe/.ssh/id_rsa.pub 
ssh-rsa AAAAB.....SCVRn

 

The ssh-keygen command can be used to create your users private key (such as id_rsa) and public certificate (such as id_rsa.pub) on the Ansible control node. While you could use the openssh_keypair module or user module with the delegate_to: localhost parameter to create your users keypair, this usually doesn't make much since, since the generation of your users keypair is typically a one time task.

And the SSH key will need to be in the authorized_keys file on each target server.

~]$ cat .ssh/authorized_keys
ssh-rsa AAAAB.....SCVRn

 

It is also noteworthy that there are Ansible modules that can take care of some of this setup for you. Check out the next section of this article ("Preventing Permission denied") for more on this.

[root@control ~] ansible-playbook ssh.yml --ask-pass

 

If you are not root, you may need to use the become command line flags.

[john.doe@control ~] ansible-playbook ssh.yml --ask-pass --become --become-method=sudo --become-user=root --ask-become-pass

 

If you are connecting to a managed node as some other user, you may need to include remote_user in the playbook.

---
- hosts: aws
  remote_user: ec2-user
  tasks:
  - name: touch /tmp/foo.txt
    file:
      path: /tmp/foo.txt
      state: touch
...

 

After this has been done, then passwordless SSH connections can be made to the managed node without having to use the --ask-pass flag.

[root@control ~] ansible-playbook ssh.yml

 

Preventing Permission denied

In a real world scenario, you are probably going to be developing Ansible playbooks that will be used by other folks in your IT department. The other members of your IT department may not be familiar with Ansible, and if your playbook returns UNREACHABLE, the other members of your IT department may come to you stating your Ansible automation "is not working". Ultimately, this makes you look bad, makes you look like you developed automation that "doesn't work". For these reasons, I tend to use a bash shell script that tests the SSH connection to the target server, and if the SSH connection returns "Permission denied", I then try to automate appending the users public SSH key to the target servers authorized_keys file.

  • This uses the ssh command with the PasswordAuthentication=no option and redirects stderr to stdout using 2>&1 and exits the connection to see if the SSH connection returned "Permission denied"
  • If the SSH command returned "Permission denied" then the authorized_keys.yml playbook is invoked to append the users public SSH key to the authorized_keys file on the target server. Check out my article authorized_key for an example of what you could have in authorized_keys.yml.
#!/bin/bash
target_server="server1.example.com"
whoami=$(echo whoami)
remote_user="john.doe"

sshcmd=`ssh -o PasswordAuthentication=no $remote_user@$target_server 2>&1 "exit"`
result=$sshcmd

if [[ $result = *"Permission denied"* ]]; then
  ansible-playbook authorized_keys.yml --inventory $target_server, --user $whoami
fi

ansible-playbook main.yml $target_server, --user $whoami



Did you find this article helpful?

If so, consider buying me a coffee over at Buy Me A Coffee



Comments


Add a Comment


Please enter cbf57a in the box below so that we can be sure you are a human.