AnsibleVoici le sixième article de la formation Ansible. Dans mon précédent article, nous avons vu la gestion des variables de projet dans le shell. L’utilité de cet exposé quelque peu abstrait vous apparaîtra ici, étant donné que nous allons le mettre en application dans la configuration de base d’Ansible.

Organiser un projet Ansible

Placez-vous dans le répertoire du cinquième atelier pratique :

$ cd ~/formation-ansible/atelier-05

Voici les quatre machines virtuelles de cet atelier :

Machine virtuelle Adresse IP
ansible 10.23.45.10
rocky 10.23.45.20
debian 10.23.45.30
suse 10.23.45.40

Démarrez les VM :

$ vagrant up

Connectez-vous au Control Host :

$ vagrant ssh ansible

L’environnement de cet atelier est préconfiguré et prêt à l’emploi :

  • Ansible et direnv sont installés sur le Control Host.
  • Le fichier /etc/hosts du Control Host est correctement renseigné.
  • L’authentification par clé SSH est établie sur les trois Target Hosts.
$ type ansible direnv
ansible is /usr/bin/ansible
direnv is /usr/local/bin/direnv
$ ansible all -i debian,rocky,suse -m ping
rocky  | SUCCESS => ...
debian | SUCCESS => ...
suse   | SUCCESS => ...

AstuceLà encore, vous pouvez sereinement ignorer les avertissements concernant l’interpréteur Python sur l’un ou l’autre Target Host. Nous allons voir tout cela de plus près en temps et en heure.

En principe, Ansible ne nous impose pas vraiment de règles strictes quant à la structure des répertoires et des fichiers. Cela vous laisse pas mal de libertés pour organiser vos projets comme vous l’entendez. Ceci étant dit, voici deux recommandations utiles pour la suite :

  • Un projet Ansible se trouve idéalement à l’intérieur d’un seul et même répertoire, ce qui permet de le gérer avec un logiciel de gestion de versions comme Git.
  • Le travail au quotidien sur le Control Host se fait en tant qu’utilisateur non privilégié.

La deuxième exigence exclut d’emblée le répertoire /etc/ansible présent dans certaines distributions, notamment Rocky Linux. S’il est présent sur votre système, oubliez-le tout simplement :

$ ls -l /etc/ansible/
total 8
-rw-r--r--. 1 root root  614 Apr 21 08:02 ansible.cfg
-rw-r--r--. 1 root root 1175 Apr 21 08:02 hosts
drwxr-xr-x. 2 root root    6 Apr 21 08:02 roles

Un projet Ansible est constitué de plusieurs choses :

  • une configuration
  • un inventaire (inventory)
  • un ou plusieurs playbooks

Commençons par mettre en place une arborescence pour notre projet :

$ mkdir -pv ~/ansible/projets/ema
mkdir: created directory '/home/vagrant/ansible'
mkdir: created directory '/home/vagrant/ansible/projets'
mkdir: created directory '/home/vagrant/ansible/projets/ema'
$ cd $_

AstuceVous vous demandez peut-être ce que veut dire le $_ fourni en argument à cd. Sachez que la variable spéciale $_ contient l’argument fourni à la dernière commande dans le shell Bash.

Configuration de base

Nous allons utiliser Ansible avec une série de paramètres autres que ceux de la configuration fournie par défaut. Il nous faut donc éditer un fichier de configuration, et c’est là où les choses se compliquent un peu. En effet, Ansible va chercher son fichier de configuration à plusieurs endroits du système, par ordre de priorité croissant :

  • /etc/ansible/ansible.cfg
  • ~/.ansible.cfg
  • ansible.cfg dans le répertoire courant
  • l’emplacement correspondant au contenu de la variable d’environnement ANSIBLE_CONFIG

Voyons dans la pratique à quoi cela ressemble. La commande ansible --version nous permet d’afficher le fichier de configuration en vigueur :

$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /etc/ansible/ansible.cfg

Ce fichier fait visiblement partie de l’installation :

$ rpm -qif /etc/ansible/ansible.cfg | head -n 1
Name        : ansible-core

À présent, je crée un fichier caché .ansible.cfg dans mon répertoire utilisateur. Ce fichier peut être vide, peu importe. Ce qui m’intéresse, c’est l’incidence sur l’emplacement du fichier de configuration identifié par Ansible :

