2026-06-24 20:17:46 -04:00
|
|
|
---
|
|
|
|
|
- name: Exiger le mot de passe admin LDAP (Vault)
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- serveur_openldap_admin_password | length > 0
|
|
|
|
|
fail_msg: "serveur_openldap_admin_password est requis (a fournir via Ansible Vault)."
|
|
|
|
|
|
2026-07-02 09:45:34 -04:00
|
|
|
- name: Installer debconf-utils (requis par le module debconf, fournit debconf-get-selections)
|
|
|
|
|
ansible.builtin.apt:
|
|
|
|
|
name: debconf-utils
|
|
|
|
|
state: present
|
|
|
|
|
update_cache: true
|
|
|
|
|
cache_valid_time: 3600
|
|
|
|
|
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Preconfigurer slapd (debconf)
|
|
|
|
|
ansible.builtin.debconf:
|
|
|
|
|
name: slapd
|
|
|
|
|
question: "{{ item.question }}"
|
|
|
|
|
vtype: "{{ item.vtype }}"
|
|
|
|
|
value: "{{ item.value }}"
|
|
|
|
|
loop:
|
|
|
|
|
- { question: "slapd/no_configuration", vtype: "boolean", value: "false" }
|
|
|
|
|
- { question: "slapd/domain", vtype: "string", value: "{{ serveur_openldap_domaine }}" }
|
|
|
|
|
- { question: "shared/organization", vtype: "string", value: "{{ serveur_openldap_organisation }}" }
|
|
|
|
|
- { question: "slapd/backend", vtype: "select", value: "MDB" }
|
|
|
|
|
- { question: "slapd/purge_database", vtype: "boolean", value: "true" }
|
|
|
|
|
- { question: "slapd/move_old_database", vtype: "boolean", value: "true" }
|
|
|
|
|
- { question: "slapd/allow_ldap_v2", vtype: "boolean", value: "false" }
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.question }}"
|
|
|
|
|
|
|
|
|
|
- name: Preconfigurer le mot de passe admin slapd (debconf)
|
|
|
|
|
ansible.builtin.debconf:
|
|
|
|
|
name: slapd
|
|
|
|
|
question: "{{ item }}"
|
|
|
|
|
vtype: password
|
|
|
|
|
value: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
loop:
|
|
|
|
|
- slapd/password1
|
|
|
|
|
- slapd/password2
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Installer OpenLDAP
|
|
|
|
|
ansible.builtin.apt:
|
|
|
|
|
name: "{{ serveur_openldap_paquets }}"
|
|
|
|
|
state: present
|
|
|
|
|
update_cache: true
|
|
|
|
|
cache_valid_time: 3600
|
|
|
|
|
|
|
|
|
|
- name: Activer et demarrer slapd
|
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_openldap_service }}"
|
|
|
|
|
enabled: true
|
|
|
|
|
state: started
|
|
|
|
|
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
# L'ANNUAIRE EST-IL VIERGE ? Mesure AVANT que ce role n'y cree quoi que ce soit (unites,
|
|
|
|
|
# comptes de service) : apres, il ne le serait plus jamais. Le paquet ne pose que la
|
|
|
|
|
# racine — `cn=admin` n'y figure que sur les installations anciennes.
|
2026-09-30 03:56:42 -04:00
|
|
|
#
|
|
|
|
|
# `awk`, PAS `grep -v | wc -l` : sur un annuaire VRAIMENT vierge, `grep -v` ne garde aucune
|
|
|
|
|
# ligne et sort en 1 — `pipefail` faisait alors echouer la mesure precisement dans le cas
|
|
|
|
|
# qu'elle doit reconnaitre (reconstruction de Chezlepro, 2026-09-30).
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
- name: Restauration — l'annuaire est-il vierge ?
|
|
|
|
|
ansible.builtin.shell: >-
|
|
|
|
|
set -o pipefail;
|
2026-09-30 03:56:42 -04:00
|
|
|
slapcat -b '{{ serveur_openldap_base_dn }}' 2>/dev/null
|
|
|
|
|
| awk -v base='dn: {{ serveur_openldap_base_dn | lower }}'
|
|
|
|
|
'tolower($0) ~ /^dn: / && tolower($0) != base && tolower($0) != "dn: cn=admin," substr(base, 5) {n++}
|
|
|
|
|
END {print n + 0}'
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
args:
|
|
|
|
|
executable: /bin/bash
|
|
|
|
|
register: serveur_openldap_entrees_initiales
|
|
|
|
|
changed_when: false
|
|
|
|
|
check_mode: false
|
|
|
|
|
|
annuaire : un compte de service par consommateur, et la porte se ferme
Keycloak, Dovecot, Postfix et Icinga Web 2 se liaient TOUS avec cn=admin, le compte
d administration de la base. C est le rootDN : slapd lui fait contourner toutes les
ACL. Un seul secret, quatre services, tous les droits sur l arbre — pour ce qui est,
trois fois sur quatre, une simple lecture.
Et les droits livres par Debian etaient intacts : `to * by * read`. Sur ldap://, sans
s authentifier, une machine du reseau enumerait tous les comptes et toutes les
adresses. Des comptes a droits mesures n auraient rien valu tant que cette ligne
restait : on aurait ferme la porte en laissant la fenetre.
L indice etait deja dans le depot. `validatePasswordPolicy` existe parce que slapd
n applique pas ses controles de qualite au rootDN : la consequence etait compensee,
la cause intacte.
- ou=services, un compte par consommateur, secret propre en voute
- sept regles d acces posees EN ENTIER (state: exact) : l ordre est la regle, et
inserer c est parier sur ce que le paquet aura mis avant nous
- amorcage_acces garde le compte d administration, NOMME comme l exception : il ne
consomme pas l annuaire, il le provisionne depuis la socket locale
- la sonde passe de -x a -Y EXTERNAL : elle lisait en anonyme et aurait annonce un
annuaire VIDE sur un annuaire parfaitement sain
- la rotation du compte d administration devient possible (elle n etait posee qu a
l installation, par debconf : la voute et slapd divergeaient en silence)
Quatre marches payees en chemin :
1. un cinquieme appelant oublie, dont l echec etait masque par no_log — la garde
refuse desormais SANS no_log : elle nomme la cle absente, jamais son contenu
2. la federation Keycloak ne reecrivait son bindDn que si l URL ou le mode changeaient
— nouveau secret, ancien nom, error code 49
3. la rotation placee APRES les taches qui se lient en administrateur
4. ansible-vault et son tube : sortie non bloquante = echec silencieux, la voute
paraissait tournee et etait identique a l octet
P72 exige que tout role incluant resoudre_annuaire NOMME son compte, et qu aucun sauf
amorcage_acces ne nomme admin. Eprouvee dans les deux sens.
Verifie sur l infrastructure : chaque compte lit ce qu il doit, aucun ne voit les
autres, la lecture anonyme rend 0 entree, et les quatre services repondent (doveadm
user, postmap -q, decouverte OIDC 200, portier SSO 200).
vault_openldap_admin et vault_ldap_bind_postfix renouveles : les deux avaient transite
en clair par une session d exploitation. Les anciennes valeurs rendent Invalid
credentials (49).
make prouver : 71 OK, 0 echec, 1 saute. ansible-lint : 0 failure, profil production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-13 13:36:38 -04:00
|
|
|
# LA ROTATION PASSE AVANT TOUT CE QUI SE LIE EN ADMINISTRATEUR (2026-09-13).
|
|
|
|
|
#
|
|
|
|
|
# Placee plus bas, elle arrivait trop tard : « Creer les unites organisationnelles » se
|
|
|
|
|
# lie deja avec le mot de passe de la VOUTE, tandis que slapd detient encore l'ANCIEN.
|
|
|
|
|
# Le deploiement echouait sur la huitieme tache, et `no_log` — qui protege la valeur —
|
|
|
|
|
# masquait aussi la cause. Un secret qu'on fait tourner doit descendre AVANT que quoi que
|
|
|
|
|
# ce soit s'en serve.
|
|
|
|
|
#
|
|
|
|
|
# Ces taches-ci n'ont pas ce probleme : elles ecrivent par `ldapi:///` en s'identifiant
|
|
|
|
|
# par la socket unix (root local), sans mot de passe. C'est precisement ce qui leur
|
|
|
|
|
# permet de reparer la liaison qu'elles changent.
|
|
|
|
|
- name: Trouver la base mdb (pour y poser les droits)
|
|
|
|
|
community.general.ldap_search:
|
|
|
|
|
dn: "cn=config"
|
|
|
|
|
scope: onelevel
|
|
|
|
|
filter: "(olcDatabase={1}mdb)"
|
|
|
|
|
attrs:
|
|
|
|
|
- dn
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
register: serveur_openldap_base_droits
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Retenir le DN de la base pour les droits
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
serveur_openldap_droits_dn: "{{ (serveur_openldap_base_droits.results | first).dn }}"
|
|
|
|
|
when: (serveur_openldap_base_droits.results | default([]) | length) > 0
|
|
|
|
|
|
|
|
|
|
# --- ROTATION DU COMPTE D'ADMINISTRATION (2026-09-13) -------------------------------
|
|
|
|
|
#
|
|
|
|
|
# CE MOT DE PASSE N'ETAIT POSE QU'A L'INSTALLATION, par debconf. Le faire tourner en
|
|
|
|
|
# voute ne descendait donc nulle part : slapd gardait l'ancien, la voute annoncait le
|
|
|
|
|
# neuf, et les deux divergeaient EN SILENCE. Le premier a s'en apercevoir aurait ete
|
|
|
|
|
# `amorcage_acces`, au pire moment — quand on cree un acces.
|
|
|
|
|
#
|
|
|
|
|
# Un secret qu'on ne peut pas faire tourner est un secret qu'on ne fera pas tourner.
|
|
|
|
|
#
|
|
|
|
|
# `slappasswd` SALE le condensat : deux appels sur la meme valeur rendent deux chaines
|
|
|
|
|
# differentes, et comparer l'existant ne dit donc rien. On memorise l'empreinte de la
|
|
|
|
|
# valeur VOULUE, comme la federation Keycloak le fait pour sa liaison — meme probleme,
|
|
|
|
|
# meme remede, et c'est le signe qu'il s'agit d'un patron, pas d'un bricolage.
|
|
|
|
|
- name: Lire l'empreinte du mot de passe d'administration en place
|
|
|
|
|
ansible.builtin.slurp:
|
|
|
|
|
src: "{{ serveur_openldap_marqueur_admin }}"
|
|
|
|
|
register: serveur_openldap_marqueur_lu
|
|
|
|
|
failed_when: false
|
|
|
|
|
changed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Hacher le mot de passe d'administration voulu
|
|
|
|
|
ansible.builtin.command:
|
|
|
|
|
argv: ["slappasswd", "-s", "{{ serveur_openldap_admin_password }}"]
|
|
|
|
|
register: serveur_openldap_admin_hash
|
|
|
|
|
changed_when: false
|
|
|
|
|
no_log: true
|
|
|
|
|
when: serveur_openldap_admin_empreinte != (serveur_openldap_marqueur_lu.content | default('') | b64decode | trim)
|
|
|
|
|
|
|
|
|
|
- name: Aligner le mot de passe d'administration de l'annuaire sur la voute
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: "{{ serveur_openldap_droits_dn }}"
|
|
|
|
|
attributes:
|
|
|
|
|
olcRootPW: "{{ serveur_openldap_admin_hash.stdout | trim }}"
|
|
|
|
|
state: exact
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
no_log: true
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_droits_dn | default('') | length > 0
|
|
|
|
|
- serveur_openldap_admin_hash is not skipped
|
|
|
|
|
|
|
|
|
|
# LE MARQUEUR S'ECRIT APRES, JAMAIS AVANT. Ecrit d'abord, une pose ratee laisserait le
|
|
|
|
|
# depot convaincu d'avoir fait tourner un secret qui n'a pas bouge — et la prochaine
|
|
|
|
|
# execution ne retenterait rien.
|
|
|
|
|
- name: Retenir l'empreinte du mot de passe d'administration pose
|
|
|
|
|
ansible.builtin.copy:
|
|
|
|
|
content: "{{ serveur_openldap_admin_empreinte }}\n"
|
|
|
|
|
dest: "{{ serveur_openldap_marqueur_admin }}"
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0600"
|
|
|
|
|
when: serveur_openldap_admin_hash is not skipped
|
|
|
|
|
|
2026-06-24 20:17:46 -04:00
|
|
|
- name: Creer les unites organisationnelles de base
|
|
|
|
|
community.general.ldap_entry:
|
|
|
|
|
dn: "ou={{ item }},{{ serveur_openldap_base_dn }}"
|
|
|
|
|
objectClass: organizationalUnit
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
loop: "{{ serveur_openldap_ou }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "ou={{ item }}"
|
|
|
|
|
no_log: true
|
2026-07-02 07:27:43 -04:00
|
|
|
|
annuaire : un compte de service par consommateur, et la porte se ferme
Keycloak, Dovecot, Postfix et Icinga Web 2 se liaient TOUS avec cn=admin, le compte
d administration de la base. C est le rootDN : slapd lui fait contourner toutes les
ACL. Un seul secret, quatre services, tous les droits sur l arbre — pour ce qui est,
trois fois sur quatre, une simple lecture.
Et les droits livres par Debian etaient intacts : `to * by * read`. Sur ldap://, sans
s authentifier, une machine du reseau enumerait tous les comptes et toutes les
adresses. Des comptes a droits mesures n auraient rien valu tant que cette ligne
restait : on aurait ferme la porte en laissant la fenetre.
L indice etait deja dans le depot. `validatePasswordPolicy` existe parce que slapd
n applique pas ses controles de qualite au rootDN : la consequence etait compensee,
la cause intacte.
- ou=services, un compte par consommateur, secret propre en voute
- sept regles d acces posees EN ENTIER (state: exact) : l ordre est la regle, et
inserer c est parier sur ce que le paquet aura mis avant nous
- amorcage_acces garde le compte d administration, NOMME comme l exception : il ne
consomme pas l annuaire, il le provisionne depuis la socket locale
- la sonde passe de -x a -Y EXTERNAL : elle lisait en anonyme et aurait annonce un
annuaire VIDE sur un annuaire parfaitement sain
- la rotation du compte d administration devient possible (elle n etait posee qu a
l installation, par debconf : la voute et slapd divergeaient en silence)
Quatre marches payees en chemin :
1. un cinquieme appelant oublie, dont l echec etait masque par no_log — la garde
refuse desormais SANS no_log : elle nomme la cle absente, jamais son contenu
2. la federation Keycloak ne reecrivait son bindDn que si l URL ou le mode changeaient
— nouveau secret, ancien nom, error code 49
3. la rotation placee APRES les taches qui se lient en administrateur
4. ansible-vault et son tube : sortie non bloquante = echec silencieux, la voute
paraissait tournee et etait identique a l octet
P72 exige que tout role incluant resoudre_annuaire NOMME son compte, et qu aucun sauf
amorcage_acces ne nomme admin. Eprouvee dans les deux sens.
Verifie sur l infrastructure : chaque compte lit ce qu il doit, aucun ne voit les
autres, la lecture anonyme rend 0 entree, et les quatre services repondent (doveadm
user, postmap -q, decouverte OIDC 200, portier SSO 200).
vault_openldap_admin et vault_ldap_bind_postfix renouveles : les deux avaient transite
en clair par une session d exploitation. Les anciennes valeurs rendent Invalid
credentials (49).
make prouver : 71 OK, 0 echec, 1 saute. ansible-lint : 0 failure, profil production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-13 13:36:38 -04:00
|
|
|
# --- COMPTES DE SERVICE (2026-09-13) ------------------------------------------------
|
|
|
|
|
#
|
|
|
|
|
# Quatre services interrogeaient l'annuaire avec son compte d'administration. Voir
|
|
|
|
|
# `defaults/main.yml` pour le raisonnement ; ici on cree les comptes et on pose les droits.
|
|
|
|
|
- name: Exiger un secret pour chaque compte de service
|
|
|
|
|
ansible.builtin.assert:
|
|
|
|
|
that:
|
|
|
|
|
- lookup('vars', item.secret, default='') | length > 0
|
|
|
|
|
fail_msg: >-
|
|
|
|
|
Le compte de service « {{ item.cn }} » n'a pas de secret : {{ item.secret }} est
|
|
|
|
|
absent ou vide dans la voute. Un compte sans mot de passe ne se lie pas, et le
|
|
|
|
|
service qui en depend echouerait a la premiere requete.
|
|
|
|
|
loop: "{{ serveur_openldap_comptes_service }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.cn }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
- name: Creer les comptes de service de l'annuaire
|
|
|
|
|
community.general.ldap_entry:
|
|
|
|
|
dn: "cn={{ item.cn }},{{ serveur_openldap_services_dn }}"
|
|
|
|
|
objectClass:
|
|
|
|
|
- simpleSecurityObject
|
|
|
|
|
- organizationalRole
|
|
|
|
|
attributes:
|
|
|
|
|
description: "{{ item.raison }}"
|
|
|
|
|
userPassword: "{{ lookup('vars', item.secret) }}"
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
loop: "{{ serveur_openldap_comptes_service }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.cn }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
# `ldap_entry` ne fait que CREER : un secret tourne en voute ne descendrait jamais dans
|
|
|
|
|
# l'annuaire, et la rotation paraitrait faite. `ldap_passwd` compare avant d'ecrire, donc
|
|
|
|
|
# il est idempotent ET il suit la voute. La lecon est deja celle de la politique de mots
|
|
|
|
|
# de passe, quinze lignes plus bas.
|
|
|
|
|
- name: Aligner le mot de passe de chaque compte de service sur la voute
|
|
|
|
|
community.general.ldap_passwd:
|
|
|
|
|
dn: "cn={{ item.cn }},{{ serveur_openldap_services_dn }}"
|
|
|
|
|
passwd: "{{ lookup('vars', item.secret) }}"
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
loop: "{{ serveur_openldap_comptes_service }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.cn }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
|
|
|
|
|
# L'ORDRE DES REGLES EST LA REGLE. slapd applique la PREMIERE dont la cible correspond et
|
|
|
|
|
# s'arrete : une regle generale placee trop haut rend muettes toutes celles qui suivent.
|
|
|
|
|
# On pose donc la liste ENTIERE (`state: exact`) plutot que d'inserer — inserer, ici,
|
|
|
|
|
# c'est parier sur ce que le paquet Debian aura mis avant nous.
|
|
|
|
|
#
|
|
|
|
|
# {0} LES MOTS DE PASSE, D'ABORD. Cette regle porte sur un ATTRIBUT : elle vaut pour
|
|
|
|
|
# toutes les entrees, comptes de service compris — c'est elle qui leur permet de se
|
|
|
|
|
# lier (`by anonymous auth`). La retirer ou la deplacer plus bas ferme l'annuaire a
|
|
|
|
|
# tout le monde, y compris a l'exploitant.
|
|
|
|
|
# {2} LES COMPTES DE SERVICE NE SE VOIENT PAS ENTRE EUX. Compromettre Postfix ne doit pas
|
|
|
|
|
# livrer le compte de Keycloak. Le rootDN, lui, contourne les ACL : l'exploitant garde
|
|
|
|
|
# la main.
|
|
|
|
|
# {3} LES PERSONNES. Keycloak ecrit (mots de passe, creations) ; les trois autres lisent ;
|
|
|
|
|
# chacun se lit soi-meme.
|
|
|
|
|
# {5} LE RACINE DE L'ANNUAIRE reste lisible : sans lui, aucun client ne peut meme
|
|
|
|
|
# decouvrir les contextes servis, et les messages parlent alors de « base introuvable ».
|
|
|
|
|
- name: Poser les droits d'acces de l'annuaire
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: "{{ serveur_openldap_droits_dn }}"
|
|
|
|
|
attributes:
|
|
|
|
|
olcAccess: "{{ serveur_openldap_acces }}"
|
|
|
|
|
state: exact
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
when: serveur_openldap_droits_dn | default('') | length > 0
|
|
|
|
|
|
2026-08-07 13:52:00 -04:00
|
|
|
# --- Politique de mot de passe (overlay ppolicy) ------------------------------
|
|
|
|
|
# Sans cet overlay, `pwdReset` n'existe pas dans le schema : `amorcage_acces` ne peut
|
|
|
|
|
# pas forcer le changement du jeton d'amorcage, et rien ne contraint la qualite ni ne
|
|
|
|
|
# verrouille apres des echecs. Voir docs/autorisation.md §3.
|
|
|
|
|
- name: Ppolicy — Charger le module
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: "cn=module{0},cn=config"
|
|
|
|
|
attributes:
|
|
|
|
|
olcModuleLoad: "ppolicy"
|
|
|
|
|
state: present
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
|
|
|
|
# Le DN de la base varie (`olcDatabase={1}mdb` en general, mais l'index n'est pas
|
|
|
|
|
# garanti) : on le LIT au lieu de le supposer.
|
|
|
|
|
- name: Ppolicy — Trouver la base mdb
|
|
|
|
|
community.general.ldap_search:
|
|
|
|
|
dn: "cn=config"
|
|
|
|
|
scope: onelevel
|
|
|
|
|
filter: "(olcDatabase={1}mdb)"
|
|
|
|
|
attrs:
|
|
|
|
|
- dn
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
register: serveur_openldap_base_mdb
|
|
|
|
|
changed_when: false
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
|
|
|
|
- name: Ppolicy — Retenir le DN de la base
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
serveur_openldap_mdb_dn: >-
|
|
|
|
|
{{ (serveur_openldap_base_mdb.results | first).dn }}
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
- (serveur_openldap_base_mdb.results | default([]) | length) > 0
|
|
|
|
|
|
identite : une declaration de politique de mot de passe, deux executants
Quatre defauts mesures dans l'integration Keycloak/LDAP, meme famille : une
valeur declaree d'un cote, consommee de l'autre, rien qui verifie la jonction.
1. Aucune regle ne s'appliquait sur le chemin d'un vrai utilisateur. Sonde :
« abcd » refuse par l'operation etendue LDAP, accepte par Keycloak (204),
puis actif pour l'authentification. Keycloak ecrivait userPassword en
direct (ppolicy aveugle) et le realm n'avait aucune passwordPolicy.
2. ldap_entry ne fait que CREER : la politique etait figee a sa creation. Le
depot disait pwdMustChange TRUE, le serveur FALSE — une reconstruction
from-zero aurait ressuscite la boucle du 2026-08-07. ldap_attrs state=exact
reconcilie la politique et l'overlay (DN lu, pas devine).
3. syncRegistrations absent : un compte cree dans Keycloak n'atteignait jamais
ou=people — acces web, aucune boite, invisible du modele de groupes.
4. Le prenom pointait sur cn (nom complet) : « Administrateur systeme systeme ».
Ajoute roles/resoudre_politique_mdp : LA declaration, traduite en pwdPolicy,
passwordPolicy et anti-force-brute. Les deux roles la consomment sans la
redeclarer.
usePasswordModifyExtendedOp ET validatePasswordPolicy : la seconde est
porteuse, Keycloak se liant en rootDN et slapd n'appliquant pas ses controles
de qualite au rootDN. La premiere seule aurait paru juste sans tenir.
Verification : abcd -> 400 « minimum length 12 » et absent de LDAP ; mot de
passe conforme -> 204 puis ldapwhoami accepte ; POST users -> 201 ET present
dans ou=people. Second passage des deux playbooks : changed=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 06:28:10 -04:00
|
|
|
- name: Ppolicy — Résoudre la politique (déclaration unique)
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: resoudre_politique_mdp
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
2026-08-07 13:52:00 -04:00
|
|
|
- name: Ppolicy — Creer l unite des politiques
|
|
|
|
|
community.general.ldap_entry:
|
|
|
|
|
dn: "ou=policies,{{ serveur_openldap_base_dn }}"
|
|
|
|
|
objectClass: organizationalUnit
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
|
|
|
|
# L'overlay AVANT la politique : `olcPPolicyDefault` reference une entree qui doit
|
|
|
|
|
# exister, mais l'overlay doit etre en place pour que le schema pwd* soit connu.
|
|
|
|
|
# L'ordre inverse echouerait des deux cotes.
|
|
|
|
|
- name: Ppolicy — Activer l overlay sur la base
|
|
|
|
|
community.general.ldap_entry:
|
|
|
|
|
dn: "olcOverlay=ppolicy,{{ serveur_openldap_mdb_dn }}"
|
|
|
|
|
objectClass:
|
|
|
|
|
- olcOverlayConfig
|
|
|
|
|
- olcPPolicyConfig
|
|
|
|
|
attributes:
|
|
|
|
|
olcOverlay: "ppolicy"
|
|
|
|
|
olcPPolicyDefault: "cn=default,ou=policies,{{ serveur_openldap_base_dn }}"
|
|
|
|
|
olcPPolicyHashCleartext: "{{ 'TRUE' if serveur_openldap_ppolicy_hash_cleartext | bool else 'FALSE' }}"
|
|
|
|
|
olcPPolicyUseLockout: "{{ 'TRUE' if serveur_openldap_ppolicy_use_lockout | bool else 'FALSE' }}"
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
- serveur_openldap_mdb_dn is defined
|
|
|
|
|
|
|
|
|
|
- name: Ppolicy — Creer la politique par defaut
|
|
|
|
|
community.general.ldap_entry:
|
|
|
|
|
dn: "cn=default,ou=policies,{{ serveur_openldap_base_dn }}"
|
|
|
|
|
objectClass:
|
|
|
|
|
- pwdPolicy
|
|
|
|
|
- person
|
|
|
|
|
- top
|
|
|
|
|
attributes: >-
|
identite : une declaration de politique de mot de passe, deux executants
Quatre defauts mesures dans l'integration Keycloak/LDAP, meme famille : une
valeur declaree d'un cote, consommee de l'autre, rien qui verifie la jonction.
1. Aucune regle ne s'appliquait sur le chemin d'un vrai utilisateur. Sonde :
« abcd » refuse par l'operation etendue LDAP, accepte par Keycloak (204),
puis actif pour l'authentification. Keycloak ecrivait userPassword en
direct (ppolicy aveugle) et le realm n'avait aucune passwordPolicy.
2. ldap_entry ne fait que CREER : la politique etait figee a sa creation. Le
depot disait pwdMustChange TRUE, le serveur FALSE — une reconstruction
from-zero aurait ressuscite la boucle du 2026-08-07. ldap_attrs state=exact
reconcilie la politique et l'overlay (DN lu, pas devine).
3. syncRegistrations absent : un compte cree dans Keycloak n'atteignait jamais
ou=people — acces web, aucune boite, invisible du modele de groupes.
4. Le prenom pointait sur cn (nom complet) : « Administrateur systeme systeme ».
Ajoute roles/resoudre_politique_mdp : LA declaration, traduite en pwdPolicy,
passwordPolicy et anti-force-brute. Les deux roles la consomment sans la
redeclarer.
usePasswordModifyExtendedOp ET validatePasswordPolicy : la seconde est
porteuse, Keycloak se liant en rootDN et slapd n'appliquant pas ses controles
de qualite au rootDN. La premiere seule aurait paru juste sans tenir.
Verification : abcd -> 400 « minimum length 12 » et absent de LDAP ; mot de
passe conforme -> 204 puis ldapwhoami accepte ; POST users -> 201 ET present
dans ou=people. Second passage des deux playbooks : changed=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 06:28:10 -04:00
|
|
|
{{ {'cn': 'default', 'sn': 'default'}
|
|
|
|
|
| combine(resoudre_politique_mdp_ldap, serveur_openldap_ppolicy_extra) }}
|
2026-08-07 13:52:00 -04:00
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
identite : une declaration de politique de mot de passe, deux executants
Quatre defauts mesures dans l'integration Keycloak/LDAP, meme famille : une
valeur declaree d'un cote, consommee de l'autre, rien qui verifie la jonction.
1. Aucune regle ne s'appliquait sur le chemin d'un vrai utilisateur. Sonde :
« abcd » refuse par l'operation etendue LDAP, accepte par Keycloak (204),
puis actif pour l'authentification. Keycloak ecrivait userPassword en
direct (ppolicy aveugle) et le realm n'avait aucune passwordPolicy.
2. ldap_entry ne fait que CREER : la politique etait figee a sa creation. Le
depot disait pwdMustChange TRUE, le serveur FALSE — une reconstruction
from-zero aurait ressuscite la boucle du 2026-08-07. ldap_attrs state=exact
reconcilie la politique et l'overlay (DN lu, pas devine).
3. syncRegistrations absent : un compte cree dans Keycloak n'atteignait jamais
ou=people — acces web, aucune boite, invisible du modele de groupes.
4. Le prenom pointait sur cn (nom complet) : « Administrateur systeme systeme ».
Ajoute roles/resoudre_politique_mdp : LA declaration, traduite en pwdPolicy,
passwordPolicy et anti-force-brute. Les deux roles la consomment sans la
redeclarer.
usePasswordModifyExtendedOp ET validatePasswordPolicy : la seconde est
porteuse, Keycloak se liant en rootDN et slapd n'appliquant pas ses controles
de qualite au rootDN. La premiere seule aurait paru juste sans tenir.
Verification : abcd -> 400 « minimum length 12 » et absent de LDAP ; mot de
passe conforme -> 204 puis ldapwhoami accepte ; POST users -> 201 ET present
dans ou=people. Second passage des deux playbooks : changed=0.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-08 06:28:10 -04:00
|
|
|
# `ldap_entry` ne fait que CREER : l'entree restait figee a ce qu'elle valait le
|
|
|
|
|
# jour de sa creation, et toute modification ulterieure de la declaration etait
|
|
|
|
|
# ignoree en silence. Constate le 2026-08-08 — le depot annoncait
|
|
|
|
|
# `pwdMustChange: TRUE`, le serveur portait `FALSE` (corrige a la main apres la
|
|
|
|
|
# boucle de changement de mot de passe du 2026-08-07), et une reconstruction
|
|
|
|
|
# from-zero aurait ressuscite le defaut. Il faut donc RECONCILIER en plus.
|
|
|
|
|
- name: Ppolicy — Reconcilier la politique par defaut
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: "cn=default,ou=policies,{{ serveur_openldap_base_dn }}"
|
|
|
|
|
attributes: "{{ resoudre_politique_mdp_ldap | combine(serveur_openldap_ppolicy_extra) }}"
|
|
|
|
|
state: exact
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
when: serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
|
|
|
|
|
# Meme raison : l'overlay non plus n'etait pose qu'a la creation. Son DN porte un
|
|
|
|
|
# index d'ordre (`{0}`, `{1}`…) attribue par slapd — on le LIT, on ne le devine pas.
|
|
|
|
|
- name: Ppolicy — Trouver le DN de l overlay
|
|
|
|
|
community.general.ldap_search:
|
|
|
|
|
dn: "{{ serveur_openldap_mdb_dn }}"
|
|
|
|
|
scope: onelevel
|
|
|
|
|
filter: "(olcOverlay=*ppolicy)"
|
|
|
|
|
attrs:
|
|
|
|
|
- dn
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
register: serveur_openldap_overlay_ppolicy
|
|
|
|
|
changed_when: false
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
- serveur_openldap_mdb_dn is defined
|
|
|
|
|
|
|
|
|
|
- name: Ppolicy — Reconcilier les reglages de l overlay
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: "{{ (serveur_openldap_overlay_ppolicy.results | first).dn }}"
|
|
|
|
|
attributes:
|
|
|
|
|
olcPPolicyDefault: "cn=default,ou=policies,{{ serveur_openldap_base_dn }}"
|
|
|
|
|
olcPPolicyHashCleartext: "{{ 'TRUE' if serveur_openldap_ppolicy_hash_cleartext | bool else 'FALSE' }}"
|
|
|
|
|
olcPPolicyUseLockout: "{{ 'TRUE' if serveur_openldap_ppolicy_use_lockout | bool else 'FALSE' }}"
|
|
|
|
|
state: exact
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_ppolicy_actif | bool
|
|
|
|
|
- (serveur_openldap_overlay_ppolicy.results | default([]) | length) > 0
|
|
|
|
|
|
2026-07-02 07:27:43 -04:00
|
|
|
# --- TLS (LDAPS + STARTTLS) via le certificat step_ca depose par client_pki ---
|
|
|
|
|
- name: TLS — creer le repertoire pont lisible par openldap
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: "{{ serveur_openldap_tls_dir }}"
|
|
|
|
|
state: directory
|
|
|
|
|
owner: openldap
|
|
|
|
|
group: openldap
|
|
|
|
|
mode: "0750"
|
|
|
|
|
when: serveur_openldap_tls_actif | bool
|
|
|
|
|
|
|
|
|
|
- name: TLS — deployer le script de synchronisation du certificat
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: setops-slapd-cert-sync.sh.j2
|
|
|
|
|
dest: /usr/local/sbin/setops-slapd-cert-sync
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0755"
|
|
|
|
|
when: serveur_openldap_tls_actif | bool
|
|
|
|
|
|
|
|
|
|
- name: TLS — deployer les unites de synchronisation (service + path)
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: "{{ item.s }}"
|
|
|
|
|
dest: "{{ item.d }}"
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0644"
|
|
|
|
|
loop:
|
|
|
|
|
- { s: "setops-slapd-cert-sync.service.j2", d: "/etc/systemd/system/setops-slapd-cert-sync.service" }
|
|
|
|
|
- { s: "setops-slapd-cert-sync.path.j2", d: "/etc/systemd/system/setops-slapd-cert-sync.path" }
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.d | basename }}"
|
|
|
|
|
when: serveur_openldap_tls_actif | bool
|
|
|
|
|
|
|
|
|
|
- name: TLS — synchroniser le certificat maintenant (si client_pki l'a depose)
|
|
|
|
|
ansible.builtin.command: /usr/local/sbin/setops-slapd-cert-sync
|
|
|
|
|
changed_when: false
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_tls_actif | bool
|
|
|
|
|
- not ansible_check_mode
|
|
|
|
|
|
|
|
|
|
- name: TLS — activer la surveillance du certificat (renouvellement)
|
|
|
|
|
ansible.builtin.systemd:
|
|
|
|
|
name: setops-slapd-cert-sync.path
|
|
|
|
|
enabled: true
|
|
|
|
|
state: started
|
|
|
|
|
daemon_reload: true
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_tls_actif | bool
|
|
|
|
|
- not ansible_check_mode
|
|
|
|
|
|
|
|
|
|
- name: TLS — verifier que le certificat pont est en place
|
|
|
|
|
ansible.builtin.stat:
|
|
|
|
|
path: "{{ serveur_openldap_tls_dir }}/cert.pem"
|
|
|
|
|
register: serveur_openldap_cert_pont
|
|
|
|
|
when: serveur_openldap_tls_actif | bool
|
|
|
|
|
|
|
|
|
|
- name: TLS — avertir si le certificat n'est pas encore disponible
|
|
|
|
|
ansible.builtin.debug:
|
|
|
|
|
msg: >-
|
|
|
|
|
client_pki n'a pas encore depose de certificat sur ce noeud
|
|
|
|
|
({{ serveur_openldap_tls_source_cert }}). TLS slapd NON configure : deploie
|
|
|
|
|
l'integration client_pki sur ce noeud, puis relance le deploiement.
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_tls_actif | bool
|
|
|
|
|
- not ansible_check_mode
|
|
|
|
|
- not (serveur_openldap_cert_pont.stat.exists | default(false))
|
|
|
|
|
|
|
|
|
|
- name: TLS — configurer slapd (olcTLS* dans cn=config)
|
|
|
|
|
community.general.ldap_attrs:
|
|
|
|
|
dn: cn=config
|
|
|
|
|
server_uri: ldapi:///
|
|
|
|
|
attributes:
|
|
|
|
|
olcTLSCACertificateFile: "{{ serveur_openldap_tls_dir }}/ca.pem"
|
|
|
|
|
olcTLSCertificateFile: "{{ serveur_openldap_tls_dir }}/cert.pem"
|
|
|
|
|
olcTLSCertificateKeyFile: "{{ serveur_openldap_tls_dir }}/key.pem"
|
|
|
|
|
state: exact
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_tls_actif | bool
|
|
|
|
|
- not ansible_check_mode
|
|
|
|
|
- serveur_openldap_cert_pont.stat.exists | default(false)
|
|
|
|
|
notify: Redemarrer slapd
|
|
|
|
|
|
|
|
|
|
- name: TLS — exposer LDAPS (SLAPD_SERVICES)
|
|
|
|
|
ansible.builtin.lineinfile:
|
|
|
|
|
path: /etc/default/slapd
|
|
|
|
|
regexp: '^SLAPD_SERVICES='
|
|
|
|
|
line: 'SLAPD_SERVICES="{{ serveur_openldap_services }}"'
|
|
|
|
|
when:
|
|
|
|
|
- serveur_openldap_tls_actif | bool
|
|
|
|
|
- serveur_openldap_cert_pont.stat.exists | default(false)
|
|
|
|
|
notify: Redemarrer slapd
|
sondes : les cinq qui manquaient le plus (autorite, base, annuaire, zones, edge)
CORRECTION DE COMPTE D ABORD. J avais annonce cinq groupes sans sonde. La
mesure en donne VINGT-SEPT : j avais compte ceux que j avais en tete, pas
ceux que le depot contient. Il en reste vingt-deux.
LES CINQ, PAR ORDRE DE DEGAT SILENCIEUX.
autorite (step_ca) — la plus urgente : nos certificats vivent 24 h, une AC
muette ne casse rien aujourd hui et casse TOUT demain, d un coup, sur les
21 machines. Elle surveille aussi l expiration de la RACINE, que personne
ne regarde parce qu elle vit des annees (relevee a 3642 jours).
base (postgresql) — une VRAIE requete, pas pg_isready : celui-ci dit que
le port repond, pas que la base sert. Plus le compte des connexions : a
saturation, chaque application tombe sans que la base ait l air morte.
annuaire (openldap) — elle COMPTE les entrees. Un annuaire vide repond
success a tout : le mensonge des sauvegardes vides, vert et sans contenu.
zones (powerdns) — un autoritatif sans zone repond NXDOMAIN a tout, ce qui
se lit comme « ce nom n existe pas ».
edge (nginx) — elle valide la configuration SUR DISQUE : nginx sert la
derniere valide, et une configuration cassee ne se voit qu au prochain
demarrage, souvent des mois plus tard.
Les cinq eprouvees vertes sur le sain puis rouges PAR PARAMETRE, sans
toucher a un service.
Etat : 20 sondes sur 19 roles, 23 services distincts, 70 instances, 67 au
vert. Les trois autres sont connues : deux sauvegardes sans donnee a
emporter, et Loki en delai de stabilisation apres redeploiement.
make prouver : CONFORME, 64 OK, 0 echec, 0 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 03:47:03 -04:00
|
|
|
|
restauration : la reconstruction remet l'etat de l'incarnation precedente
Chaque role proprietaire (AC, bases, annuaire, Nextcloud, rspamd/DKIM,
courriel, forge, web) remet son etat au moment ou il le creerait neuf,
depuis le dernier instantane anterieur a la naissance de la machine.
La sauvegarde refuse de deposer tant qu'un etat d'avant attend.
Outil de noeud setops-restaurer ; cibles sauvegarder-maintenant,
restauration-etat, restauration-renoncer ; test_restauration.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-09-30 02:39:22 -04:00
|
|
|
# --- L'ANNUAIRE D'UNE INCARNATION PRECEDENTE (2026-09-30) ---------------------------
|
|
|
|
|
#
|
|
|
|
|
# EN FIN DE ROLE, PAS AU DEBUT. Le LDIF porte des attributs de `ppolicy` (`pwdChangedTime`,
|
|
|
|
|
# `pwdReset`...) que slapd refuse tant que l'overlay n'est pas charge — c'est-a-dire plus
|
|
|
|
|
# haut dans ce role. On remplace donc ce que le role vient de creer par ce qui vivait
|
|
|
|
|
# avant ; `setops-restaurer` le rejoue d'abord a blanc, et met la base neuve de cote.
|
|
|
|
|
#
|
|
|
|
|
# Sans ceci, une reconstruction rendait a `sysadmin` le mot de passe d'amorcage : c'est
|
|
|
|
|
# ainsi que l'absence de restauration a ete decouverte, le 2026-09-30.
|
|
|
|
|
- name: Restauration — l'annuaire d'une incarnation precedente ?
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: client_backup
|
|
|
|
|
tasks_from: restaurer.yml
|
|
|
|
|
vars:
|
|
|
|
|
client_backup_restaurer_jeu: serveur_openldap
|
|
|
|
|
client_backup_restaurer_vierge: "{{ (serveur_openldap_entrees_initiales.stdout | default('1') | int) == 0 }}"
|
|
|
|
|
|
|
|
|
|
- name: Restauration — remettre l'annuaire
|
|
|
|
|
changed_when: true
|
|
|
|
|
ansible.builtin.command:
|
|
|
|
|
argv:
|
|
|
|
|
- /usr/local/sbin/setops-restaurer
|
|
|
|
|
- annuaire
|
|
|
|
|
- --instantane
|
|
|
|
|
- "{{ client_backup_restauration.instantane }}"
|
|
|
|
|
- "{{ serveur_openldap_base_dn }}"
|
|
|
|
|
when: client_backup_restauration.etat == 'a_restaurer'
|
|
|
|
|
|
|
|
|
|
# Les comptes de service reviennent avec le mot de passe de l'EPOQUE. On les realigne sur
|
|
|
|
|
# la voute tout de suite : Keycloak, Postfix et Dovecot s'y lient avec la valeur actuelle.
|
|
|
|
|
- name: Restauration — realigner les comptes de service sur la voute
|
|
|
|
|
community.general.ldap_passwd:
|
|
|
|
|
dn: "cn={{ item.cn }},{{ serveur_openldap_services_dn }}"
|
|
|
|
|
passwd: "{{ lookup('vars', item.secret) }}"
|
|
|
|
|
server_uri: "ldapi:///"
|
|
|
|
|
bind_dn: "{{ serveur_openldap_admin_dn }}"
|
|
|
|
|
bind_pw: "{{ serveur_openldap_admin_password }}"
|
|
|
|
|
loop: "{{ serveur_openldap_comptes_service }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.cn }}"
|
|
|
|
|
no_log: true
|
|
|
|
|
when: client_backup_restauration.etat == 'a_restaurer'
|
|
|
|
|
|
|
|
|
|
- name: Restauration — acter l'annuaire remis
|
|
|
|
|
ansible.builtin.include_role:
|
|
|
|
|
name: client_backup
|
|
|
|
|
tasks_from: acter.yml
|
|
|
|
|
vars:
|
|
|
|
|
client_backup_acter_etat: restaure
|
|
|
|
|
when: client_backup_restauration.etat == 'a_restaurer'
|
|
|
|
|
|
sondes : les cinq qui manquaient le plus (autorite, base, annuaire, zones, edge)
CORRECTION DE COMPTE D ABORD. J avais annonce cinq groupes sans sonde. La
mesure en donne VINGT-SEPT : j avais compte ceux que j avais en tete, pas
ceux que le depot contient. Il en reste vingt-deux.
LES CINQ, PAR ORDRE DE DEGAT SILENCIEUX.
autorite (step_ca) — la plus urgente : nos certificats vivent 24 h, une AC
muette ne casse rien aujourd hui et casse TOUT demain, d un coup, sur les
21 machines. Elle surveille aussi l expiration de la RACINE, que personne
ne regarde parce qu elle vit des annees (relevee a 3642 jours).
base (postgresql) — une VRAIE requete, pas pg_isready : celui-ci dit que
le port repond, pas que la base sert. Plus le compte des connexions : a
saturation, chaque application tombe sans que la base ait l air morte.
annuaire (openldap) — elle COMPTE les entrees. Un annuaire vide repond
success a tout : le mensonge des sauvegardes vides, vert et sans contenu.
zones (powerdns) — un autoritatif sans zone repond NXDOMAIN a tout, ce qui
se lit comme « ce nom n existe pas ».
edge (nginx) — elle valide la configuration SUR DISQUE : nginx sert la
derniere valide, et une configuration cassee ne se voit qu au prochain
demarrage, souvent des mois plus tard.
Les cinq eprouvees vertes sur le sain puis rouges PAR PARAMETRE, sans
toucher a un service.
Etat : 20 sondes sur 19 roles, 23 services distincts, 70 instances, 67 au
vert. Les trois autres sont connues : deux sauvegardes sans donnee a
emporter, et Loki en delai de stabilisation apres redeploiement.
make prouver : CONFORME, 64 OK, 0 echec, 0 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
2026-09-10 03:47:03 -04:00
|
|
|
# --- Sonde de supervision (docs/supervision-conception.md) --------------------------
|
|
|
|
|
# Le role qui possede la verite depose sa propre sonde ; le porteur (`client_sante`) la
|
|
|
|
|
# fait tourner et pousse le verdict, sans savoir ce qu'elle mesure.
|
|
|
|
|
- name: Assurer le repertoire des sondes de supervision
|
|
|
|
|
ansible.builtin.file:
|
|
|
|
|
path: /usr/local/lib/setops/sondes
|
|
|
|
|
state: directory
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0755"
|
|
|
|
|
|
|
|
|
|
- name: Deposer la sonde « annuaire »
|
|
|
|
|
ansible.builtin.template:
|
|
|
|
|
src: sonde-annuaire.sh.j2
|
|
|
|
|
dest: /usr/local/lib/setops/sondes/annuaire.sh
|
|
|
|
|
owner: root
|
|
|
|
|
group: root
|
|
|
|
|
mode: "0750"
|