Exploiter
Déploiement d'un client
En bref
Niveau : intermédiaire
Durée : 45 minutes
Prérequis : tous les rôles des pages précédentes écrits ; une VM Debian 12 vierge
Niveau de test : reconstitué
Le déploiement, c'est quoi ?
Les pages précédentes ont décrit les rôles un par un. Cette page les assemble : le fichier site.yml complet, la procédure pour intégrer un nouveau client, et le test qui prouve que le déploiement est reproductible. C'est la page qui répond à l'objectif du projet : un client, une commande.
| Élément | Rôle |
|---|---|
site.yml |
Playbook unique : contrôles, puis rôles dans l'ordre |
inventory/host_vars/<client>/ |
Variables et secrets du client |
Étiquettes (tags) |
Permettent de rejouer une seule partie |
--limit |
Restreint l'exécution à un client |
Nouvelle commande → dossier host_vars → ligne dans l'inventaire → ansible-playbook site.yml --limit <client>
Concrètement, déployer un client revient à créer ses fichiers de variables, l'ajouter à l'inventaire, et lancer le même playbook que pour tous les autres. Aucun rôle n'est modifié.
Prérequis
- Le serveur Ansible est en place, avec
.vault_pass(page 1). - Les rôles
base-hardening,docker-engine,teleport-agent,traefik,authentik,nextcloud,immich,vaultwardenetfail2banexistent dansroles/. - La VM du client est livrée : Debian 12, utilisateur
deployautorisé par clé SSH, adresse du réseau d'administration. - Les enregistrements DNS du client pointent vers l'adresse publique de la VM.
Les secrets attendus par application
Chaque application commandée exige des secrets dans le Vault. Une table dans les variables communes les liste, pour que le playbook puisse vérifier qu'aucun ne manque avant de commencer.
# inventory/group_vars/all/secrets_catalogue.yml
# Secrets obligatoires : ceux du socle, puis ceux de chaque application.
nebuleuse_core_secrets:
- vault_authentik_secret_key
- vault_authentik_db_password
- vault_authentik_bootstrap_password
- vault_authentik_bootstrap_token
# Une entrée par application du catalogue, même sans secret (liste vide).
nebuleuse_app_secrets:
nextcloud:
- vault_nextcloud_db_password
- vault_nextcloud_admin_password
immich:
- vault_immich_db_password
- vault_immich_admin_password
vaultwarden:
- vault_vaultwarden_admin_token
jellyfin: []
papermerge: []
homeassistant: []
matrix: []
Le playbook complet
# site.yml
- name: Déployer un client Nébuleuse
hosts: clients
become: true # les tâches s'exécutent en root via sudo
# Un client à la fois : une erreur sur l'un n'interrompt pas la préparation des autres.
serial: 1
pre_tasks:
# --- Contrôles : échouer tout de suite plutôt qu'au milieu du déploiement ---
- name: Vérifier que toutes les applications commandées existent au catalogue
ansible.builtin.assert:
that:
- nebuleuse_apps | difference(nebuleuse_catalogue) | length == 0
fail_msg: >-
Application(s) inconnue(s) : {{ nebuleuse_apps | difference(nebuleuse_catalogue) }}
quiet: true
tags: always
- name: Vérifier que le client a bien un domaine
ansible.builtin.assert:
that:
- client_domain is defined
- client_domain | length > 0
fail_msg: "La variable client_domain doit être définie pour {{ inventory_hostname }}."
quiet: true
tags: always
- name: Vérifier que les secrets nécessaires existent dans le Vault
ansible.builtin.assert:
that:
# "vars" contient toutes les variables visibles pour ce client, Vault déchiffré compris.
- nebuleuse_secrets_manquants | length == 0
fail_msg: "Secrets manquants dans le Vault : {{ nebuleuse_secrets_manquants }}"
quiet: true
vars:
nebuleuse_secrets_attendus: >-
{{ nebuleuse_core_secrets +
(nebuleuse_apps | map('extract', nebuleuse_app_secrets) | flatten | list) }}
nebuleuse_secrets_manquants: >-
{{ nebuleuse_secrets_attendus | reject('in', vars) | list }}
tags: always
roles:
# 1. Socle : système, pare-feu, Docker et réseau "proxy".
- { role: base-hardening, tags: [base] }
- { role: docker-engine, tags: [docker] }
# 2. Accès administrateur par le bastion.
- { role: teleport-agent, tags: [teleport] }
# 3. Publication web et certificats.
- { role: traefik, tags: [traefik] }
# 4. SSO : toujours présent, il fait partie du socle.
- { role: authentik, tags: [sso] }
# 5. Applications : déployées uniquement si elles figurent dans la commande.
- { role: nextcloud, tags: [nextcloud], when: "'nextcloud' in nebuleuse_apps" }
- { role: immich, tags: [immich], when: "'immich' in nebuleuse_apps" }
- { role: vaultwarden, tags: [vaultwarden], when: "'vaultwarden' in nebuleuse_apps" }
# 6. Protection : en dernier, elle lit les journaux des rôles précédents.
- { role: fail2ban, tags: [fail2ban] }
Les contrôles portent l'étiquette always : ils s'exécutent même quand un seul rôle est rejoué avec --tags. Le premier passage d'un nouveau client doit en revanche se faire sans étiquette.
Intégrer un nouveau client
La procédure est la même pour chaque client. L'exemple prend un troisième client, de numéro 3 : adresses 10.99.0.23 et 192.0.2.23.
# 1. Créer le dossier de variables à partir du client existant le plus proche.
cp -r inventory/host_vars/client-alpha inventory/host_vars/client-<nom>
# 2. Ajouter la machine à l'inventaire.
# inventory/hosts.yml (extrait)
all:
children:
clients:
hosts:
client-<nom>:
ansible_host: 10.99.0.23
# 3. Éditer vars.yml (domaine, e-mail, applications) puis vault.yml (secrets neufs).
# Chaque client a des secrets distincts : ne jamais recopier ceux d'un autre.
ansible-vault edit inventory/host_vars/client-<nom>/vault.yml
# 4. Vérifier la connexion et la syntaxe.
ansible client-<nom> -m ping
ansible-playbook site.yml --syntax-check
# 5. Simuler : montre ce qui changerait, sans rien modifier.
ansible-playbook site.yml --limit client-<nom> --check --diff
# 6. Déployer.
ansible-playbook site.yml --limit client-<nom>
La simulation (--check) s'arrête vite sur un client vierge : plusieurs tâches dépendent de ce que les précédentes ont réellement installé. Elle est surtout utile sur un client déjà déployé, pour prévoir l'effet d'une modification.
Le test d'idempotence
Un déploiement est idempotent quand le rejouer sur un client à jour ne modifie rien. C'est le critère qui distingue un playbook fiable d'un script.
# Premier passage : de nombreuses tâches "changed".
ansible-playbook site.yml --limit client-<nom>
# Second passage immédiat : la ligne finale doit afficher "changed=0".
ansible-playbook site.yml --limit client-<nom>
Si le second passage signale des changements, la tâche concernée est à corriger : un command sans changed_when, un modèle qui change à chaque exécution (une date, une valeur aléatoire), ou un module qui ne compare pas l'état réel.
Rejouer une partie seulement
# Un seul service : par exemple après un changement de version de Nextcloud.
ansible-playbook site.yml --limit client-alpha --tags nextcloud
# Plusieurs services, dans l'ordre du playbook.
ansible-playbook site.yml --limit client-alpha --tags traefik,sso
# Ajouter une application à un client existant : modifier nebuleuse_apps dans vars.yml,
# puis rejouer son étiquette et celle du SSO (qui crée la connexion).
ansible-playbook site.yml --limit client-alpha --tags sso,immich,fail2ban
Vérification globale
# Sur la VM : tous les conteneurs sont "Up".
docker ps --format '{{.Names}}\t{{.Status}}'
# Les certificats sont délivrés : chaque adresse répond en HTTPS.
for h in sso cloud photos vault; do
curl -sS -o /dev/null -w "$h.penhoat.example : %{http_code}\n" "https://$h.penhoat.example/"
done
# Le bastion voit la VM (depuis le bastion).
tctl nodes ls
# Les jails Fail2ban sont actives.
sudo fail2ban-client status
Pièges
- Secret manquant découvert en fin de parcours : sans le contrôle des secrets, l'erreur « is undefined » survient après plusieurs minutes de déploiement. Le tableau
nebuleuse_app_secretsdoit être tenu à jour à chaque nouvelle application. - Rejouer une application sans le SSO : une application a besoin de la connexion créée par Authentik. Pour la première installation d'une application, inclure l'étiquette
sso. --limitoublié : sans lui, le playbook cible tous les clients, l'un après l'autre.serial: 1limite les dégâts, mais le temps et les effets d'une erreur s'accumulent.- Secrets copiés d'un client à l'autre : un secret commun annule l'isolation entre clients. Chaque
vault.ymldoit avoir ses propres valeurs. - Certificats de test restés actifs : si
traefik_acme_stagingest resté àtrueaprès les essais, les navigateurs refusent le certificat. La variable est à repasser àfalse, puis le dossieracmeà vider avant de rejouer l'étiquettetraefik. - Idempotence qui se dégrade : une tâche ajoutée sans
changed_whenfait échouer le test d'idempotence. Le test se rejoue après chaque modification de rôle.
Page suivante : Pièges et dépannage.
Pièges et dépannage
En bref
Niveau : intermédiaire
Durée : 20 minutes de lecture
Prérequis : avoir lu les pages de rôles
Niveau de test : reconstitué
Dépanner, c'est quoi ?
Une application qui ne répond pas peut tomber en panne à plusieurs endroits : le DNS, le certificat, Traefik, Authentik, l'application elle-même. Chercher au hasard fait perdre du temps. La méthode la plus sûre consiste à remonter le chemin d'une requête, étape par étape, et à s'arrêter à la première qui échoue.
| Étape | Question | Page de référence |
|---|---|---|
| 1. DNS | Le nom pointe-t-il vers la bonne adresse ? | Traefik |
| 2. Pare-feu | Les ports 80 et 443 sont-ils ouverts et joignables ? | Socle |
| 3. Traefik | Le routeur existe-t-il et le certificat est-il délivré ? | Traefik |
| 4. Application | Le conteneur tourne-t-il et répond-il ? | Page de l'application |
| 5. SSO | La connexion par Authentik aboutit-elle ? | Authentik |
| 6. Blocage | L'adresse du visiteur est-elle bloquée ? | Fail2ban |
DNS → pare-feu → Traefik → application → SSO → blocage éventuel
Les commandes de diagnostic
# 1. DNS : l'adresse retournée doit être l'adresse publique de la VM.
dig +short cloud.penhoat.example
# 2. Pare-feu : règles de la VM et chaîne des blocages.
sudo ufw status verbose
sudo iptables -L DOCKER-USER -n
# 3. Traefik : journal de démarrage, puis requêtes récentes.
docker logs --tail 50 alpha_traefik
sudo tail -n 20 /var/log/traefik/access.log
# 4. Application : conteneurs, puis journal d'un conteneur précis.
docker ps --format '{{.Names}}\t{{.Status}}'
docker logs --tail 50 alpha_nextcloud
# 5. SSO : l'API d'Authentik répond.
curl -sSk --resolve sso.penhoat.example:443:127.0.0.1 https://sso.penhoat.example/-/health/live/
# 6. Blocage : adresses bloquées par jail.
sudo fail2ban-client status nebuleuse-traefik
Symptômes courants
| Symptôme | Cause probable | Vérification et correction |
|---|---|---|
| Le navigateur affiche une erreur de certificat | Certificat non délivré, ou mode staging actif |
traefik_acme_staging doit valoir false ; examiner le journal de Traefik pour l'erreur ACME |
| Erreur 404 de Traefik | Le routeur n'existe pas | Labels traefik.enable et Host(...) absents ou erronés dans le fichier Compose |
| Erreur 502 ou 504 | Traefik n'atteint pas le conteneur | Mauvais port dans loadbalancer.server.port, conteneur hors du réseau proxy, label traefik.docker.network manquant |
| Boucle de connexion sur le SSO | Mauvais flux sur le provider | Le provider doit utiliser le flux d'autorisation (page Authentik) |
| « Redirect URI invalide » | Adresse de retour différente | Comparer caractère pour caractère l'adresse du provider et celle de l'application |
| « Accès refusé » après connexion | Pas de règle d'accès liée à l'application | Lier la règle nebuleuse-allow-all à l'application |
| L'application ne joint pas le SSO | Détour par l'adresse publique | Alias réseau de Traefik pour sso.<domaine> |
| Visiteur légitime bloqué | Seuil trop bas, ou adresse partagée | fail2ban-client set <jail> unbanip <adresse>, puis relever le seuil ou ajouter à ignoreip |
Le déploiement échoue sur une variable vault_... |
Secret absent du Vault | Contrôle des secrets en début de site.yml |
| SSH refusé après le socle | Pare-feu ou ListenAddress |
Se connecter par la console de l'hébergeur et vérifier sshd -T |
| Le disque se remplit | Journaux ou bibliothèque Immich | docker system df ; du -sh /opt/nebuleuse/* ; vérifier la rotation du journal Traefik |
Où sont les journaux ?
| Élément | Emplacement |
|---|---|
| Journal d'accès de Traefik | /var/log/traefik/access.log |
| Traefik, applications, Authentik | docker logs <conteneur> |
| Vaultwarden | /opt/nebuleuse/vaultwarden/data/vaultwarden.log |
| Fail2ban | /var/log/fail2ban.log |
| Ansible | Sortie du terminal ; pour garder une trace : -vv, ou une redirection vers un fichier |
Si le déploiement échoue en cours de route
Un déploiement qui s'arrête au milieu laisse la VM dans un état intermédiaire, mais rejouable : les rôles sont idempotents.
- Lire le message de la première tâche en erreur : les suivantes en découlent souvent.
- Corriger la cause (variable, secret, DNS, connectivité).
- Rejouer le playbook sur ce client, avec la même commande.
- Si l'erreur persiste dans un rôle précis, le rejouer seul avec
--tagset-vvpour afficher le détail des appels.
# Rejouer un seul rôle avec le détail de chaque tâche.
ansible-playbook site.yml --limit client-alpha --tags sso -vv
Remettre une application à zéro
Cette opération supprime les données de l'application : elle n'est à faire que sur une VM d'essai, ou après une sauvegarde.
# Sur la VM : arrêter l'application et supprimer ses conteneurs.
cd /opt/nebuleuse/nextcloud && docker compose down
# Supprimer ses données (IRRÉVERSIBLE).
sudo rm -rf /opt/nebuleuse/nextcloud/html /opt/nebuleuse/nextcloud/db-data
# Depuis le serveur Ansible : redéployer.
ansible-playbook site.yml --limit client-alpha --tags nextcloud
Les variables d'installation (compte administrateur, base de données) ne sont lues qu'au premier démarrage. Pour les changer, il faut soit passer par l'outil du service (occ, interface d'administration), soit repartir de zéro comme ci-dessus.
Pour aller plus loin
- Sauvegardes : aucun rôle de sauvegarde n'est décrit ici. Il faudrait sauvegarder les dossiers
/opt/nebuleuse/<application>de chaque client, ainsi que le dépôt Git et le mot de passe du Vault du serveur Ansible. - Supervision : la page de la base de connaissance sur la supervision (à écrire) permettrait de surveiller les certificats, l'espace disque et les conteneurs de chaque VM.
- Mises à jour : les versions d'images sont figées dans les variables des rôles. Un rythme de mise à jour (mensuel, par exemple) et une procédure de retour arrière restent à définir.
Page suivante : Fiche Atelier Penhoat.