$ touch ~/.ansible.cfg
$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /home/vagrant/.ansible.cfg

J’en conclus que le fichier ~/.ansible.cfg aura la priorité sur /etc/ansible/ansible.cfg lorsque les deux sont présents sur le système.

Continuons cette petite expérience et créons un autre fichier ansible.cfg dans notre répertoire de projet :

$ cd ~/ansible/projets/ema/
$ touch ansible.cfg
$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /home/vagrant/ansible/projets/ema/ansible.cfg

Ici, mon fichier ~/ansible/projets/ema/ansible.cfg l’emporte visiblement sur les deux autres. Cette solution semble donc adaptée à première vue à notre projet. Tant que nous nous trouvons à la racine du projet, Ansible utilisera le fichier de configuration ansible.cfg propre au projet.

Le problème, c’est que ce fonctionnement n’est plus valable lorsque vous quittez le répertoire actuel. Dans ce cas, Ansible aura recours à un autre – voire aucun – fichier de configuration, ce qui n’est pas souhaitable :

$ mkdir -v playbooks
mkdir: created directory 'playbooks'
$ cd playbooks/
$ pwd
/home/vagrant/ansible/projets/ema/playbooks
$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /home/vagrant/.ansible.cfg

AstuceCertes, on aurait toujours la possibilité de rester cantonnés à la racine de notre projet pour invoquer toutes nos commandes, mais ce n’est pas toujours commode. La solution la plus élégante consiste ici à identifier notre fichier de configuration ansible.cfg grâce à la variable d’environnement ANSIBLE_CONFIG gérée par direnv.

Créez un fichier .envrc à la racine du projet, c’est-à-dire dans ~/ansible/projets/ema :

export ANSIBLE_CONFIG=$(expand_path ansible.cfg)

Autorisez l’utilisation de la variable d’environnement :

$ direnv allow
direnv: loading ~/ansible/projets/ema/.envrc
direnv: export +ANSIBLE_CONFIG

Dorénavant, le fichier ansible.cfg à la racine de votre projet sera correctement identifié même si vous changez de répertoire à l’intérieur de celui-ci :

$ pwd
/home/vagrant/ansible/projets/ema
$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /home/vagrant/ansible/projets/ema/ansible.cfg
$ cd playbooks/
$ pwd
/home/vagrant/ansible/projets/ema/playbooks
$ ansible --version | head -n 2
ansible [core 2.14.14]
  config file = /home/vagrant/ansible/projets/ema/ansible.cfg

Maintenant que nous sommes fixés sur l’emplacement du fichier ansible.cfg, voyons de plus près son contenu. Commençons par une simple directive au format INI qui définit l’emplacement de notre inventaire :

[defaults]
inventory = ./inventory

Utiliser les logs

La directive log_path permet de journaliser toutes les actions d’Ansible. Le fichier journal peut être choisi librement. En revanche, le répertoire censé contenir ce fichier doit exister :

$ mkdir -v ~/logs
mkdir: created directory '/home/vagrant/logs'

Partant de là, vous pouvez définir la journalisation dans ansible.cfg :

[defaults]
inventory = ./inventory
log_path = ~/logs/ansible.log

Faites un test pour vérifier si la journalisation s’effectue comme prévu :

$ ansible all -i rocky,debian,suse -m ping
...
$ cat ~/logs/ansible.log

Un premier inventaire

Un inventaire (inventory) indique à Ansible la liste des Target Hosts qu’il est censé gérer. Notre fichier de configuration ansible.cfg définit déjà un fichier inventory comme inventaire. Voici un premier jet de ce fichier, adapté à notre environnement labo :

[testing]
rocky
debian
suse

