Pour rentabiliser ses investissements, AdrarNum souhaiterait élargir son offre de services par des solutions Cloud clé-en-main. La stratégie consiste à migrer progressivement les services maintenues et hébergées chez les clients vers son DataCenter, tout récemment installé dans la zone industrielle du parc de la plaine, à Toulouse, et passer d’une entreprise de type ESN classique à celle de CSP (Cloud Service Provider).
construction d’une offre de services GLPI en PaaS
AdrarNum souhaiterait rajouter à son catalogue une solution GLPI en PaaS installée et préconfiguré en moins d’une heure.
Après livraison du produit, AdrarNum est responsable des mises à jour.
• Du serveur web
• De la version de PHP
• Du SGBDR
• Et de GLPI et de ses plugins.
La tendance qui se dégage de la veille technologique menée autour des produits de déploiement et de gestion de configurations penchant du côté de Ansible, vous êtes chargé de proposer une procédure d’installation et de maintenance des serveurs GLPI des futurs clients.
• Installation de GLPI et de tous les composants nécessaires sur une machine virtuelle dédiée au client, par Ansible
• Les clients n’auront accès aux serveurs qu’en https
• Seules les versions de PHP supérieures à la version 7 seront supportées
• Les tâches d’administration du serveur incombent à AdrarNum mais l’administration de l’application GLPI est du ressort du client. A la livraison, Il lui sera fourni une URL, un identifiant et mot de passe d’accès à GLPI réservé à cet effet.
• AdrarNum fournira au client un script d’installation de l’agent FusionInventory sur les postes clients à partir d’un serveur de téléchargement.
• Le client aura le choix de récréer des comptes locaux à GLPI ou utiliser un serveur LDAP de son choix.
• Sécuriser le serveur client avec Fail2Ban
Dans un premier temps on crée une clé SSH qui sera liée à notre ansible.
Pour cela on crée une clé avec le meilleur chiffrement disponible :
ssh-keygen -f ~/.ssh/ansible_user -t RSA -b 4096
attention, les clé SSH doivent avoir un niveau d"autorisation ugo de 600 c'est à dire : lecture et ecriture pour root uniquement
Ainsi on pourra différencier ces connexions de celles des admins.
Cette clé, sera ensuite envoyée à tous les hôtes via la commande : ssh-copy-id utilisateur@hote ce qui ajoutera la clé publique au fichier :
~/.ssh/authorized_keys de l'hôte.
Pour continuer dans l'automatisation on pourra créer un agent SSH, lié à cette clé, permettant de ne pas rentrer le mot de passe à chaque requettes SSH de la part d'ansible.
pour cela :
eval $(ssh-agent)ssh-add /.ssh/ansible_user
attention en cas d'arrêt il faudra peut être relancer l'agent
Ansible ne doit pas se comporter de la même façon si la cible est un équipement réseau ou un serveur, c’est la raison pour laquelle il a besoin de modules et de plugins dédiées. Les modules sont des programmes externes, généralement développés en Python, qui vont proposer des fonctions dédiées à des plateformes spécifique.
.ansible/
├── ansible.cfg
├── group_vars
│ ├── webserv.yml
│ └── database.yml
├── host_vars
│ ├── webserv1.yml
│ └── database1.yml
├── inventory.yml
├── password.yml
└── playbook.yml
C'est le fichier de config d'ansible, permetant d'adapter son comportement en fonction de nos besoins.
Il n'est pas présent à l'installation, il devra être créé, from scratch, ou via la commande ansible-config init pour avoir une idée des paramètres disponibles (l'option --disabled commentera touts les paramètres pour que l'on active que ceux qui nous intéressent).
Le fichier contient plusieurs blocs, ici le bloc défault :
# config file for ansible -- https://ansible.com/
# ===============================================
# nearly all parameters can be overridden in ansible-playbook
# or with command line flags. ansible will read ANSIBLE_CONFIG,
# ansible.cfg in the current working directory, .ansible.cfg in
# the home directory or /etc/ansible/ansible.cfg, whichever it
# finds first
[defaults]
# some basic default values...
#inventory = /etc/ansible/hosts
#library = /usr/share/my_modules/
#module_utils = /usr/share/my_module_utils/
#remote_tmp = ~/.ansible/tmp
#local_tmp = ~/.ansible/tmp
#plugin_filters_cfg = /etc/ansible/plugin_filters.yml
#forks = 5
#poll_interval = 15
#sudo_user = root
#ask_sudo_pass = True
#ask_pass = True
#transport = smart
#remote_port = 22
dans notre cas, les options qui pourront nous être utile sont les suivants :
[defaults]
deprecation_warnings = False
host_key_checking = False
Le premier désactivera les messages d’avertissement informant de suppression de fonctionnalités pour plus de lisibilité. Le second paramètre désactivera la vérification des clés ssh lors de la connexion du contrôleur Ansible vers les équipements réseaux distants et évitera les erreurs si ces clés ne sont pas connues.
Le fichier inventory (inventaire) fera la liste des hotes que l'on veut administrer.
Pour inventorier nos hotes, ils seront classés par groupe :
webservers:
hosts:
192.168.1.9:
dbservers:
hosts:
192.168.1.8:
infra:
children:
webservers:
dbservers:
On a donc les groupes webservers,dbservers,infra.
Les deux premier sont les groupes d'hotes. Mais ils sont aussi les groupes enfant du groupe 'infra'.
Une fois le fichier d'inventaire écrit, il est possible de vérifier son arborescence via la commande : ansible-inventory -i inventory.yml --graph

