Introduction to Ansible
I have a few different devices on my home network and I want to keep them up to date. This is great, but it takes too much time to update all of these devices as frequently as I would like to. To solve this problem, I want to automate that process. Looking through my options, ansible seemed like the way to go.
Ansible is an open-source IT automation platform built on top of python and run by Red Hat. It’s agentless, pretty simple to use, highly customizable, and leveraged by many enterprises to manage large numbers of devices. This last point gives an added bonus: on top of making life easier for my home environment, knowing how to use Ansible can be a good skill to have professionally as well.
Ansible uses “playbooks” for its automation scripts. In reality, a playbook is a YAML file that ansible will run through sequentially and determines the configurations for the actions it takes.
In this post, I’ll go over the process of installing and setting up ansible so you can start building your own playbooks. In my next post, I’ll walk through the playbook that I built to automate updating my homelab infrastructure.
Installing Ansible
Pre-Requisites
Installing Ansible is pretty simple, but there are a few pre-requisites to consider:
-
You’ll need to have python and its package manager,
pip
, installed. -
Windows is not natively supported as a control node (i.e. the device with ansible installed on it), so you’ll either need to use a machine running linux, or you’ll need to install and set up Windows Subsystem for Linux (WSL).
Installation
Now onto the actual installation. To do this in the most universal way, we’ll simply use pip
to install ansible. Open up your linux terminal (ex. bash) and run:
pip install ansible
Here are some other things you may need to do:
-
If you’re using WSL and get an error like
Error: Could not install packages due to an OSError: [WinError 206] The filename or extension is too long
, you can open the registry editor application, navigate toComputer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\FileSystem
, and setLongPathsEnabled
to1
instead of0
. -
If you get a warning during the install that says something like
WARNING: The scripts [...] are installed in <DIRECTORY NAME> which is not on PATH
, you can permanently add this folder to yourPATH
variable by adding the following lines to the end of your~/.bashrc
file#Add to the path for ansible scripts export PATH="$PATH:<DIRECTORY NAME>"
Make sure to replace
<DIRECTORY NAME>
with the directory in the warning. Then to apply this new setting, just runsource ~/.bashrc
Set Up the Environment
I authenticate to devices on my network using SSH keys. I decided that I wanted to give ansible its own SSH key that I would then distribute to all of my devices. You might decide that you want to just use password authentication, share your existing keys with ansible, or create a separate key for each device. All of these are totally valid options depending on your personal risk tolerance.
Here’s how I set up my key and distributed it.
Generate an SSH Key
Generate a new SSH key by running
ssh-keygen
Choose a filename and location for the key and give it a passphrase if you so wish. I saved my key as ~/.ssh/ansi
and gave it a strong passphrase using a password generator like this one.
This will create two files. The one that we specified is the private key. Additionally, a file in the same directory with the same name and a .pub
extension will be created (for me, ~/.ssh/ansi.pub
). This is our public key. If we run cat <path to public key>
, it will show us the public key. It should look like this
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCvH+GMBogxYe/xKrE3apC7yWHQFjpb47Yssy[...]
We’ll copy this whole thing to a notes file for the next step.
Distribute the Key to the Devices
Now it’s just a matter of getting this new key to the devices we want to manage.
To do this, you can either use ssh-copy-id
or manually log into your device (using whatever method you’d prefer) and add the public key you wrote down earlier to the end of the appropriate ~/.ssh/authorized_keys
file. I just added the key to the default user on each of my devices, but feel free to create a new user specifically for ansible if you’d prefer. Linux Handbook has a good how-to on all of this if you’re new to it.
Repeat the process for all of the devices you want to manage with Ansible.
Ansible Connection Test
Now we’ll make sure everything’s working. To do that, we’ll set up a connection test.
Set Up the Inventory File
First, we need to create an inventory of the devices we want to test a connection to.
Start by creating a new directory
mkdir ansible_connection_test
move into that directory
cd ansible_connection_test
and start a new file called inventory.ini
nano inventory.ini
We’ll create a group of hosts called hosts
and list all of the devices we want to test under it, along with the name of the user that we added the SSH key to earlier. The file should look like this
[hosts]
server1.local ansible_user=server1_user
server2.local ansible_user=server2_user
server3.local ansible_user=server3_user
...
Run the Test
Now we can run our connection test.
We’ll start by firing up ssh-agent
so we don’t have to specify the private key and passphrase over and over again. Run
eval `ssh-agent -s`
Then we’ll add our private key file to ssh-agent
ssh-add '<path to private key>'
Enter the passphrase for the key if you set one.
Now, to run our connection test all we need to do is run
ansible hosts -m ping -i inventory.ini
Note: If you get any warnings saying that the authenticity of a host can’t be established, just type “yes” and continue on. If you have multiple hosts, you may have to type this multiple times and it may break ansible’s output formatting a bit. Saying “yes” here will add these hosts to a known hosts file on your device so it won’t be asked about again.
We should get back something like this (one of these per device we’re testing)
server01.local | SUCCESS => {
"ansible_facts": {
"discovered_interpreter_python": "/usr/bin/python3"
},
"changed": false,
"ping": "pong"
}
Setting up a Vault for Secure Variables
Some of my devices require a password in order to elevate privileges. Of course, updating a system requires elevated privileges. As a result, I need to include those passwords in my ansible configuration somehow. However, I don’t want to include them in plaintext on my disk for security reasons. At the same time, I don’t want to be bothered with typing in those passwords each time. Instead, what I can do is set up an ansible vault. Ansible vault lets us encrypt sensitive data when not in use.
Our vault needs to be saved to a specific location to be used. Start with your terminal in the directory where you’ll ultimately want to save your playbook.
Now we’ll create some new directories
mkdir group_vars
cd group_vars
mkdir all
cd all
This will set up this directory structure
├───<playbook_dir>
└───group_vars
└───all
We should now be in the all
directory. To set up our vault, we’ll run
ansible-vault create vault.yml
After we set up our vault password it will open up a text editor (by default, vi
, though this can be changed by setting an EDITOR
environment variable) where we can then enter our sensitive variables into the vault using YAML syntax. The syntax should look like this
variable_name_1: value1
variable_name_2: value2
...
Now we can use this vault to include these sensitive variables in our ansible configuration files. In our desired case of adding sudo (or “become”) passwords for ansible to use, we can add the ansible_become_pass
variable to the line for for the device in our inventory using templating, like this
[hosts]
server1.local ansible_user=server1_user ansible_become_pass='{{variable_name_1}}'
Now when we run our ansible playbook ansible will use our vault to dynamically insert the sudo password into the inventory. We just need to make sure to pass our ansible command the --ask-vault-pass
flag so it can prompt us for the password to decrypt the vault.
Conclusion
From here, we can start to create playbooks. In my next post, I’ll walk through the playbook that I created to update my homelab infrastructure.