2026-06-24 20:17:46 -04:00
|
|
|
---
|
2026-08-07 15:33:32 -04:00
|
|
|
|
|
|
|
|
# L'URL PUBLIQUE de l'IdP se derive de l'exposition declaree au plan, elle ne se
|
|
|
|
|
# fabrique pas : `keycloak.<domaine>` n'est publie nulle part (voir resoudre_idp).
|
|
|
|
|
- name: Resoudre le fournisseur d'identite (role partage)
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: resoudre_idp
|
|
|
|
|
vars:
|
|
|
|
|
resoudre_idp_realm: "{{ serveur_grafana_oidc_realm }}"
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Exiger le mot de passe admin Grafana (Vault)
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- serveur_grafana_admin_password | length > 0
|
|
|
|
|
fail_msg: "serveur_grafana_admin_password est requis (Ansible Vault)."
|
|
|
|
|
|
|
|
|
|
- name: Assurer le repertoire des trousseaux apt
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: /etc/apt/keyrings
|
|
|
|
|
state: directory
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0755"
|
|
|
|
|
|
2026-08-09 14:05:25 -04:00
|
|
|
# Recuperee UNE FOIS. Sans garde, chaque deploiement recontactait le serveur du
|
|
|
|
|
# fournisseur : cinq cles x quatorze hotes = soixante-dix allers-retours externes pour
|
|
|
|
|
# des cles deja installees, et autant d'occasions qu'un tiers lent fasse tomber le
|
|
|
|
|
# deploiement. Arbitrage rendu le 2026-08-09 : une plateforme souveraine ne depend pas
|
|
|
|
|
# de six serveurs etrangers pour redeployer ce qu'elle possede deja.
|
|
|
|
|
#
|
|
|
|
|
# CONSEQUENCE ASSUMEE : une rotation de cle amont n'est plus recuperee toute seule. Elle
|
|
|
|
|
# ne passe pas inapercue pour autant — `apt` refuse alors le depot, bruyamment. Pour
|
|
|
|
|
# forcer le rafraichissement : supprimer le fichier et rejouer le role.
|
|
|
|
|
- name: Cette ressource est-elle deja recuperee ? (Telecharger la cle de signature Gr)
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: "{{ serveur_grafana_depot_cle_fichier }}"
|
|
|
|
|
register: telecharger_la_cle_de_signature_grafana_present
|
|
|
|
|
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Telecharger la cle de signature Grafana
|
2026-08-09 14:05:25 -04:00
|
|
|
when: not telecharger_la_cle_de_signature_grafana_present.stat.exists
|
2026-06-24 20:17:46 -04:00
|
|
|
ansible.builtin.get_url:
|
|
|
|
|
url: "{{ serveur_grafana_depot_cle_url }}"
|
|
|
|
|
dest: "{{ serveur_grafana_depot_cle_fichier }}"
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0644"
|
|
|
|
|
|
|
|
|
|
- name: Ajouter le depot apt Grafana
|
|
|
|
|
ansible.builtin.apt_repository:
|
|
|
|
|
repo: "{{ serveur_grafana_depot_source }}"
|
|
|
|
|
filename: grafana
|
|
|
|
|
state: present
|
|
|
|
|
|
paquets tiers : passer par le cache du controleur, plus par Internet
Trois depots tiers etaient en HTTPS, et client_artefacts pose
Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et
aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait
pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait
les chercher sur Internet a sa naissance.
step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une
machine neuve n obtenait ni son client d autorite ni ses metriques — elle n
entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors
ligne, et il tenait dans un mot.
make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256
verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les
installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux
qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en
apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour
ce que le cache n a PAS fourni, et rien d autre.
Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli
desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache
et la machine obtient ses certificats. Zero echec.
Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son
index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et
un depot injoignable faisait continue AVANT d incrementer le total, si bien que
le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut
pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en
le faisant echouer.
Reste hors ligne : NTP externe, et l expedition des alertes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
|
|
|
# LE CACHE DU CONTROLEUR D'ABORD, LE DEPOT DISTANT POUR LE RESTE (2026-09-03).
|
|
|
|
|
#
|
|
|
|
|
# Les depots tiers sont en HTTPS, et `client_artefacts` pose
|
|
|
|
|
# `Acquire::https::Proxy "DIRECT"` — ils CONTOURNENT donc le cache du site et sortent sur
|
|
|
|
|
# Internet a chaque construction de VM. `make cacher-paquets` les tire une fois, versions
|
|
|
|
|
# epinglees et empreintes verifiees ; ce role les depose depuis ce cache.
|
|
|
|
|
- name: Poser les paquets tiers depuis le cache du controleur
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: paquets_tiers
|
|
|
|
|
vars:
|
|
|
|
|
paquets_tiers_noms: "{{ serveur_grafana_paquets }}"
|
|
|
|
|
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Installer Grafana
|
|
|
|
|
ansible.builtin.apt:
|
paquets tiers : passer par le cache du controleur, plus par Internet
Trois depots tiers etaient en HTTPS, et client_artefacts pose
Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et
aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait
pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait
les chercher sur Internet a sa naissance.
step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une
machine neuve n obtenait ni son client d autorite ni ses metriques — elle n
entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors
ligne, et il tenait dans un mot.
make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256
verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les
installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux
qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en
apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour
ce que le cache n a PAS fourni, et rien d autre.
Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli
desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache
et la machine obtient ses certificats. Zero echec.
Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son
index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et
un depot injoignable faisait continue AVANT d incrementer le total, si bien que
le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut
pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en
le faisant echouer.
Reste hors ligne : NTP externe, et l expedition des alertes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
|
|
|
# CE QUE LE CACHE N'A PAS FOURNI, ET RIEN D'AUTRE. Les dependances Debian passent
|
|
|
|
|
# par le cache du site en HTTP ; seuls les paquets tiers non caches exigent Internet.
|
|
|
|
|
# Reinstaller ce que le cache vient de poser ferait un `update_cache` inutile — et
|
|
|
|
|
# hors ligne, il echouerait APRES un travail deja fait.
|
|
|
|
|
name: "{{ serveur_grafana_paquets | difference((paquets_tiers_disponibles | default({})).keys() | list) }}"
|
2026-06-24 20:17:46 -04:00
|
|
|
state: present
|
|
|
|
|
update_cache: true
|
|
|
|
|
|
paquets tiers : passer par le cache du controleur, plus par Internet
Trois depots tiers etaient en HTTPS, et client_artefacts pose
Acquire::https::Proxy DIRECT — sans quoi le cache du site refuse les tunnels et
aucun depot tiers n est joignable. La ligne est juste ; sa consequence ne l avait
pas ete vue : ces trois depots CONTOURNENT le cache, et chaque VM neuve allait
les chercher sur Internet a sa naissance.
step-cli et alloy sont poses par des integrations UNIVERSELLES. Sans lien, une
machine neuve n obtenait ni son client d autorite ni ses metriques — elle n
entrait dans aucun flux chiffre. Dernier obstacle a une reconstruction hors
ligne, et il tenait dans un mot.
make cacher-paquets tire les 21 deb aux versions epinglees, empreinte SHA256
verifiee depuis l index du depot. Le role partage paquets_tiers les depose et les
installe EN UN SEUL appel a apt — il sait resoudre un ensemble de fichiers locaux
qui se dependent, la ou paquet par paquet echouerait sur l ordre (Icinga en
apporte dix-sept). Six roles branches ; chacun retombe sur le depot distant pour
ce que le cache n a PAS fourni, et rien d autre.
Eprouve pour de vrai : packages.smallstep.com renvoye vers 127.0.0.1, step-cli
desinstalle, cache local efface. Le role rejoue installe 0.30.6-1 depuis le cache
et la machine obtient ses certificats. Zero echec.
Deux defauts de mon propre outil, trouves en le construisant : Smallstep sert son
index NON COMPRESSE (404 sur .gz) donc step-cli n etait jamais mis en cache ; et
un depot injoignable faisait continue AVANT d incrementer le total, si bien que
le script rapportait 20 sur 20 alors qu il en manquait un. Une garde qui ne peut
pas echouer ne garde rien — troisieme fois cette semaine. Corrige puis eprouve en
le faisant echouer.
Reste hors ligne : NTP externe, et l expedition des alertes.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
2026-09-05 08:22:14 -04:00
|
|
|
when: (serveur_grafana_paquets
|
|
|
|
|
| difference((paquets_tiers_disponibles | default({})).keys() | list)) | length > 0
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Provisionner les datasources (Prometheus + Loki)
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: datasources.yaml.j2
|
|
|
|
|
dest: /etc/grafana/provisioning/datasources/setops.yaml
|
|
|
|
|
owner: root
|
|
|
|
|
group: grafana
|
|
|
|
|
mode: "0640"
|
|
|
|
|
notify: Redemarrer grafana
|
|
|
|
|
|
2026-07-04 16:10:59 -04:00
|
|
|
- name: Assurer le repertoire des dashboards
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: "{{ serveur_grafana_dashboards_dir }}"
|
|
|
|
|
state: directory
|
|
|
|
|
owner: root
|
|
|
|
|
group: grafana
|
|
|
|
|
mode: "0750"
|
|
|
|
|
|
|
|
|
|
- name: Deployer le provisioning des dashboards
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: dashboards.yaml.j2
|
|
|
|
|
dest: /etc/grafana/provisioning/dashboards/setops.yaml
|
|
|
|
|
owner: root
|
|
|
|
|
group: grafana
|
|
|
|
|
mode: "0640"
|
|
|
|
|
notify: Redemarrer grafana
|
|
|
|
|
|
|
|
|
|
- name: Deployer les dashboards Set-OPS
|
|
|
|
|
ansible.builtin.copy:
|
|
|
|
|
src: dashboards/
|
|
|
|
|
dest: "{{ serveur_grafana_dashboards_dir }}/"
|
|
|
|
|
owner: root
|
|
|
|
|
group: grafana
|
|
|
|
|
mode: "0640"
|
|
|
|
|
directory_mode: "0750"
|
|
|
|
|
notify: Redemarrer grafana
|
|
|
|
|
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Assurer le repertoire de drop-in systemd
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: /etc/systemd/system/grafana-server.service.d
|
|
|
|
|
state: directory
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0755"
|
|
|
|
|
|
|
|
|
|
- name: Deployer la configuration d'environnement (domaine + secret)
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: setops.conf.j2
|
|
|
|
|
dest: /etc/systemd/system/grafana-server.service.d/setops.conf
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0600"
|
|
|
|
|
no_log: true
|
|
|
|
|
notify: Redemarrer grafana
|
|
|
|
|
|
|
|
|
|
- name: Activer et demarrer Grafana
|
2026-07-01 21:01:53 -04:00
|
|
|
when: not ansible_check_mode
|
2026-06-24 20:17:46 -04:00
|
|
|
ansible.builtin.systemd:
|
|
|
|
|
name: "{{ serveur_grafana_service }}"
|
|
|
|
|
enabled: true
|
|
|
|
|
state: started
|
|
|
|
|
daemon_reload: true
|
2026-08-07 21:10:47 -04:00
|
|
|
|
|
|
|
|
# --- ROTATION DU COMPTE DE SECOURS -------------------------------------------
|
|
|
|
|
# `GF_SECURITY_ADMIN_PASSWORD` n'agit qu'a la CREATION du compte : changer la voute
|
|
|
|
|
# ne changeait rien, et la voute se mettait a mentir en silence. Le runbook de
|
|
|
|
|
# reprise (docs/autorisation.md §6) promet pourtant cette rotation — c'est ce qui
|
|
|
|
|
# transforme une livraison en transfert. Constate le 2026-08-07.
|
|
|
|
|
#
|
|
|
|
|
# Idempotence par EMPREINTE : on garde le sha256 du secret applique. Tant qu'il ne
|
|
|
|
|
# change pas, on ne touche a rien ; des qu'il change, on reapplique. On ne peut pas
|
|
|
|
|
# lire le mot de passe en place, donc on memorise ce qu'on a pose.
|
keycloak : un jeton frais la ou on s'en sert ; grafana : un echec lisible
Technolibre remonte depuis zero une seconde fois — 14 hotes, 2588 taches ok,
0 failed. Deux defauts trouves en chemin.
LE JETON KEYCLOAK VIVAIT 60 SECONDES. Il etait pris dans politique-mdp.yml —
le 2e des neuf fichiers du role — et reutilise jusqu'au 8e. Entre les deux,
six fichiers de travail dont groupes-ldap.yml et ses reprises espacees de
15 s. Sur une construction NEUVE le temps depasse la minute : 401. Sur un
REJEU tout est converge, ca va vite, ca passe.
D'ou les deux echecs du matin, chaque fois suivis d'un succes au rejeu, qui
donnaient l'illusion d'une course au demarrage de Keycloak. J'avais ecrit
alors ne pas avoir de mesure qui le prouve — c'etait juste, et la cause etait
l'AGE du jeton. jeton-admin.yml en prend un frais la ou on s'en sert.
GRAFANA : UN ECHEC TRANSITOIRE RENDU ILLISIBLE. Premier demarrage, apres 67 s
de migrations : « failed to create admin user: no such column: uid », alors
que la migration qui ajoute cette colonne etait journalisee comme reussie.
Base neuve : tout remigre, service actif, colonne presente. L'incident ne
s'est pas reproduit et Chezlepro ne l'a jamais eu — je n'ai donc PAS corrige
la cause, faute de l'avoir reproduite. J'ai corrige ce qui la rendait
indechiffrable :
- Restart=on-failure venait du paquet SANS RestartSec, donc 100 ms : six
relances en une seconde, chacune rejouant les migrations sur la meme base
SQLite. Un echec unique se presentait comme un desastre. RestartSec=10 ;
- la rotation du compte de secours echouait cinq fois sous no_log en
annoncant « the output has been hidden », alors que la vraie cause etait
ailleurs et lisible : le serveur ne demarrait pas. Une attente explicite sur
le port precede desormais la CLI, avec un message qui renvoie a la PREMIERE
erreur du journal.
Troisieme fois dans la journee que no_log masque la cause au moment ou elle
sert : une garde qui protege un secret ne doit pas emporter le diagnostic.
Verifie : 7 devis sur Technolibre — MTU, identite, certificats, PostgreSQL,
courriel, frontiere CONFORME ; prouver.py 35 OK ; ansible-lint production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 20:19:50 -04:00
|
|
|
# EXIGER QUE LE SERVEUR REPONDE AVANT DE TOUCHER A SA BASE. La CLI qui suit echouait
|
|
|
|
|
# sinon cinq fois de suite sous `no_log`, en annoncant « the output has been hidden » —
|
|
|
|
|
# alors que la vraie cause etait ailleurs et parfaitement lisible : `grafana-server` ne
|
|
|
|
|
# demarrait pas, sa base ayant echoue une migration au premier lancement (2026-08-10,
|
|
|
|
|
# `no such column: uid`). Cinq reprises censurees contre un message clair : on prefere
|
|
|
|
|
# le message.
|
|
|
|
|
- name: Attendre que Grafana réponde avant de toucher au compte de secours
|
|
|
|
|
ansible.builtin.wait_for:
|
|
|
|
|
host: 127.0.0.1
|
|
|
|
|
port: "{{ serveur_grafana_port | default(3000) }}"
|
|
|
|
|
timeout: 120
|
|
|
|
|
register: serveur_grafana_pret
|
|
|
|
|
failed_when: false
|
|
|
|
|
when: not ansible_check_mode
|
|
|
|
|
|
|
|
|
|
- name: Dire que Grafana ne répond pas, plutôt que d'échouer sur sa CLI
|
|
|
|
|
ansible.builtin.fail:
|
|
|
|
|
msg: >-
|
|
|
|
|
Grafana n'écoute pas sur le port {{ serveur_grafana_port | default(3000) }} après
|
|
|
|
|
120 s : la rotation du compte de secours ne peut pas aboutir, et sa CLI ne dirait
|
|
|
|
|
rien d'utile. Regarder `journalctl -u grafana-server` — et y chercher la PREMIÈRE
|
|
|
|
|
erreur, pas la dernière : `Restart=on-failure` en empile plusieurs.
|
|
|
|
|
when:
|
|
|
|
|
- not ansible_check_mode
|
|
|
|
|
- serveur_grafana_pret is failed
|
|
|
|
|
|
2026-08-07 21:10:47 -04:00
|
|
|
- name: Empreinte du mot de passe admin en place
|
|
|
|
|
ansible.builtin.slurp:
|
|
|
|
|
src: "{{ serveur_grafana_marqueur_admin }}"
|
|
|
|
|
register: serveur_grafana_marque
|
|
|
|
|
failed_when: false
|
|
|
|
|
changed_when: false
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Appliquer le mot de passe du compte de secours (rotation)
|
|
|
|
|
ansible.builtin.command:
|
|
|
|
|
argv:
|
|
|
|
|
- grafana-cli
|
|
|
|
|
- "--homepath={{ serveur_grafana_homepath }}"
|
|
|
|
|
# `paths.data` DOIT etre impose : la CLI le prend par defaut a
|
|
|
|
|
# `<homepath>/data`, alors que le paquet Debian range la base dans
|
|
|
|
|
# /var/lib/grafana. Sans lui, la CLI cree une base FANTOME, y ecrit, et
|
|
|
|
|
# annonce « Admin password changed successfully » — pendant que le serveur
|
|
|
|
|
# lit l'autre. Constate le 2026-08-07 : le compte n'avait pas bouge depuis
|
|
|
|
|
# le deploiement initial, malgre quatre reinitialisations « reussies ».
|
|
|
|
|
- "--configOverrides=cfg:default.paths.data={{ serveur_grafana_donnees }}"
|
|
|
|
|
- admin
|
|
|
|
|
- reset-admin-password
|
|
|
|
|
- "{{ serveur_grafana_admin_password }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
# La tache ne s'execute QUE si l'empreinte differe : quand elle tourne, elle
|
|
|
|
|
# change reellement le mot de passe.
|
|
|
|
|
changed_when: true
|
2026-08-08 23:47:34 -04:00
|
|
|
# PATIENTE : sur une machine neuve, cette commande suit de peu le premier
|
|
|
|
|
# demarrage de grafana-server, qui cree encore sa base. La CLI echoue alors sur
|
|
|
|
|
# une base absente ou verrouillee. Constate le 2026-08-08 pendant la premiere
|
|
|
|
|
# reconstruction from-zero ; rejouee seule quelques minutes plus tard, la meme
|
|
|
|
|
# commande passe. Meme classe que l'ecriture Keycloak qui suit la synchro LDAP :
|
|
|
|
|
# une COURSE de premier demarrage, pas une panne. On attend une condition, pas
|
|
|
|
|
# une duree.
|
|
|
|
|
register: serveur_grafana_reset
|
|
|
|
|
retries: 5
|
|
|
|
|
delay: 10
|
|
|
|
|
until: serveur_grafana_reset is succeeded
|
2026-08-07 21:10:47 -04:00
|
|
|
when: >-
|
|
|
|
|
(serveur_grafana_marque.content | default('') | b64decode | trim)
|
|
|
|
|
!= (serveur_grafana_admin_password | hash('sha256'))
|
|
|
|
|
notify: Redemarrer grafana
|
|
|
|
|
|
|
|
|
|
- name: Retenir l'empreinte appliquee
|
|
|
|
|
ansible.builtin.copy:
|
|
|
|
|
content: "{{ serveur_grafana_admin_password | hash('sha256') }}\n"
|
|
|
|
|
dest: "{{ serveur_grafana_marqueur_admin }}"
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0600"
|
|
|
|
|
no_log: true
|