A savoir qu'il éxiste deux groupe par défaut :
'all' et 'ungrouped'. 'All' contient tous les hotes quel que soit leur groupe. 'ungrouped' est un groupe "divers".
Mais chaque hote peut être contenu dans plusieurs groupes, dans le cas d'un environement multi-sites par exemple :
webservers:
hosts:
192.168.1.9:
dbservers:
hosts:
192.168.1.8:
infra:
children:
webservers:
dbservers:
Paris:
hosts:
192.168.1.9
Toulouse:
hosts:
192.168.1.8
Ce qui nous donne cette représentation :

Il faudra créer des variables utilisés par ansible pour ses connexions aux équipements, comme les id de connexion (plus tard placés dans un vault)
Mais également des chemins ou des ports à modifier :

Nous pouvont utiliser un Vault pour chiffrer les identifiants de connexion à nos équipements.
Par défaut Ansible Vault propose un chiffrement symétrique AES256 et demandera un mot de passe qui fera office de clé. Ce mot de passe sera à utiliser à chaque lancement de playbook afin de débloquer l’accès aux identifiants.
Le fichier password.yml contiendra les variables d'identification qui sont à reporter dans les playbooks ou les group_vars
password :
---
router_user: cisco
router_password: C1sc0
group_vars :
---
ansible_connection: network_cli
ansible_network_os: ios
ansible_user: "{{ router_user }}"
ansible_ssh_pass: "{{ router_password }}"
On pourra ensuite, soit appeler le fichier vault directement dans la commande de lancement du playbook :
$ ansible-playbook playbook.yml -e @password.yml --ask-vault-password Vault password:
soit, ajouter l'information au playbook directement :
--
- name: play A
hosts: routers
connection: local
gather_facts: no
vars_files:
- password.yml
dans ce deuxième cas il suffit d'avoir la variable --ask-vault-password dans le lancement du playbook.
Pour augmenter la modularité et l'organisation de notre environement ansible, on peut utiliser des roles :
C'est une manière structurée de créer des taches pour nos hotes en regroupant les actions ayant un objectif commun (exemple : toutes les actions nécessaires à l'install de LAMP mises dans le role serveurWeb).
On cherchera à créer des roles qui soient utilisés le plus possible.
Il est possible de les partager ou d'en télécharger via ansible-galaxy
Pour créer un role on utilise la commande ansible-galaxy init nom_du_role
Un répertoire est alors créé :

