TUTOS.EU

Première exemple d'utilisation de Ansible de A à Z


Cet article est là pour vous permettre d'avoir un premier exemple fonctionnel d'Ansible.

Il a été écrit après avoir visionné plusieurs des 127 vidéos de la playlist dédiée de xavki (trop long de tout regarder pour un premier essai),

Découverte de Ansible (très bien, un exemple de fou, des idées sur ce qu'on peut en faire, mais il manque du détail si on veut appliquer from scratch),

you need to learn ansible right now de NetworkChuck (bien mais il se connecte avec un login/mot de passe d'un compte root de base)

et une partie du getting_started de ansible.com


Le serveur Ansible s'installe obligatoirement sur une machine Linux.

Au niveau des prérequis, on va commencer par faire le nécessaire sur une machine cible qui sera gérée par Ansible.

Ansible fonctionnant sans agent, il faut que son compte ait les droits dessus.
On va y créer un compte dédié.

Donc sur une machine cible, avec les commandes suivantes, on passe root et on crée le compte que va utiliser Ansible.

sudo -i
useradd -m myaccount4ansible
passwd myaccount4ansible
Lien vers le fichier : cliquez ici Copier le code

Toujours sur la machine cible, on va donner les droits sudo à ce compte, sans qu'il ait à saisir un mot de passe pour cela.

Pour ce faire on va créer un fichier nommé admin sous /etc/sudoers.d avec nano

nano /etc/sudoers.d/admins
Lien vers le fichier : cliquez ici Copier le code

Mettez y ceci

myaccount4ansible     ALL=(ALL)   NOPASSWD:ALL
Lien vers le fichier : cliquez ici Copier le code

Il est préférable d'éviter d'utiliser un login/mot de passe.
Le mieux est de se connecter avec une clé SSH.
Toujours sur la machine cible, éditer la configuration du service SSH avec

nano /etc/ssh/sshd_config
Lien vers le fichier : cliquez ici Copier le code

Au niveau du paramètre AllowGroups, ajouter celui qui correspond au compte utilisé par Ansible.
Cela permettra à votre compte de se connecter en ssh

Exemple :

AllowGroups myaccount4ansible
Lien vers le fichier : cliquez ici Copier le code

A la fin du fichier, ajouter également une directive particulière pour que votre compte puisse s'authentifier avec une clé (ainsi qu'un mot de passe)

Match Group myaccount4ansible
PasswordAuthentication yes
PubKeyAuthentication yes
Lien vers le fichier : cliquez ici Copier le code

On peut ajouter des contraintes sur l'ip source par exemple.
On trouve des informations en cherchant match dans https://man7.org/linux/man-pages/man5/sshd_config.5.html

Match Group myaccount4ansible Address 172.16.1.*
PasswordAuthentication yes
PubKeyAuthentication yes
Lien vers le fichier : cliquez ici Copier le code

Redémarrer le service ssh pour prise en compte

systemctl restart sshd
Lien vers le fichier : cliquez ici Copier le code

Maintenant, sur le serveur Ansible, passer sur le compte qui sera utilisé pour lancer les commandes

su -l ansible
Lien vers le fichier : cliquez ici Copier le code

Si vous n'avez pas déjà une clé ssh, générez la avec la commande ci-dessous.
Notez que l'article https://nbeguier.medium.com/a-real-world-comparison-of-the-ssh-key-algorithms-b26b0b31bfd9
préconise Ed25519 au lieu de ECDSA

ssh-keygen -t ed25519
Lien vers le fichier : cliquez ici Copier le code

Il vous sera demandé un nom de fichier.
Ici le compte se nomme test donc j'ai nommé la clé testkey.
Elle sera placée à la racine du home du compte.

Vous trouverez deux fichiers, avec un en .pub pour la clé publique, et l'autre sans extension pour la clé privée.

On va maintenant charger votre clé privée dans un agent.
Vérifiez qu'il n'y en a pas un de lancé avec

ssh-add -l
Lien vers le fichier : cliquez ici Copier le code

Si il n'est pas lancé vous devez avoir le message
Could not open a connection to your authentication agent

Lancez l'agent et ajoutez y votre clé privée.
Ici elle s'appelle testkey

eval `ssh-agent`
ssh-add testkey
Lien vers le fichier : cliquez ici Copier le code

Déclarez votre clé publique sur le serveur à piloter avec Ansible avec la commande ssh-copy-id.
Pour que la commande fonctionne, vous devez avoir chargé votre clé privée au préalable avec la commande ssh-add sous peine d'avoir l'erreur
/usr/bin/ssh-copy-id: ERROR: failed to open ID file '/home/test/testkey': No such file

192.168.0.170 est l'ip de la machine où déclarer la clé et myaccount4ansible est le compte sur lequel la copier

ssh-copy-id -i testkey.pub myaccount4ansible@192.168.0.170
Lien vers le fichier : cliquez ici Copier le code

Testez la connexion sur la machine cible.

ssh 'myaccount4ansible@192.168.0.170'
Lien vers le fichier : cliquez ici Copier le code

En aparté voici des choses que l'on m'a indiqué pour ne pas à avoir à lancer un agent avec ces commandes :

eval `ssh-agent`
ssh-add testkey
Lien vers le fichier : cliquez ici Copier le code

avoir sa clé publique dans

cd
cat .ssh/authorized_keys
Lien vers le fichier : cliquez ici Copier le code

Dans /etc/ssh/sshd_config faire ces réglages (PAM veut dire Pluggable Authentication Modules, des librairies pour authentifier un utilisateurs sur des application ou services) :

UsePAM yes
Lien vers le fichier : cliquez ici Copier le code

Toujours dans /etc/ssh/sshd_config, éventuellement decommenter cette ligne mais par défaut c'est à Yes

PubkeyAuthentication yes
Lien vers le fichier : cliquez ici Copier le code

decommenter

AuthorizedKeysFile      .ssh/authorized_keys
Lien vers le fichier : cliquez ici Copier le code

Régler ce paramètre ainsi :

PermitRootLogin prohibit-password
 

commenter

#GSSAPIKeyExchange no
#GSSAPIEnablek5users no

dans

# GSSAPI options
#GSSAPIAuthentication yes
#GSSAPICleanupCredentials no
#GSSAPIStrictAcceptorCheck yes
GSSAPIKeyExchange no
GSSAPIEnablek5users no

 


Sur le serveur, installez simplement ansible avec

sudo apt install ansible
Lien vers le fichier : cliquez ici Copier le code

Vérifiez la version avec

ansible --version
Lien vers le fichier : cliquez ici Copier le code

Comme indiqué sur la doc officielle, ansible peut s'installer avec python.

Contrôler la présence de python3 en demandant d'afficher la version :

python3 -V
Lien vers le fichier : cliquez ici Copier le code

Si nécessaire, vous pouvez installer python3 avec l'une de ces commandes :

sudo apt install python3
sudo yum install python3
Lien vers le fichier : cliquez ici Copier le code

Contrôler la présence de pip3 avec

python3 -m pip -V
Lien vers le fichier : cliquez ici Copier le code

Tout cela pour dire qu'on peut alors installer ansible avec

python3 -m pip install --user ansible
Lien vers le fichier : cliquez ici Copier le code

Problème du fichier ansible.cfg absent

Avec une installation avec python3 je me suis retrouvé sans fichier ansible.cfg

D'après ce post je ne suis pas le seul à avoir eu le problème.

On peut vérifier l'existence du fichier de configuration avec la commande ansible --version

Si config file est à 'None' c'est qu'il n'existe pas. Exemple :

 


[ansible@MYSERVER ~]$ ansible --version
ansible [core 2.14.4]
  config file = None
  configured module search path = ['/home/ansibleio/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
  ansible python module location = /home/ansibleio/.local/lib/python3.9/site-packages/ansible
  ansible collection location = /home/ansibleio/.ansible/collections:/usr/share/ansible/collections
  executable location = /home/ansibleio/.local/bin/ansible
  python version = 3.9.14 (main, Nov  7 2022, 00:00:00) [GCC 11.3.1 20220421 (Red Hat 11.3.1-2)] (/usr/bin/python3)
  jinja version = 3.1.2
  libyaml = True

 

A ce sujet la doc indique qu'on peut générer le fichier dans son homefolder avec la commande

cd
ansible-config init --disabled -t all > ansible.cfg
sudo mkdir /etc/ansible
sudo chown root:votrecompteansible ansible.cfg
sudo chown root:votrecompteansible /etc/ansible
sudo mv ansible.cfg /etc/ansible/
sudo chmod 660 /etc/ansible/ansible.cfg
Lien vers le fichier : cliquez ici Copier le code

Editez ansible.cfg

nano /etc/ansible/ansible.cfg
Lien vers le fichier : cliquez ici Copier le code

Décommentez cette ligne pour ne pas à avoir à valider les fingerprint

host_key_checking = False

D'autres options pour ansible.cfg sont expliquées sur https://youtu.be/8Hb-i9lXdXA?t=368
On y parle par exemple de l'outil ansible-config, mais il n'est pas nécessaire ici.

A propos de ansible-config, j'ai tout de même noté que ansible-config list donne tous les paramètres que l'on peut configurer.

xavki en parle ici. Il donne ces choses à modifier.

 

On peut par exemple avoir la durée de chaque task avec
[defaults]
callback_whitelist = profile_tasks

 

Pour gagner en temps d exécution, mettre :
[ssh_connection]
pipelining = True

 

Partager plusieurs sessions pour une même connection et mettre un peu de persistence
[ssh_connection]
ssh_args = -o ControlMaster=auto -o Controlpersist=60s

 

ajouter éventuellement ceci :
-o PreferredAuthentications=publickey

 

Pour gérer 30 serveurs à la fois
[defaults]
forks = 30

 

 


Editez le fichier hosts

nano /etc/ansible/hosts
Lien vers le fichier : cliquez ici Copier le code

On fait un groupe de machines nommé [linux]
On y place l'ip de notre machine cible
On indique également le login à utiliser pour se connecter

Faites un premier est simple avec un ping de la machine cible

ansible linux -m ping
Lien vers le fichier : cliquez ici Copier le code

Vous devez avoir un retour en vert

Si vous avez un permission denied c'est peut être tout simplement que vous n'avez pas lancez votre agent ssh ni ajouté votre clé privée dedans (commandes eval `ssh-agent` et ssh-add)

Vous pouvez aussi lancer une commande, comme cat.
Ici on utilise cat pour avoir le type d'OS

ansible linux -a "cat /etc/os-release"
Lien vers le fichier : cliquez ici Copier le code

Au lieu de lancer une commande, on peut demander à jouer un playbook, un recueil, une liste de choses à faire. Ils sont au format yml

On va en créé un avec

nano /etc/ansible/oneplaybook.yml
Lien vers le fichier : cliquez ici Copier le code

Placez ceci dans le code.
Cela va installer nano sur la machine cible si le programme n'est pas présent.

---
 - name: lejob
   hosts: linux
   tasks:
    - name: check nano
      become: yes
      become_method: sudo
      apt:
       name: nano
       state: latest
Lien vers le fichier : cliquez ici Copier le code

Pour jouer son contenu, taper

ansible-playbook /etc/ansible/oneplaybook.yml
Lien vers le fichier : cliquez ici Copier le code

Le résultat est ici en vert, du coup c'est bon signe.
On a ok=2 pour dire qu'on a bien réussi à passer sudo et à faire l'installation de nano
changed=0 indique qu'il n'y a pas eu de modification, cad que nano était déjà installé.

Voici le détail du contenu du playbook

Attention l'indentation est très importante dans un fichier yml
L'indentation ce sont les retraits, les espaces et tabulations situés à gauche des lignes

Dans cet exemple j'ai écrit
---
- name: lejob


au lieu de
---
 - name: lejob

Le pire, c'est que le bug que cela provoque n'est pas indiqué à la bonne ligne.
Le programme indique ici à tort que l'erreur est au niveau de "hosts: linux"

Comme montré sur https://www.toptechskills.com/ansible-tutorials-courses/ansible-yum-module-tutorial-examples/#when-to-use-the-yum-module-vs-package-module

On peut filtrer sur la distribution, et utiliser apt sur une debian ou yum sur centos
Exemple :

---
 - name: install nano on centos
   hosts: linux
   tasks:
    - name: check nano
      become: yes
      become_method: sudo
      yum:
       name: nano
       state: latest
       update_cache: true
      when: ansible_os_family == 'RedHat'

 - name: install nano on Debian
   hosts: linux
   tasks:
    - name: check nano
      become: yes
      become_method: sudo
      apt:
       name: nano
       state: latest
       update_cache: true
      when: ansible_os_family == 'Debian'
Lien vers le fichier : cliquez ici Copier le code

On peut créer un utilisateur avec

---
 - name: Create account
   hosts: linux
   become: yes
   become_method: sudo
   tasks:
    - name: Creation d'un user
      ansible.builtin.user:
       name: unuseransible
       shell: /bin/bash
       createhome: yes
       append: yes
       state: present
    - name: set du primary group
      ansible.builtin.user:
       name: unuseransible
       groups: unuseransible
       group: unuseransible
Lien vers le fichier : cliquez ici Copier le code
---
 - name: Replace line in file examples
   hosts: linux
   tasks:
   - name: "Replace line in file apache conf"
     become: yes
     become_method: sudo
     replace:
       path: /home/myuser/test
       regexp: '(^ServerName\s)(.*)$'
       replace: '\1www.newdomain.com'
       backup: yes
Lien vers le fichier : cliquez ici Copier le code

On peut déclencher une action si une ligne a été changée

---
   - name: "reglage du compte admin dans /opt/tomcat/conf/tomcat-users.xml"
     replace:
       path: /opt/tomcat/conf/tomcat-users.xml
       regexp: '(^(\s+)?<user username="admin")(.*)$'
       replace: '  <user username="admin" password="lepassword" roles="manager-gui,admin-gui"/>'
       backup: no
     register: result
   - name: "Restart service tomcat"
     ansible.builtin.service:
       name: tomcat
       state: restarted
     when: result.changed
Lien vers le fichier : cliquez ici Copier le code

On peut aussi vérifier qu'une ligne existe avec le module lineinfile dont la page est
https://docs.ansible.com/ansible/2.4/lineinfile_module.html

et ce site donne des exemples d'utilisation :
https://www.middlewareinventory.com/blog/ansible-lineinfile-examples/

---
 - name: Lineinfile example
   hosts: linux
   become: yes
   become_method: sudo
   tasks:
   - name: "lineinfile module example"
     lineinfile:
       path: /home/myuser/test
       line: "parametre 1"
       state: present
       backup: no
Lien vers le fichier : cliquez ici Copier le code

Du coup, on peut mixer les 2 et modifier un paramètre existant et le créer le cas échéant

---
 - name: Replace line in file examples
   hosts: linux
   become: yes
   become_method: sudo
   tasks:
   - name: "si le parametre existe on change son reglage"
     replace:
       path: /home/myuser/test
       regexp: '(^(\s+)?(#+)?LogLevel\s)(.*)$'
       replace: 'LogLevel debug'
       backup: no
   - name: "creation de la ligne si inexistante"
     lineinfile:
       path: /home/myuser/test
       line: "LogLevel debug"
       state: present
       backup: no
Lien vers le fichier : cliquez ici Copier le code

2