Set-OPS-Public/roles/amorcage_acces/tasks/main.yml
Daniel Allaire ba70b80197 amorcage_acces : le role qui cree UN acces puis se retire
Cree uid=sysadmin et cn=sysadmin dans LDAP. Prouve sur idm-01 : le compte
s'authentifie, et le second passage ne touche a rien (changed=0, 7 taches
sautees) — idempotence par EXISTENCE, pas par conformite (D-67).

Il suit l'annuaire au lieu de se declarer au plan : il ecrit par `ldapi:///` et
doit tourner sur cet hote. Le declarer comme groupe obligerait chaque instance a
le poser sur le bon hote, et elles ne le nomment pas pareil (idm-01 ici,
id-ldap-01 chez Technolibre) — je l'ai d'abord pose sur infra-pki-01 par erreur.

Trois defauts trouves en le construisant :

1. `pwdReset` n'existe pas dans ce schema (overlay ppolicy non charge) :
   l'entree entiere etait rejetee et `no_log` masquait la cause. J'avais suppose
   un mecanisme sans verifier. Le role le DETECTE maintenant, et la doctrine ne
   promet plus un changement force qui n'a pas lieu.

2. Le mot de passe aurait ete stocke EN CLAIR : `ldap_entry` ecrit userPassword
   litteralement. Hache par `slappasswd -h {SSHA}` desormais.

3. `voute.py` ne scannait que roles/<groupe> : un role applique par un playbook
   sans etre un groupe echappait au recensement, ce que D-20 interdit. Il suit
   maintenant les listes `roles:` des playbooks.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-07 13:42:27 -04:00

165 lines
6.2 KiB
YAML

