It is best practice to use Ansible with SSH keys in order to create the SSH connections to the servers. This does require a little bit of extra setup before hand in order to ensure that the server can be reached by Ansible via SSH keys alone. As I have been doing this quite a lot recently I decided to package the setup steps into an Ansible playbook.
When you first set up a Linux server you will find that you are usually given root access, and it is up to you to configure it after the fact in order to have an administrator user with the correct access. With this root user we will use Ansible to log into the host, create a new user, setup SSH key access and then alter the sudoers file so that the new user can perform Ansible tasks.
Assuming that the host we want to configure has an IP address of 10.0.0.1 we can create an inventory file that looks like the following.
[hosts]
10.0.0.1 ansible_connection=ssh ansible_ssh_user=root ansible_ssh_pass=myrootpassword
As we don't have SSH key access we need to tell Ansible to use an alternative method. The ansible_ssh_user parameter tells Ansible which user to login as and ansible_ssh_pass tells Ansible what the users password is.
Those of you who know something about Ansible might wonder why you would pass the password to Ansilbe using the ansible_ssh_pass parameter and not the --ask-pass flag on the command line. The reason is that --ask-pass will only take in a single password and pass this to all hosts. This is fine if every host in your inventory file has the same root password, but I'm guessing that this is probably not the case. The idea here is that you can spend some time setting up your virtual machines and then plug them into this setup playbook in order to get them to a minimal level for Ansible provisioning. Once done you can continue on to your other playbooks to provision the Ansible hosts accordingly.
In order to use the ansible_ssh_pass parameter you first need to install the sshpass program. This allows you to send passwords to SSH commands, and Ansible utilises this program to send passwords to it's own connections. If you are on Ubuntu you can install sshpass like this.
sudo apt-get install sshpass
If you try to connect with Ansible now you might get an authentication failed message, even if the password is correct. This is because your local system is trying to ask if you want to store a key check of the host you are connecting to, which gets in the way of Ansible trying to connect. To disable the host key check you need to create a file called ansible.cfg (in the same folder as your inventory file) and add the following.
[defaults]
host_key_checking=false
The ansible.cfg file is automatically picked up by Ansible and is used to set certain Ansible configuration options. In this case we are turning off host key checking and allowing Ansible to connect to the host without asking if it should add the host key to the list of known hosts.
Before setting up the playbook you first need to create an ssh key that will be used to setup the connection. This can be done with the ssh-keygen command in the usual manner. Once created, place the key into the same directory as the Ansible script. Just remember not to commit them into any source control systems, especially if they are public repositories.
After this you are ready to create a setup playbook that will put the ssh key on the server. This playbook will run using the connection details in the hosts.ini file created above. This playbook will run through the following actions.
- Create a user on the remote host. The name of this user is defined at the top of the playbook as a variable.
- Set the password for the user created. This is mainly so this use has a full presence on the server and can also be used to test commands on the server before porting them back into Ansible playbooks. Again, the password is set using a variable at the top of the playbook.
- Use the authorized_key Ansible module to copy the public ssh key (kept in the same folder as the Ansible project) and place it on the server in the .ssh/authorized_keys file. After this step it is possible to connect to the server using the ssh keys alone. There is still one step left to do though.
- The final step is to allow the 'ansibleremote' user to complete 'sudo' actions on the remote host without needing to enter a password. We do this by adding a line to the /etc/sudoers file.
Here is the setup playbook in full.
---
- hosts: all
user: root
vars:
createuser: 'ansibleremote'
createpassword: 'myamazingpassword'
tasks:
- name: Setup | create user
command: useradd -m {{ createuser }} creates=/home/{{ createuser }}
sudo: true
- name: Setup | set user password
shell: usermod -p $(echo '{{ createpassword }}' | openssl passwd -1 -stdin) {{ createuser }}
sudo: true
- name: Setup | authorized key upload
authorized_key: user={{ createuser }}
key="{{ lookup('file', 'mypublickey.pub') }}"
path='/home/{{ createuser }}/.ssh/authorized_keys'
manage_dir=no
sudo: true
- name: Sudoers | update sudoers file and validate
lineinfile: "dest=/etc/sudoers
insertafter=EOF
line='{{ createuser }} ALL=(ALL) NOPASSWD: ALL'
regexp='{{ createuser }} ALL=(ALL) NOPASSWD: ALL'
state=present"
sudo: true
You can run this setup playbook using the following command.
ansible-playbook --inventory-file=hosts.ini setup.yml
Once complete you can now use the 'ansibleremote' user to run other Ansible playbooks and complete actions on hosts using the secure ssh keys. There are a few ways of using the ssh key connection, but one way is by referencing it in your hosts.ini file in the following way.
[default]
10.0.0.1 ansible_ssh_user=ansibleremote ansible_ssh_private_key_file=privatekey
Comments
Submitted by Murph on Thu, 07/10/2014 - 18:06
PermalinkSubmitted by Vlad on Mon, 07/28/2014 - 23:42
PermalinkSubmitted by giHlZp8M8D on Tue, 07/29/2014 - 09:23
PermalinkTASK: [Sudoers | update sudoers file and validate] **************************** fatal: [XX.XXX.X.X] => a duplicate parameter was found in the argument string (ALL) fatal: [127.0.0.1] => a duplicate parameter was found in the argument string (ALL) FATAL: all hosts have already failed -- aborting
Not been able to work out why so far. Thanks MikeSubmitted by Kimberlad on Mon, 08/04/2014 - 15:35
PermalinkSubmitted by AnneTheAgile on Mon, 08/04/2014 - 19:15
PermalinkSubmitted by giHlZp8M8D on Mon, 08/04/2014 - 22:06
Permalinkvars_prompt:
(http://docs.ansible.com/playbooks_prompts.html)Submitted by Dave on Mon, 08/18/2014 - 02:49
PermalinkSubmitted by Goll on Thu, 04/02/2015 - 19:40
PermalinkSubmitted by giHlZp8M8D on Wed, 04/08/2015 - 10:25
PermalinkSubmitted by tom on Thu, 01/07/2016 - 08:24
PermalinkSubmitted by giHlZp8M8D on Thu, 01/07/2016 - 09:13
PermalinkSubmitted by wekker on Wed, 03/02/2016 - 14:51
PermalinkSubmitted by Kevin on Wed, 10/25/2017 - 17:43
PermalinkReally like your stuff man, thanks for sharing
Submitted by ChrisFlafe on Fri, 07/02/2021 - 11:20
PermalinkAdd new comment