webserv/
├── defaults # variables par défaut (peut être surchargé par les vars)
│ └── main.yml
├── files # fichiers à copier ou statiques
├── handlers # déclencheurs
│ └── main.yml
├── meta # pour le partage sur galaxy et inclure les dépendances
│ └── main.yml
├── README.md
├── tasks # actions à effectuer (point d'entrée du fichier)
│ └── main.yml
├── templates # stocke des fichers au format jinja
├── tests
│ ├── inventory
│ └── test.yml
└── vars # variables (structurelles) de roles
└── main.yml
Il y a deux fichiers qui vont nous intéresser. Le fichier main.yml dans le répertoire tasks permet de décrire les taches à effectuer. C’est en quelque sorte l’équivalent d’un playbook. Ensuite, le fichier main.yml du répertoire vars va nous permettre de définir nos variables.
Plusieurs playbooks vont être nécessaires. En effet, plusieurs types de taches vont devoir être mises en place :
- name: Install Apache and PHP
ansible.builtin.apt: # Utilisation du module apt pour l'installation de paquets
name: ['apache2', 'php', 'php-mysql'] # Liste des paquets à installer
state: present # Assure que les paquets sont installés
update_cache: yes # Met à jour le cache des paquets avant l'installation
- name: Install extra packages
ansible.builtin.apt:
name: "{{ extra_packages }}" # Utilise une variable pour les paquets supplémentaires
state: present # Assure l'installation des paquets
- name: Setup virtualhost
ansible.builtin.template:
src: templates/glpi-template.conf # Utilise un template de configuration
dest: "/etc/apache2/sites-available/{{ http_conf }}" # Destination du fichier de configuration
- name: Activate Apache2 rewrite module
community.general.apache2_module:
name: rewrite # installe le module de réécriture
state: present
- name: Activate Apache2 ssl module
community.general.apache2_module:
name: ssl # Installe le module SSL
state: present
- name: Enable new site
ansible.builtin.command: a2ensite {{ http_conf }} # Active le site Apache
notify: "Restart Apache" # Affiche le message
---
- name: Create CSR directory
ansible.builtin.file:
path: "{{ ssl_csr_directory }}"
state: directory
mode: '0755'
- name: Generate an OpenSSL private key with the default values (4096 bits, RSA)
community.crypto.openssl_privatekey:
path: "{{ ssl_privkey_directory }}/glpi.pem"
- name: Generate an OpenSSL Certificate Signing Request
community.crypto.openssl_csr:
path: "{{ ssl_csr_directory }}/glpi.csr"
privatekey_path: "{{ ssl_privkey_directory }}/glpi.pem"
common_name: "www.{{ http_host }}.com"
country_name: FR
organization_name: AIS
email_address: "{{ ssl_csr_email }}"
- name: Generate a Self Signed OpenSSL certificate
community.crypto.x509_certificate:
path: "{{ ssl_crt_directory }}/glpi.crt"
privatekey_path: "{{ ssl_privkey_directory }}/glpi.pem"
csr_path: "{{ ssl_csr_directory }}/glpi.csr"
provider: selfsigned
---
- name: Install UFW Firewall
ansible.builtin.apt:
name: ufw
state: present
- name: UFW resets existing rules
community.general.ufw:
state: reset
- name: UFW firewall allow SSH
community.general.ufw:
rule: allow
port: 22
- name: UFW firewall allow DNS
community.general.ufw:
rule: allow
port: 53
- name: UFW firewall allow HTTP on port {{ http_port }}
community.general.ufw:
rule: allow
port: "{{ http_port }}"
proto: tcp
- name: UFW firewall allow HTTPS on port {{ https_port }}
community.general.ufw:
rule: allow
port: "{{ https_port }}"
proto: tcp
- name: Configure default incoming policy
community.general.ufw:
policy: reject
direction: incoming
- name: Configure default outgoing policy
community.general.ufw:
policy: allow
direction: outgoing
- name: Enable UFW
community.general.ufw:
state: enabled
notify: "Reload UFW"
---
- name: Install Fail2ban
ansible.builtin.apt:
name: fail2ban
state: present
- name: Copy custom config file
ansible.builtin.template:
src: custom.conf
dest: /etc/fail2ban/jail.d/custom.conf
mode: '0644'
- name: Start fail2ban service
service:
name: fail2ban
state: started
---
- name: Install MariaDB Server
ansible.builtin.apt:
name:
- mariadb-server
- python3-mysqldb
state: present
update_cache: yes
- name: Ensure mariadb service is start
ansible.builtin.service:
name: mysql
state: started
enabled: yes
- name: Removes all anonymous user accounts
ansible.builtin.mysql_user:
name: ''
host_all: true
state: absent
- name: Remove test database
ansible.builtin.mysql_db:
name: "test"
state: "absent"
- name: Create MariaDB client config
ansible.builtin.copy:
dest: "/root/.my.cnf"
content: |
[client]
user=root
password={{ glpi_db_root_password }}
mode: 0400
- name: Upload MariaDB table config
ansible.builtin.template:
src: "table.sql.j2"
dest: "/tmp/table.sql"
- name: Add MariaDB table to database
community.mysql.mysql_db:
name: "{{ glpi_db_name }}"
state: present
login_user: root
login_password: '{{ glpi_db_root_password }}'
state: import
target: /tmp/table.sql
login_unix_socket: /run/mysqld/mysqld.sock
- name: Clean temp table.sql file
ansible.builtin.file:
path: /tmp/table.sql
state: absent
- name: "Create {{ glpi_db_user }} with all {{ glpi_db_name }} privileges"
community.mysql.mysql_user:
name: "{{ glpi_db_user }}"
password: "{{ glpi_db_password }}"
priv: "{{ glpi_db_name }}.*:ALL"
host: localhost
state: present
login_user: root
login_password: '{{ glpi_db_root_password }}'
login_unix_socket: /var/run/mysqld/mysqld.sock
notify: "Restart MariaDB Serveur"
---
- name: Check if GLPI directory exists
ansible.builtin.stat:
path: "{{ glpi_install_path }}"
register: dir_stat
- name: Check if install.php exists
ansible.builtin.stat:
path: "{{ glpi_install_path }}/install/install.php"
register: install_stat
- name: Download GLPI archive
ansible.builtin.get_url:
url: https://github.com/glpi-project/glpi/releases/download/10.0.10/glpi-10.0.10.tgz
dest: /tmp
when: not install_stat.stat.exists
- name: Create install directory and unarchive GLPI archive
ansible.builtin.unarchive:
src: /tmp/glpi-10.0.10.tgz
dest: /var/www/
owner: www-data
group: www-data
mode: '0755'
remote_src: yes
when: not dir_stat.stat.exists
- name: Install GLPI
ansible.builtin.command:
"php bin/console -n db:install -H {{ glpi_db_host }} -P {{ glpi_db_port }} -d {{ glpi_db_name }} -u {{ glpi_db_user }} -p {{ glpi_db_password }} -L fr_FR --reconfigure --force"
args:
chdir: "{{ glpi_install_path }}"
when: not dir_stat.stat.exists
- name: Clean install.php file
ansible.builtin.file:
path: "{{ glpi_install_path }}/install/install.php"
state: absent
- name: Clean archive file
ansible.builtin.file:
path: /tmp/glpi-10.0.10.tgz
state: absent
- name: Install Apache and PHP
ansible.builtin.apt: # Utilisation du module apt pour l'installation de paquets
name: ['apache2', 'php', 'php-mysql'] # Liste des paquets à installer
state: present # Assure que les paquets sont installés
update_cache: yes # Met à jour le cache des paquets avant l'installation
- name: Install extra packages
ansible.builtin.apt:
name: "{{ extra_packages }}" # Utilise une variable pour les paquets supplémentaires
state: present # Assure l'installation des paquets
- name: Setup virtualhost
ansible.builtin.template:
src: templates/glpi-template.conf # Utilise un template de configuration
dest: "/etc/apache2/sites-available/{{ http_conf }}" # Destination du fichier de configuration
- name: Setup Apache SSL
ansible.builtin.import_tasks: ssl.yml # On appelle le playbook pour l'install du SSL
- name: Activate Apache2 rewrite module
community.general.apache2_module:
name: rewrite # installe le module de réécriture
state: present
- name: Activate Apache2 ssl module
community.general.apache2_module:
name: ssl # Installe le module SSL
state: present
- name: Enable new site
ansible.builtin.command: a2ensite {{ http_conf }} # Active le site Apache
notify: "Restart Apache" # Affiche le message
- name: Install and configure UFW
ansible.builtin.import_tasks: ufw.yml # appelle le playbook de configuration UFW
- name: Install and configure Fail2ban
ansible.builtin.import_tasks: fail2ban.yml # appelle le playbook de configuration Fail2ban
Pour rendre la configuration plus structurée on vas se baser sur nos différents playbooks et en faire des roles :
trois roles se démarquent :
ansible-galaxy init nom_du_role
à partir de nos trois roles, plusieurs taches découleront :
Toutes les taches du playbook se sont bien lancés.
On peut se connecter à notre site :
Il nous reste à lancer le playbook dans lequel on a lister les taches à lancer :

Les handlers vont être lancé à la suite des tasks :

Enfin le resultat de l'ensemble des taches sera donné lorsqu'il a fini :

On peut se connecter à notre serveur GLPI :


Le produit peut maintenant être livré au client pour qu'il crée ses utilisateurs, etc ...
https://github.com/thfx31/ansible-glpi/
https://galaxy.ansible.com/ui/standalone/roles/supertarto/glpi/
https://www.it-connect.fr/installation-pas-a-pas-de-glpi-10-sur-debian-12/
https://galaxy.ansible.com/ui/standalone/roles/?page=1&page_size=10&sort=-created