---
# Amorcage des acces — D-67. Voir defaults/main.yml pour la doctrine, et
# docs/autorisation.md §6 pour le runbook de reprise.
- name: Résoudre la connexion à l'annuaire
ansible.builtin.include_role:
name: resoudre_annuaire
- name: Exiger le secret d'amorçage et le mot de passe d'annuaire (Vault)
ansible.builtin.assert:
that:
- amorcage_acces_secret | length > 0
- amorcage_acces_admin_password | length > 0
fail_msg: >-
`vault_sysadmin_amorcage` et `vault_openldap_admin` sont requis (voûte).
Le premier est un jeton d'amorçage à usage unique — pas un mot de passe
permanent : voir docs/autorisation.md §6.
when: amorcage_acces_actif | bool
# --- LE CŒUR DU RÔLE : on REGARDE avant d'agir --------------------------------
# La condition n'est pas la conformité, c'est l'EXISTENCE. Un compte présent est
# laissé strictement intact, quel que soit son état — c'est ce qui distingue ce
# rôle de tous les autres du dépôt (D-67).
- name: Le compte d'amorçage existe-t-il déjà ?
community.general.ldap_search:
dn: "ou=people,{{ resoudre_annuaire_base_dn }}"
scope: onelevel
filter: "(uid={{ amorcage_acces_uid }})"
server_uri: "ldapi:///"
bind_dn: "{{ resoudre_annuaire_bind_dn }}"
bind_pw: "{{ amorcage_acces_admin_password }}"
register: amorcage_acces_existant
changed_when: false
no_log: true
when: amorcage_acces_actif | bool
- name: Retenir si l'amorçage a déjà eu lieu
ansible.builtin.set_fact:
amorcage_acces_deja_fait: >-
{{ (amorcage_acces_existant.results | default([]) | length) > 0 }}
when: amorcage_acces_actif | bool
- name: Annoncer que l'amorçage est déjà fait (aucune action)
ansible.builtin.debug:
msg: >-
Compte `{{ amorcage_acces_uid }}` déjà présent : Set-OPS n'y touche pas.
Les habilitations sont gouvernées par une personne (D-67) — voir
docs/autorisation.md §6.
when:
- amorcage_acces_actif | bool
- amorcage_acces_deja_fait | bool
# --- Tout ce qui suit ne s'exécute QUE si le compte est absent -----------------
# Le mot de passe est HACHÉ par slapd lui-même. `ldap_entry` écrirait la chaîne
# littéralement : le jeton d'amorçage se retrouverait en clair dans la base, lisible
# par quiconque peut lire l'annuaire.
- name: Hacher le jeton d'amorçage (slappasswd, SSHA)
ansible.builtin.command:
argv:
- slappasswd
- "-h"
- "{SSHA}"
- "-s"
- "{{ amorcage_acces_secret }}"
register: amorcage_acces_hache
changed_when: false
no_log: true
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool
# Le changement forcé s'appuie sur `pwdReset`, qui vient de l'overlay `ppolicy`.
# On le DÉTECTE au lieu de le supposer : sans l'overlay, l'attribut est inconnu du
# schéma et l'entrée entière est rejetée — panne obscure, et le compte n'existe pas
# du tout. Mesuré le 2026-08-07 : seul `back_mdb` était chargé.
- name: L'overlay ppolicy est-il chargé (attribut `pwdReset` connu) ?
ansible.builtin.command:
argv:
- ldapsearch
- "-Y"
- EXTERNAL
- "-H"
- "ldapi:///"
- "-b"
- "cn=schema,cn=config"
- "(olcAttributeTypes=*pwdReset*)"
- dn
register: amorcage_acces_ppolicy
changed_when: false
failed_when: false
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool
- name: Retenir si le changement forcé est applicable
ansible.builtin.set_fact:
amorcage_acces_reset_possible: >-
{{ amorcage_acces_changement_force | bool
and 'dn:' in (amorcage_acces_ppolicy.stdout | default('')) }}
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool
- name: Créer le compte d'amorçage du sysadmin
community.general.ldap_entry:
dn: "uid={{ amorcage_acces_uid }},ou=people,{{ resoudre_annuaire_base_dn }}"
objectClass:
- inetOrgPerson
- organizationalPerson
- person
- top
attributes:
uid: "{{ amorcage_acces_uid }}"
cn: "{{ amorcage_acces_nom }}"
sn: "{{ amorcage_acces_nom.split(' ') | last }}"
userPassword: "{{ amorcage_acces_hache.stdout | trim }}"
pwdReset: "{{ 'TRUE' if amorcage_acces_reset_possible | bool else omit }}"
mail: "{{ amorcage_acces_courriel | default(omit, true) }}"
server_uri: "ldapi:///"
bind_dn: "{{ resoudre_annuaire_bind_dn }}"
bind_pw: "{{ amorcage_acces_admin_password }}"
no_log: true
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool
# `groupOfNames` EXIGE au moins un membre : un groupe vide est refusé par le
# schéma — ce qui tombe bien, un groupe d'habilitation sans personne n'aurait
# aucun sens à l'amorçage.
- name: Créer le groupe d'habilitation avec le sysadmin pour membre
community.general.ldap_entry:
dn: "cn={{ amorcage_acces_groupe }},ou=groups,{{ resoudre_annuaire_base_dn }}"
objectClass:
- groupOfNames
- top
attributes:
cn: "{{ amorcage_acces_groupe }}"
member: "uid={{ amorcage_acces_uid }},ou=people,{{ resoudre_annuaire_base_dn }}"
description: >-
Habilitation d'administration. Amorcé par Set-OPS, gouverné ensuite par
une personne — le dépôt ne réconcilie pas ses membres (D-67).
server_uri: "ldapi:///"
bind_dn: "{{ resoudre_annuaire_bind_dn }}"
bind_pw: "{{ amorcage_acces_admin_password }}"
no_log: true
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool
- name: Annoncer la reprise en main
ansible.builtin.debug:
msg: >-
{{ [
'Accès d amorçage créé : uid=' ~ amorcage_acces_uid ~ ', groupe=' ~ amorcage_acces_groupe ~ '.',
'Mot de passe en voûte sous `vault_sysadmin_amorcage`.',
(amorcage_acces_reset_possible | bool)
| ternary('Changement FORCÉ à la première ouverture (ppolicy actif).',
'ATTENTION : rien ne force le changement — l overlay ppolicy n est pas chargé. '
~ 'Le changer à la main dès la première connexion (docs/autorisation.md §6).'),
'À partir d ici, Set-OPS ne touche plus aux habilitations (D-67).'
] }}
when:
- amorcage_acces_actif | bool
- not amorcage_acces_deja_fait | bool