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 various authentication methods, 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 connection will be made 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. In this example, even though the Ansible playbook command was run by john.doe, since the --user jane.doe option was used, the SSH connection will be made as jane.doe.

[john.doe@server1 ~]$ ansible-playbook example.yml --inventory hosts.yml --user jane.doe

 

If the --user option and remote_user parameter were both not used, then the SSH connection will be made by the user running the Ansible playbook command, john.doe in this example.

[john.doe@server1 ~]$ ansible-playbook example.yml --inventory hosts.yml

 

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 OpenSSH is being used on the target servers, and OpenSSH on each target server is configured to allow PubkeyAuthentication, then you should be able to make the SSH connection to the target using an SSH public/private key pair. 

PubkeyAuthentication   yes
AuthorizedKeysFile     .ssh/authorized_keys

 

The ssh-keygen command can be used to create your users SSH private key (such as id_rsa) and SSH 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 the generation of your users keypair is typically a one-time task.

Notice that the SSH private key (id_rsa) is only readable and writable by john.doe in this example. This means that the Ansible playbook must be run as john.doe since only john.doe has permission to read the SSH private key file.

~]$ ls -lisa /home/john.doe/.ssh/
-rw-------. 1 john.doe users 1679 Apr 30 20:34 id_rsa
-rw-r--r--. 1 john.doe users  412 Apr 30 20:34 id_rsa.pub

 

If the example.yml playbook does not include remote_user then you would have to issue the ansible-playbook command as john.doe.

[john.doe@controller]$ ansible-playbook example.yml

 

Or you can run the ansible-playbook command as some other user with the --user option. But this will probably fail because this will use john.doe SSH private key such as /home/john.doe/.ssh/id_rsa and jane.doe probably doesn't (and shouldn't) have permission to read and use john.doe SSH private key.

[john.doe@controller]$ ansible-playbook example.yml --user jane.doe

 

In this scenario, you will almost always have to also include the --private-key option so that the SSH connection is made using jane.doe SSH private key.

[john.doe@controller]$ ansible-playbook example.yml --user jane.doe --private-key /home/jane.doe/.ssh/id_rsa

 

If the example.yml playbook does include remote_user: john.doe then you can issue the ansible-playbook command as some other user.

[jane.doe@controller]$ ansible-playbook example.yml

 

The SSH public certificate (id_rsa.pub) on the Ansible controller will need to be in the authorized_keys file on each target server.

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

~]$ cat /path/to/.ssh/authorized_keys <- target server
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 884a4c in the box below so that we can be sure you are a human.