Nowadays you can have your pick of tools that help you manage your infrastructure. The one mentioned in the paper, cfengine, is still around (albeit very different from the 1998 tool). And there's Puppet, Chef, Saltstack, ... to name but a few of the more popular ones.
Which one you use depends on a number of factors. Your manager may have fallen for a steak-and-strippers proposal. Or you absolutely want to use a specific programming language to write the tools (Ruby and Python are common). You want a server-agent setup or you want to work agentless. Today we're going to take a look at how to get up-and-running with Ansible.
![]() |
http://www.deviantart.com/art/setting-out-113310530 |
For my workstation I set up an Oracle Linux 7.3. (Windows is not an option for the workstation). There are several ways to install Ansible, I picked the Python pip method (because it works on most Linux distributions) :
sudo pip install ansible
That didn't work the first time round, the following packages were needed on my system : libffi-devel, python-devel, openssl-devel. Well, that's the downside of working with pip. I installed them and all was well.
sudo mkdir /etc/ansible
sudo chown <youruser>:<yourgroup> /etc/ansible
Note that I'm not using root. While a couple of sudo's are required to get started, ansible does not require root. Substitute <youruser> and <yourgroup> with whatever your user-with-sudo-permissions is. For the remainder of this post I'll assume it is ansible.
Ansible is agentless but it doesn't work by magic. It uses ssh as its primary means to connect to servers. So ... we're going to need a key.
[ansible@ansibleworkstation ~]$ ssh-keygen -t rsa
[ansible@ansibleworkstation ~]$ cd .ssh
[ansible@ansibleworkstation .ssh]$ cp id_rsa.pub authorized_keys
The last statement is the clue, we are going to need the public key we just generated put into the .ssh/authorized_keys file of the target user on every server that we want to manage.
Hold on. What is the target user ? Well, ansible is going to connect to the servers with ssh. Preferably not to the root user but to a user that can become another user (through sudo or other means, there are multiple options). The target user. For this post I'll assume it is also ansible, uses sudo to become another user and requires a password to execute sudo, but it can be any user you wish (we'll see further on how to define it).
The next step is to define the servers that we want to manage. As a reminder, each host mentioned below requires our public key in the .ssh/authorized_keys file of the target user !
[ansible@ansibleworkstation ~]$ vi /etc/ansible/hosts
ansibleworkstation ansible_ssh_user=ansible
athena ansible_ssh_user=ansible
As you can see we're also going to manage the workstation itself. To check if things are working we can do the following.
[ansible@ansibleworkstation ~]$ export ANSIBLE_HOST_KEY_CHECKING=False
[ansible@ansibleworkstation ~]$ ansible all -m ping
athena | SUCCESS => {
"changed": false,
"ping": "pong"
}
ansibleworkstation | SUCCESS => {
"changed": false,
"ping": "pong"
}
[ansible@ansibleworkstation ~]$ export ANSIBLE_HOST_KEY_CHECKING=True
That looks good. I set the ANSIBLE_HOST_KEY_CHECKING to False because this is the first time Ansible connects to the servers and they are not in our .ssh/known_hosts yet. Once the command runs they are added so that's covered now (unless you add a server or reinstall a server of course ... keeping the .ssh/known_hosts correct is needed to be able to run things without manual intervention).
Ok, Ansible has executed the ping on the servers as the target user. That's great, but most installations will require root-permissions.
[ansible@ansibleworkstation ~]$ vi /etc/ansible/hosts
ansibleworkstation ansible_ssh_user=ansible ansible_become_pass=XXX
athena ansible_ssh_user=ansible ansible_become_pass=YYY
[ansible@ansibleworkstation ~]$ ansible all -a "touch /var/tmp/touched" --sudo
ansibleworkstation | SUCCESS | rc=0 >>
athena | SUCCESS | rc=0 >>
[ansible@ansibleworkstation ~]$ ll /var/tmp/touched
-rw-r--r--. 1 root root 0 Dec 11 11:20 /var/tmp/touched
ansible@athena:~$ ll /var/tmp/touched
-rw-r--r-- 1 root root 0 Dez 11 11:20 /var/tmp/touched
That worked, but this way the /etc/ansible/hosts file will quickly become unwieldy. Lets fix that.
[ansible@ansibleworkstation ~]$ mkdir /etc/ansible/host_vars
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/ansibleworkstation
ansible_ssh_user: ansible
ansible_become_pass: XXX
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/athena
ansible_ssh_user: ansible
ansible_become_pass: YYY
[ansible@ansibleworkstation ~]$ vi /etc/ansible/hosts
ansibleworkstation
athena
Excellent. However, we do have those passwords in plaintext, don't we ? No way we can put /etc/ansible under version control unless we change that.
In a first step we are going to create a file that contains all the variables (those we want in plaintext and those we don't want in plaintext) for a specific host.
[ansible@ansibleworkstation ~]$ mv /etc/ansible/host_vars/athena /etc/ansible/host_vars/athena_vars
[ansible@ansibleworkstation ~]$ mv /etc/ansible/host_vars/ansibleworkstation /etc/ansible/host_vars/ansibleworkstation_vars
[ansible@ansibleworkstation ~]$ mkdir /etc/ansible/host_vars/athena
[ansible@ansibleworkstation ~]$ mkdir /etc/ansible/host_vars/ansibleworkstation
[ansible@ansibleworkstation ~]$ mv /etc/ansible/host_vars/ansibleworkstation_vars /etc/ansible/host_vars/ansibleworkstation/vars
[ansible@ansibleworkstation ~]$ mv /etc/ansible/host_vars/athena_vars /etc/ansible/host_vars/athena/vars
In a second step we are going to create a second file that contains only the variables that we don't want in plaintext and we are going to redirect to those variables from the vars file.
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/athena/vars
ansible_ssh_user: "{{ vault_ansible_ssh_user }}"
ansible_become_pass: "{{ vault_ansible_become_pass }}"
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/athena/vault
vault_ansible_ssh_user: ansible
vault_ansible_become_pass: YYY
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/ansibleworkstation/vars
ansible_ssh_user: "{{ vault_ansible_ssh_user }}"
ansible_become_pass: "{{ vault_ansible_become_pass }}"
[ansible@ansibleworkstation ~]$ vi /etc/ansible/host_vars/ansibleworkstation/vault
vault_ansible_ssh_user: ansible
vault_ansible_become_pass: XXX
And finally we encrypt the vault files (use the same password, having multiple vault-passwords is a pain).
[ansible@ansibleworkstation ~]$ ansible-vault encrypt /etc/ansible/host_vars/athena/vault
New Vault password:
Confirm New Vault password:
Encryption successful
[ansible@ansibleworkstation ~]$ ansible-vault encrypt /etc/ansible/host_vars/ansibleworkstation/vault
New Vault password:
Confirm New Vault password:
Encryption successful
Verify the vault files, no more plaintext and /etc/ansible is ready for version control ! This does require a change in how we execute the commands though.
[ansible@ansibleworkstation ~]$ ansible all -a "echo /var/tmp/touched" --sudo --ask-vault-pass
Vault password:
athena | SUCCESS | rc=0 >>
ansibleworkstation | SUCCESS | rc=0 >>
There, you are now all set up to securely execute Ansible commands. To conclude this post we're going to create an example Playbook (Ansible's name for a recipe/manifest/<whatever you call it>).
[ansible@ansibleworkstation ~]$ mkdir /etc/ansible/playbooks
[ansible@ansibleworkstation ~]$ vi /etc/ansible/playbooks/example.yml
---
- hosts: all
tasks:
- name: create /var/tmp/touched file
shell: echo "{{ ansible_bios_version }}" > /var/tmp/touched
[ansible@ansibleworkstation ~]$ ansible-playbook /etc/ansible/playbooks/example.yml --sudo --ask-vault-pass
Vault password:
PLAY [all] *********************************************************************
TASK [setup] *******************************************************************
ok: [ansibleworkstation]
ok: [athena]
TASK [create /var/tmp/touched file] ********************************************
changed: [athena]
changed: [ansibleworkstation]
PLAY RECAP *********************************************************************
ansibleworkstation : ok=2 changed=1 unreachable=0 failed=0
athena : ok=2 changed=1 unreachable=0 failed=0
[ansible@ansibleworkstation ~]$ ll /var/tmp/touched
-rw-r--r--. 1 root root 11 Dec 11 14:25 /var/tmp/touched
[ansible@ansibleworkstation ~]$ cat /var/tmp/touched
VirtualBox
ansible@athena:~$ ll /var/tmp/touched
-rw-r--r-- 1 root root 11 Dez 11 14:25 /var/tmp/touched
ansible@athena:~$ cat /var/tmp/touched
VirtualBox
The ansible_bios_version is a fact that Ansible gathers from the servers. There are many such facts, check them as follows
[ansible@ansibleworkstation ~]$ ansible all -m setup
And that concludes this blogpost. This is of course just the start of the journey with Ansible. Every journey starts with a first step though and I hope I helped with that.