[testing:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=vagrant

Quelques remarques en vrac :

  • La syntaxe utilisée ressemble vaguement à un format INI.
  • Les noms entre crochets comme [testing] permettent de définir des groupes de cibles.
  • Rien ne vous oblige à définir des groupes, mais vous verrez que c’est une fonctionnalité pratique.
  • Le groupe spécial [all] contient toutes les cibles. Il existe toujours, même s’il n’a pas été défini explicitement.
  • Ici, nous avons paramétré le groupe [testing] avec l’ajout :vars. En l’occurrence, nous avons spécifié l’utilisation de Python 3.
  • La directive ansible_user définit le compte utilisateur avec lequel Ansible est censé se connecter à ses cibles.

Si tout se passe bien, notre ping ressemblera à ceci :

$ ansible all -m ping
debian | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
suse | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
rocky | SUCCESS => {
    "changed": false,
    "ping": "pong"
}

Au-delà du ping

Le ping constitue une première étape dans la configuration de nos cibles, mais ce n’est pas tout. Étant donné qu’il ne requiert pas de privilèges particuliers, nous n’en savons pas plus sur les droits d’accès nécessaires pour les tâches administratives diverses et variées. Faisons le test par l’exemple et demandons à Ansible d’exécuter une tâche qui requiert des droits d’accès élevés :

$ ansible all -a "head -n 1 /etc/shadow"
debian | FAILED | rc=1 >>
head: cannot open '/etc/shadow' for reading: Permission denied
rocky | FAILED | rc=1 >>
head: cannot open '/etc/shadow' for reading: Permission denied
suse | FAILED | rc=1 >>
head: cannot open '/etc/shadow' for reading: Permission denied

Dans notre environnement de labo, l’utilisateur vagrant peut avoir des droits sudo illimités sans mot de passe. Profitons-en et configurons une élévation des droits avec un seul paramètre supplémentaire :

[testing]
rocky
debian
suse

[testing:vars]
ansible_python_interpreter=/usr/bin/python3
ansible_user=vagrant
ansible_become=yes

Voyons ce que ça donne :

$ ansible all -a "head -n 1 /etc/shadow"
debian | CHANGED | rc=0 >>
root:!$y$j9T$1UCdnxq34BxNVM1P31I2R1$d6AgxFx72UvS6:0:99999:7:::
suse | CHANGED | rc=0 >>
root:!$6$Vkg2x/wlMzXkunYA$aeTVs1qXTe/Dmoo9unCiOxV:19728::::::
rocky | CHANGED | rc=0 >>
root:!!$6$xDTZIRLhFUOzp2Zh$MpRtbsOkz9Qvbxy1C2k9nj:19728:0:99999:7:::

Cette fois-ci, Ansible dispose bien des privilèges nécessaires pour s’acquitter de l’opération avec succès. Nous voilà prêts pour envoyer des vraies pépites de tâches administratives à Ansible.

Quittez le Control Host :

$ exit

Supprimez toutes les VM de l’atelier :

$ vagrant destroy -f

Exercice

Le moment est venu de faire un petit exercice récapitulatif. Placez-vous dans le répertoire du sixième atelier pratique :

$ cd ~/formation-ansible/atelier-06

Voici les quatre machines virtuelles Ubuntu 20.04 de cet atelier :

Machine virtuelle Adresse IP
control 10.23.45.10
target01 10.23.45.20
target02 10.23.45.30
target03 10.23.45.40

Démarrez les VM :

$ vagrant up

Connectez-vous au Control Host :

$ vagrant ssh control
  • Éditez /etc/hosts de manière à ce que les Target Hosts soient joignables par leur nom d’hôte simple.
  • Configurez l’authentification par clé SSH avec les trois Target Hosts.
  • Installez Ansible.
  • Envoyez un premier ping Ansible sans configuration.
  • Créez un répertoire de projet ~/monprojet.
  • Créez un fichier vide ansible.cfg dans ce répertoire.
  • Vérifiez si ce fichier est bien pris en compte par Ansible.
  • Spécifiez un inventaire nommé hosts.
  • Activez la journalisation dans ~/journal/ansible.log.
  • Testez la journalisation.
  • Créez un groupe [testlab] avec vos trois Target Hosts.
  • Définissez explicitement l’utilisateur vagrant pour la connexion à vos cibles.
  • Envoyez un ping Ansible vers le groupe de machines [all].
  • Définissez l’élévation des droits pour l’utilisateur vagrant sur les Target Hosts.
  • Affichez la première ligne du fichier /etc/shadow sur tous les Target Hosts.
  • Quittez le Control Host et supprimez toutes les VM de l’atelier.

Lire la suite : Commandes Ad-hoc


La rédaction de cette documentation demande du temps et des quantités significatives de café espresso. Vous appréciez ce blog ? Offrez un café au rédacteur en cliquant sur la tasse.

 

Catégories : Formation

0 commentaire

Laisser un commentaire

Emplacement de l’avatar

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *