Ansible : cas pratique (1er partie)

Ansible : cas pratique (1er partie)

Encore un article sur Ansible…mais cette fois avec une approche pas à pas et concrète d’une gestion de parc serveurs.

Je pars du principe que vous connaissez un peu le fonctionnement d’Ansible. Dans le cas contraire, vous pouvez consulter mon article précédent. L’article sera découpé en plusieurs parties pour rester digeste et un dépôt git sera mis à disposition avec l’ensemble du projet.

Contexte

Cet exemple couvre la gestion d’un parc de serveurs Debian 12 par une petite équipe composée de développeurs et d’administrateurs système:

  • gestion des utilisateurs (2 catégories)
  • installation des services de bases (postfix, snmpd, ntp, firewalld, sshd)
  • mises à jour automatique (unattended_upgrades)
  • installation d’outils de base

L’infrastructure

Elle repose sur un serveur central de management (control node dans la terminologie Ansible) sous Debian 12. Ce serveur doit pouvoir se connecter en SSH à l’ensemble des serveurs à gérer. Inversement, les serveurs à gérer doivent pouvoir accéder au control node en HTTP pour récupérer un petit script shell qui permettra de créer le compte ansible pour les connexions en SSH.

Installer et créer la structure Ansible sur le control node (serveur central):

1sudo apt install ansible ansible-lint -y
2sudo mkdir /opt/Ansible && cd $_
3sudo mkdir host_vars group_vars roles inventories .ssh
4sudo touch inventories/production

le fichier production contiendra l’inventaire des serveurs à manager

Générer une paire de clés SSH pour la connexion aux serveurs à manager (managed nodes)

1sudo sh -c 'ssh-keygen -t ed25519 -f /opt/Ansible/.ssh/id_ed25519 -C "ansible@control-node"'

il est important de protéger la clé privée avec une passphrase robuste. En cas de compromission du serveur central et en l’absence de passphrase, il serait trivial de détruire l’ensemble du parc serveur.

Ajouter le fichier de configuration Ansible:

1sudo sh -c 'ansible-config init --disabled > /opt/Ansible/ansible.cfg'

Modifier la configuration d’Ansible:

Dans le fichier /opt/Ansible/ansible.cfg, je vais préciser:

  • le chemin vers la clé SSH à utiliser: private_key_file=.ssh/id_ed25519
  • le chemin vers le fichier d’inventaire: inventory=./inventories/production
  • renoncer à la vérification des clés SSH: host_key_checking=False
  • définir l’utilisateur ansible par défaut: remote_user=ansible

la commande ansible-config dump --only-changed -t all permet d’afficher uniquement les valeurs modifiées

Installer un serveur web:

Il sera utilisé uniquement pour récupérer le script de création du compte ansible sur les serveurs à manager.

1sudo apt install lighttpd -y
2sudo rm /var/www/html/index.lighttpd.html

Copier le script shell suivant dans /var/www/html/setup.sh (modifier la variable SSH_PUBLIC_KEY avec le contenu du fichier /opt/Ansible/.ssh/id_ed25519.pub créé précédemment)

 1#!/bin/bash
 2# Create Ansible user and add this pubkey
 3#
 4if [ "$(id -u)" -ne 0 ]; then
 5    echo "This script must be run as root."
 6    exit 1
 7fi
 8
 9# Install requirements
10apt install sudo -y
11
12# Define variables
13USERNAME="ansible"
14SSH_PUBLIC_KEY="copier-ici-la-clé-publique-créée-précédemment"
15
16# Add the new user
17adduser --disabled-password --gecos "Ansible User" $USERNAME
18
19# Create .ssh directory and set permissions
20mkdir -p /home/$USERNAME/.ssh
21chmod 700 /home/$USERNAME/.ssh
22
23# Add the provided SSH public key to authorized_keys
24echo $SSH_PUBLIC_KEY > /home/$USERNAME/.ssh/authorized_keys
25chmod 600 /home/$USERNAME/.ssh/authorized_keys
26chown -R $USERNAME:$USERNAME /home/$USERNAME
27chmod 700 /home/$USERNAME
28
29# Allow new user to use sudo without password
30echo "$USERNAME ALL=(ALL) NOPASSWD:ALL" > /etc/sudoers.d/$USERNAME
31chmod 440 /etc/sudoers.d/$USERNAME

Cette étape est facultative mais permet de gagner du temps lors du déploiement des serveurs. Vous pouvez aussi l’automatiser lors d’une install PXE (preseed), avec du Cloud-Init ou du Terraform…

Configurer les serveurs à manager

Sur les serveurs à manager, il faut ajouter le compte ansible en utilisant le script:

A exécuter en tant que root en modifiant l’URL pour pointer vers votre control node

1wget -qO - http://<url-control-node>/setup.sh | bash

Ajouter les serveurs managés dans l’inventaire ansible du control node: /opt/Ansible/inventories/production

1[debian_12]
2serveur-01.exemple.com      # description
3serveur-02.exemple.com      # description

Il est possible d’utiliser la notation: serveur-[01:02].exemple.com

Tester le fonctionnement d’Ansible :

1cd /opt/Ansible
2sudo ansible all -m shell -a 'cat /etc/issue'
3
4serveur-01.exemple.com | CHANGED | rc=0 >>
5Debian GNU/Linux 12 \n \l

Ansible se connecte bien aux serveurs en utilisant les paramètres définis dans le fichier de configuration.

Ajouter le rôle “debian_12”

Ce rôle va permettre de gérer la configuration initiale et l’ensemble des services de base.

sur le control node:

1cd /opt/Ansible
2sudo ansible-galaxy role init --init-path ./roles debian_12

Pour rappel, cette commande va générer toute la structure de dossiers et fichiers nécéssaire au fonctionnement du role.

Ajouter des tâches dans le rôle

Les tâches doivent être définis dans le fichier: /opt/Ansible/roles/debian_12/tasks/main.yml Pour plus de lisibilité, je vais utiliser des inclusions pour gérer chaque partie.

Installer les paquets de base

Je commence toujours par installer les pré-requis. Sur le control node, dans le fichier: /opt/Ansible/roles/debian_12/tasks/main.yml

1---
2- name: Include install default packets
3  ansible.builtin.include_tasks: packages.yml
4  tags: packages

et dans le fichier: /opt/Ansible/roles/debian_12/tasks/packages.yml

 1---
 2- name: Add common packages
 3  ansible.builtin.package:
 4    name:
 5      - vim
 6      - unzip
 7      - zsh
 8      - bash-completion
 9      - htop
10      - nmap
11      - nload
12      - snmpd
13      - chrony
14      - cloud-guest-utils
15      - net-tools
16      - xfsprogs
17      - bsd-mailx
18      - tree
19    state: present
20  tags: packages

Rien de particulier ici, le module package d’Ansible va itérer sur la liste de paquets à installer.

Gestion des utilisateurs

On aborde un gros morceau avec la gestion des utilisateurs et les règles de gestions suivantes:

  • gérer 2 catégories d’utilisateurs (admins et développeurs)
  • ajouter les comptes admins par défaut et les comptes developpeurs uniquement sur certains serveurs
  • autoriser l’accès SSH uniquement pour les membres du groupe ssh-users
  • authentification par clés publiques SSH par défaut
  • autoriser l’accès par mot de passe pour des intervenants occasionnels appartenant au groupe ssh-nokey
  • autoriser l’utilisation de sudo sans mot de passe pour les membres du groupe sudo
  • simplifier le cycle de vie des comptes (ajout,suppression,remplacement de clés)
  • refuser les connexion root en SSH

Sur le control node, je vais ajouter 2 dossiers:

  • /opt/Ansible/files : pour stocker les fichiers contenants les clés publiques des utilisateurs
  • /opt/Ansible/users_vars : pour gérer les variables propres à chaque utilisateur
1sudo mkdir -p /opt/Ansible/files/pubkeys /opt/Ansible/users_vars
2sudo touch /opt/Ansible/users_vars/main.yml

La tentation est grande de mettre les variables des utilisateurs et les fichiers dans les dossiers prévus à cet effet directement dans le rôle. Mais dans ce découpage d’inventaire par famille d’OS, il ne serait pas possible de factoriser ces éléments entre différentes versions (debian_13, rockylinux_9, etc…).

Dans le fichier /opt/Ansible/group_vars/all, j’ajoute une variable add_dev_users: no dans la section defaults

1# Global
2ansible_connection: ssh
3ansible_user: ansible
4default_shell: /bin/bash
5
6# Default
7add_dev_users: false

Dans le fichier: /opt/Ansible/users_vars/main.yml

 1---
 2# utiliser la commande `mkpasswd --method=sha-512` pour générer le hash du password
 3admin_users:
 4  - username: solohan
 5    state: present
 6    comment: Han Solo
 7    groups: sudo,ssh-users
 8    password: "$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0"
 9
10  - username: skywalkerluke
11    state: present
12    comment: Luke Skywalker
13    groups: sudo,ssh-users
14    password: "$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0"
15
16dev_users:
17  - username: vadordark
18    state: present
19    comment: Dark Vador
20    groups: sudo,ssh-users
21    password: "$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1"
22
23  - username: renkylo
24    state: present
25    comment: Kylo Ren
26    groups: sudo,ssh-users
27    password: "$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771"

Ici, tous les utilisateurs pourront obtenir une connexion SSH et utiliser sudo.

Dans le répertoire /opt/Ansible/files/pubkeys, je vais créer un fichier par utilisateur contenant sa clé publique SSH.

Il est important que le nom du fichier soit le nom de connexion de l’utilisateur (username)

1tree /opt/Ansible/files/pubkeys/
2/opt/Ansible/files/pubkeys/
3├── renkylo
4├── skywalkerluke
5├── solohan
6└── vadordark
7cat /opt/Ansible/files/pubkeys/solohan
8ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOzRGvI6qSFBYHSyseuTEzwm74KMISfUz9SAN7hWV/xW solohan@laptop

Rajouter dans le fichier: /opt/Ansible/roles/debian_12/tasks/main.yml

1- name: Include users tasks
2  ansible.builtin.include_tasks: users.yml
3  tags: users

Dans le fichier: /opt/Ansible/roles/debian_12/tasks/users.yml

  1---
  2- name: Include external variables
  3  ansible.builtin.include_vars: ../../users_vars/main.yml
  4  tags: users
  5
  6- name: Create users with bash as default shell
  7  ansible.builtin.lineinfile:
  8    path: "/etc/default/useradd"
  9    regexp: "^SHELL=/bin/sh"
 10    line: "SHELL=/bin/bash"
 11  tags: users
 12
 13- name: Ensure group "ssh-nokey" exist
 14  ansible.builtin.group:
 15    name: ssh-nokey
 16    state: present
 17  tags: users
 18
 19- name: Ensure group "sudo" exist
 20  ansible.builtin.group:
 21    name: sudo
 22    state: present
 23  tags: users
 24
 25- name: Ensure group "ssh-users" exist
 26  ansible.builtin.group:
 27    name: ssh-users
 28    state: present
 29  tags: users
 30
 31- name: Add ansible user in "ssh-users"
 32  ansible.builtin.user:
 33    name: ansible
 34    groups: ssh-users
 35  tags: users
 36
 37- name: Create accounts for ADMIN
 38  ansible.builtin.user:
 39    name: "{{ item.username }}"
 40    comment: "{{ item.comment }}"
 41    groups: "{{ item.groups }}"
 42    state: "{{ item.state }}"
 43    password: "{{ item.password }}"
 44    update_password: on_create
 45    # update_password: always
 46    append: yes
 47  with_items: "{{ admin_users }}"
 48  tags: users
 49
 50- name: Create accounts for DEV
 51  ansible.builtin.user:
 52    name: "{{ item.username }}"
 53    comment: "{{ item.comment }}"
 54    groups: "{{ item.groups }}"
 55    state: "{{ item.state }}"
 56    password: "{{ item.password }}"
 57    update_password: on_create
 58    # update_password: always
 59    append: yes
 60  with_items: "{{ dev_users }}"
 61  when: add_dev_users
 62  tags: users
 63
 64- name: Set ADMIN authorized key
 65  ansible.posix.authorized_key:
 66    user: "{{ item.username }}"
 67    key: "{{ lookup('file', '../../files/pubkeys/' + item.username) }}"
 68  with_items: "{{ admin_users }}"
 69  when: item.state == "present"
 70  tags: users
 71
 72- name: Set DEV authorized key
 73  ansible.posix.authorized_key:
 74    user: "{{ item.username }}"
 75    key: "{{ lookup('file', '../../files/pubkeys/' + item.username) }}"
 76  with_items: "{{ dev_users }}"
 77  when: item.state == "present" and add_dev_users
 78  tags: users
 79
 80- name: Remove ADMIN users homedir when user is absent
 81  ansible.builtin.file:
 82    path: /home/{{ item.username }}
 83    state: absent
 84  with_items: "{{ admin_users }}"
 85  when: item.state == "absent"
 86  tags: users
 87
 88- name: Remove DEV users homedir when user is absent
 89  ansible.builtin.file:
 90    path: /home/{{ item.username }}
 91    state: absent
 92  with_items: "{{ dev_users }}"
 93  when: item.state == "absent" and add_dev_users
 94  tags: users
 95
 96- name: Add sudo logfile
 97  ansible.builtin.lineinfile:
 98    path: /etc/sudoers
 99    insertafter: "^Defaults    secure_path = /sbin:/bin:/usr/sbin:/usr/bin"
100    line: "Defaults    logfile=/var/log/sudo.log"
101  tags: users
102
103- name: Enable passwordless for sudo group in sudoers
104  ansible.builtin.lineinfile:
105    path: /etc/sudoers
106    regexp: "^%sudo  ALL=(ALL)       ALL"
107    line: "%sudo  {{ ansible_hostname }}=(ALL)  NOPASSWD:ALL"
108  tags: users

La première tâche permet de charger les variables situées en dehors du rôle. Ensuite, je vérifie que les groupes dont j’ai besoin existe. J’utilise la condition when pour créer les comptes des développeurs uniquement si la variable add_dev_users est à true (false par défaut). Dès lors, il suffira de déclarer cette variable dans /opt/Ansible/host_vars/<fqdn_du_serveur> pour créer aussi ces comptes uniquement sur les serveurs qui le nécessite.

Configurer le serveur SSH

Rajouter dans le fichier: /opt/Ansible/roles/debian_12/tasks/main.yml

1- name: Include SSH server config
2  ansible.builtin.include_tasks: sshd.yml
3  tags: sshd

Dans le fichier: /opt/Ansible/roles/debian_12/tasks/sshd.yml

 1---
 2- name: Secure SSH server
 3  ansible.builtin.template:
 4    src: sshd-custom.conf.j2
 5    dest: /etc/ssh/sshd_config.d/sshd-custom.conf
 6    owner: root
 7    group: root
 8    mode: "0600"
 9  notify: Restart sshd
10  tags: sshd

On utilise ici le mécanisme de handlers pour redémarrer de daemon SSH si la configuration change.

Dans le fichier /opt/Ansible/roles/debian_12/handlers/main.yml

1---
2# handlers for SSHD
3- name: Restart sshd
4  ansible.builtin.service:
5    name: sshd
6    state: restarted

Dans le fichier /opt/Ansible/roles/debian_12/templates/sshd-custom.conf.j2

 1{{ ansible_managed | comment }}
 2
 3PermitRootLogin no
 4PasswordAuthentication no
 5
 6# Disconnect idle client after 30mn
 7ClientAliveInterval 1800
 8ClientAliveCountMax 1
 9
10MaxAuthTries 3
11MaxSessions 3
12
13# Only ssh-users group members can connect
14AllowGroups ssh-users
15
16# Allow password login for ssh-nokey group members
17Match Group ssh-nokey
18	PasswordAuthentication yes
19
20# End of 'Match' blocks
21Match all

Utiliser un playbook pour lancer le rôle.

Le projet est déjà bien avancé, il est temps de vérifier si tout fonctionne correctement. Pour cela, je vais ajouter un playbook pour appliquer le rôle sur l’ensemble des serveurs.

Dans le fichier /opt/Ansible/infra.yml

1---
2- name: Configure servers
3  hosts: debian_12
4  become: true
5  roles:
6    - debian_12

et utiliser le linter Ansible pour vérifier la syntaxe sur l’ensemble du projet:

 1ansible-lint /opt/Ansible/infra.yml
 2Read documentation for instructions on how to ignore specific rule violations.
 3
 4              Rule Violation Summary
 5 count tag            profile rule associated tags
 6     1 schema[meta]   basic   core
 7     3 meta-incorrect shared  metadata
 8     1 meta-no-info   shared  metadata
 9
10Failed after min profile: 5 failure(s), 0 warning(s) on 9 files.

Hormis les métadonnées que je vous laisse personnaliser à votre guise, il n’y a pas d’erreur de syntaxe.

Je peux donc lancer le playbook (je limite volontairement à un seul serveur)

vous pouvez passer par une phase de “dry run” avec l’option --check mais qui n’est pas toujours très concluante quand certaines tâches dépendent d’autres non réellement appliquées.

1sudo ansible-playbook infra.yml --limit serveur-01.exemple.com
 1PLAY [Configure servers] **************************************************************************
 2
 3TASK [Gathering Facts] ****************************************************************************
 4Enter passphrase for key '/opt/Ansible/.ssh/id_ed25519':
 5ok: [serveur-01.exemple.com]
 6
 7TASK [debian_12 : Include install default packets] ************************************************
 8included: /opt/Ansible/roles/debian_12/tasks/packages.yml for serveur-01.exemple.com
 9
10TASK [debian_12 : Add common packages] ************************************************************
11changed: [serveur-01.exemple.com]
12
13TASK [debian_12 : Include users tasks] ************************************************************
14included: /opt/Ansible/roles/debian_12/tasks/users.yml for serveur-01.exemple.com
15
16TASK [debian_12 : Include external variables] *****************************************************
17ok: [serveur-01.exemple.com]
18
19TASK [debian_12 : Create users with bash as default shell] ****************************************
20changed: [serveur-01.exemple.com]
21
22TASK [debian_12 : Ensure group "ssh-nokey" exist] *************************************************
23changed: [serveur-01.exemple.com]
24
25TASK [debian_12 : Ensure group "sudo" exist] ******************************************************
26ok: [serveur-01.exemple.com]
27
28TASK [debian_12 : Ensure group "ssh-users" exist] *************************************************
29changed: [serveur-01.exemple.com]
30
31TASK [debian_12 : Add ansible user in "ssh-users"] ************************************************
32changed: [serveur-01.exemple.com]
33
34TASK [debian_12 : Create accounts for ADMIN] ******************************************************
35changed: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
36changed: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
37
38TASK [debian_12 : Create accounts for DEV] ********************************************************
39skipping: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
40skipping: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
41skipping: [serveur-01.exemple.com]
42
43TASK [debian_12 : Set ADMIN authorized key] *******************************************************
44changed: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
45changed: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
46
47TASK [debian_12 : Set DEV authorized key] *********************************************************
48skipping: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
49skipping: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
50skipping: [serveur-01.exemple.com]
51
52TASK [debian_12 : Remove ADMIN users homedir when user is absent] *********************************
53skipping: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
54skipping: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
55skipping: [serveur-01.exemple.com]
56
57TASK [debian_12 : Remove DEV users homedir when user is absent] ***********************************
58skipping: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
59skipping: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
60skipping: [serveur-01.exemple.com]
61
62TASK [debian_12 : Add sudo logfile] ***************************************************************
63changed: [serveur-01.exemple.com]
64
65TASK [debian_12 : Enable passwordless for sudo group in sudoers] **********************************
66changed: [serveur-01.exemple.com]
67
68TASK [debian_12 : Include SSH server config] ******************************************************
69included: /opt/Ansible/roles/debian_12/tasks/sshd.yml for serveur-01.exemple.com
70
71TASK [debian_12 : Secure SSH server] **************************************************************
72changed: [serveur-01.exemple.com]
73
74RUNNING HANDLER [debian_12 : Restart sshd] ********************************************************
75changed: [serveur-01.exemple.com]
76
77PLAY RECAP ****************************************************************************************
78serveur-01.exemple.com : ok=17   changed=11   unreachable=0    failed=0    skipped=4    rescued=0    ignored=0

Je rajoute maintenant les comptes des développeurs:

Dans le fichier: /opt/Ansible/host_vars/serveur-01.exemple.com

1add_dev_users: true

Je profite de l’utilisation des tags, pour relancer le playbook uniquement sur la partie users.

1sudo ansible-playbook infra.yml --limit serveur-01.exemple.com --tags users
 1PLAY [Configure servers] ***********************************************************************************************************************************************************************************
 2
 3TASK [Gathering Facts] *************************************************************************************************************************************************************************************
 4Enter passphrase for key '/opt/Ansible/.ssh/id_ed25519':
 5ok: [serveur-01.exemple.com]
 6
 7TASK [debian_12 : Include users tasks] *********************************************************************************************************************************************************************
 8included: /opt/Ansible/roles/debian_12/tasks/users.yml for serveur-01.exemple.com
 9
10TASK [debian_12 : Include external variables] **************************************************************************************************************************************************************
11ok: [serveur-01.exemple.com]
12
13TASK [debian_12 : Create users with bash as default shell] *************************************************************************************************************************************************
14ok: [serveur-01.exemple.com]
15
16TASK [debian_12 : Ensure group "ssh-nokey" exist] **********************************************************************************************************************************************************
17ok: [serveur-01.exemple.com]
18
19TASK [debian_12 : Ensure group "sudo" exist] ***************************************************************************************************************************************************************
20ok: [serveur-01.exemple.com]
21
22TASK [debian_12 : Ensure group "ssh-users" exist] **********************************************************************************************************************************************************
23ok: [serveur-01.exemple.com]
24
25TASK [debian_12 : Add ansible user in "ssh-users"] *********************************************************************************************************************************************************
26ok: [serveur-01.exemple.com]
27
28TASK [debian_12 : Create accounts for ADMIN] ***************************************************************************************************************************************************************
29ok: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
30ok: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
31
32TASK [debian_12 : Create accounts for DEV] *****************************************************************************************************************************************************************
33changed: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
34changed: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
35
36TASK [debian_12 : Set ADMIN authorized key] ****************************************************************************************************************************************************************
37ok: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
38ok: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
39
40TASK [debian_12 : Set DEV authorized key] ******************************************************************************************************************************************************************
41changed: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
42changed: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
43
44TASK [debian_12 : Remove ADMIN users homedir when user is absent] ******************************************************************************************************************************************
45skipping: [serveur-01.exemple.com] => (item={'username': 'solohan', 'state': 'present', 'comment': 'Han Solo', 'groups': 'sudo,ssh-users', 'password': '$6$SzlZvkG88iMYtAOV$LQXxHREb85Jv7onoxJfW7Y02aoWr51v8hrL.QkyPEzuQ93nHxSY/YvoKM5JJQN0ARhtam1QUibA/9CJGx6gZo0'})
46skipping: [serveur-01.exemple.com] => (item={'username': 'skywalkerluke', 'state': 'present', 'comment': 'Luke Skywalker', 'groups': 'sudo,ssh-users', 'password': '$6$AcgkntPPP6XVx3hf$GWJnTPHuVPyqO2IeBHxWRSxb2D8Bg8yu0oHZ6SRSyT8tzPr5NieqcZheqaJLWUYtKy3U2o/xzC1kleU5aVsBx0'})
47skipping: [serveur-01.exemple.com]
48
49TASK [debian_12 : Remove DEV users homedir when user is absent] ********************************************************************************************************************************************
50skipping: [serveur-01.exemple.com] => (item={'username': 'vadordark', 'state': 'present', 'comment': 'Dark Vador', 'groups': 'sudo,ssh-users', 'password': '$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1'})
51skipping: [serveur-01.exemple.com] => (item={'username': 'renkylo', 'state': 'present', 'comment': 'Kylo Ren', 'groups': 'sudo,ssh-users', 'password': '$6$ZaC.HNhhEGF/ZoSF$ees9o9i90qd2rjhKJXKh3OUxQWjslnKb4tOeqdh3a7RzBRUV3SgV.0bWyuSvURPYgZiQNQyH4sb.UuhKknD771'})
52skipping: [serveur-01.exemple.com]
53
54TASK [debian_12 : Add sudo logfile] ************************************************************************************************************************************************************************
55ok: [serveur-01.exemple.com]
56
57TASK [debian_12 : Enable passwordless for sudo group in sudoers] *******************************************************************************************************************************************
58ok: [serveur-01.exemple.com]
59
60PLAY RECAP *************************************************************************************************************************************************************************************************
61serveur-01.exemple.com : ok=14   changed=2    unreachable=0    failed=0    skipped=2    rescued=0    ignored=0

Cette fois, les comptes des développeurs sont bien ajoutés. Si je dois supprimer un utilisateur particulier, il suffit de passer le state de son compte à absent.

Dans le fichier: /opt/Ansible/users_vars/main.yml

1dev_users:
2  - username: vadordark
3    state: absent
4    comment: Dark Vador
5    groups: sudo,ssh-users
6    password: "$6$E0XYQTabJWodgk4E$z2UZFtnjVCmPsL/fg7V8AB2EJfbcpwH5t5ngSEi4MWMr0DZ7PamSYZLoeKaUuzZ2jwYb22Lmum.MYooh9j2fb1"

et relancer le playbook:

1sudo ansible-playbook infra.yml --limit serveur-01.exemple.com --tags users
2PLAY RECAP *************************************************************************************************************************************************************************************************
3serveur-01.exemple.com : ok=15   changed=2    unreachable=0    failed=0    skipped=1    rescued=0    ignored=0

Le compte de Dark Vador et son répertoire personnel sont bien supprimés.

Conclusion

Fin de cette première partie déjà bien dense. Si vous avez des pistes d’amélioration, n’hésitez pas à me les remonter (@BrunoL@mamot.fr ). Dans la prochaine partie, on finira de configurer les services de bases…à suivre !

Photo de Lenny Kuhne sur Unsplash