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.
- --ask-pass command line flag
- configure the default hosts file with your SSH username and password
- Use the ansible-vault create command to create a file that contains an encrypted version of your SSH password and and then use the --vault-password--file or --vault-id command line option
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