Ansible

From
www.ansible.com
:
Ansible is a radically simple IT automation engine that automates cloud provisioning, configuration management, application deployment, intra-service orchestration, and many other IT needs.
Installation
On the control machine (master),
install
the
ansible-core
package. Additionally, you can install the
ansible
package, which provides a range of community curated collections.
On the managed machines (nodes),  where you want to automate deployment or configuration tasks,
python
is required and it may be necessary to indicate the specific
#Python binary location
in some circumstances.  A way to communicate with the node is also necessary, this is usually
SSH
. Note that a functioning
SSH key
setup eases the use of Ansible but is not required.
Tip
You may want to install syntax highlighting of Ansible files (e.g.
vim-ansible
for
vim
)
Basic usage
Configuration
Ansible parameters are set in the configuration file which can either be
ansible.cfg
in the current directory,
.ansible.cfg
in the home directory or
/etc/ansible/ansible.cfg
, whichever it finds first.
A base config can be generated with:
$ ansible-config init --disabled > ansible.cfg
Inventory
The infrastructure is listed in the Ansible inventory file, which defaults to being saved in the location
/etc/ansible/hosts
or one can specify a different inventory file using the
-i
command line switch. For instance, the following inventory defines a cluster with 7 nodes organized into two groups:
/etc/ansible/hosts
[control]
192.168.12.1
foo-[a:c].example.org
localhost ansible_connection=local

[managed]
192.168.12.2
192.168.12.3
One can assign specific attributes to every node in the infrastructure file at the corresponding line or in the
ansible.cfg
configuration file.
By default Ansible executes playbooks over SSH, the
ansible_connection
parameter extends the connection to:
local
to deploy the playbook to the control machine itself
docker
deploys the playbook directly into Docker containers
Check
Ansible - intro inventory
for details.
Ping
You may check if all the nodes listed in the inventory are alive by
$ ansible all -m ping
Playbook
Playbooks are the main organizational unit to configure and deploy the whole infrastructure.  Check
the official document
for more details.  Here is an extremely simple demonstration, where the administrator of the above inventory wants to perform a full system upgrade on a set of Arch Linux hosts. First, create a playbook file, with YAML formatting (
always
2 spaces indentation):
syu.yml
---
- name: All hosts up-to-date
  hosts: control managed
  become: true

  tasks:
    - name: Full system upgrade
      community.general.pacman:
        update_cache: true
        upgrade: true
Then, run the playbook script:
$ ansible-playbook --ask-become-pass syu.yml
Vault
A
vault
can be used to keep sensitive data in an encrypted form in playbooks or roles, rather than in plaintext.  The vault password can be stored in plaintext in a file, for example
vault_pass.txt
containing
myvaultpassword
, to be used later on as a command parameter:
$ ansible-playbook
site.yml
--vault-id
vault_pass.txt
In order to encrypt the content
the var content
of a variable named
varname
using the password stored in
vault_pass.txt
, the following command should be used:
$ ansible-vault encrypt_string --vault-id
vault_pass.txt
'
the var content
' --name
varname
More securely, to avoid inputting the variable content in the command line and be prompted for it instead, one can use:
$ ansible-vault encrypt_string --vault-id
vault_pass.txt
--stdin-name
varname
Reading plaintext input from stdin. (ctrl-d to end input)
The command returns directly the protected variable that can be inserted into a playbook. Encrypted and non-encrypted variables can coexist in a YAML file as illustrated below:
notsecret: myvalue

mysecret: !vault |
          $ANSIBLE_VAULT;1.1;AES256
          66386439653236336462626566653063336164663966303231363934653561363964363833313662
          6431626536303530376336343832656537303632313433360a626438346336353331386135323734
          62656361653630373231613662633962316233633936396165386439616533353965373339616234
          3430613539666330390a313736323265656432366236633330313963326365653937323833366536
          3462

other_not_secret: othervalue
Package management
Official repositories
Ansible has a
pacman module
(provided by the
ansible
package) to handle installation, removal and system upgrades with
pacman
.
AUR
For the
Arch User Repository
(AUR)
, it is required to use the external module
ansible-aur
. See the README for use and installation instructions.
While Ansible expects to ssh as root, AUR helpers do not allow executing operations as root, they all fail with "you cannot perform this operation as root". For Ansible automation, it is therefore recommended to create a user, for example named
aur_builder
, that has no need for password with pacman in
sudoers
. This can be done in Ansible with the following actions:
task.yml
- user: name=
aur_builder
- lineinfile:
     path: /etc/sudoers.d/
aur_builder-allow-to-sudo-pacman
state: present
     line: "
aur_builder
ALL=(ALL) NOPASSWD: /usr/bin/pacman"
     validate: /usr/sbin/visudo -cf %s
     create: yes
Then, AUR helpers or
makepkg
can be used associated with the Ansible parameters
become: yes
and
become_user: aur_builder
Tips and tricks
User account creation
Ansible can manage user accounts and in particular it is able to create new ones. This is achieved in playbooks with the
user module
which takes an optional
password
argument to set the user's password. It is the
hashed value of the password
that needs to be provided to the module.
The hashing can simply be performed on the fly within Ansible using one of its internal
hash-filters
:
- user:
  name:
user_name
password: "{{ '
user_password
' | password_hash('sha512', '
mypermsalt
') }}"
  shell: /usr/bin/nologin
Tip
The salt should be fixed and explicitly supplied as a second parameter of the hash function for the operation to be idempotent (can be repeated without changing the state of the system).
With this approach it is recommended to vault-encrypt
user_password
so that it does not appear in plain text, see
#Vault
. However, an encrypted variable cannot be piped directly and will first need to be assigned to another one that will be piped.
Alternatively, the hashing can be performed outside Ansible. The following commands return respectively the
MD5
and the
SHA512
hashed values of
user_password
:
$ openssl passwd -1
user_password
$ python -c 'import crypt; print(crypt.crypt("
user_password
", crypt.mksalt(crypt.METHOD_SHA512)))'
Python binary location
Ansible requires
Python
on the target machine. By default Ansible assumes it can find a
/usr/bin/python
on the remote system that is a 2.X or 3.X version, specifically 2.6 or higher.
If some of your modules specifically require Python2, you need to inform Ansible about its location by setting the
ansible_python_interpreter
variable in the inventory file. This can be done by using host groups in the inventory:
/etc/ansible/hosts
[archlinux]
server1
server2

[debian]
server3

[archlinux:vars]
ansible_python_interpreter=/usr/bin/python2
More information about Python version support in Ansible is available in
[1]
,
[2]
and
[3]
.
Troubleshooting
Unarchive
The
unarchive
module unpacks an archive. However
tar
files are not well supported and several outstanding issues are reported in
GitHub - unarchive
. In particular when the parameter
keep_newer
is set to
yes
, idempotence is not observed. In case you face an issue with the module, you can use instead the
zip
format which is better integrated in Ansible.
See also
https://www.ansible.com/resources/videos/quick-start-video
- Ansible concept in 12 minutes
https://docs.ansible.com/ansible/latest/collections/community/general/pacman_module.html
- Official documentation of the pacman module