139 lines
5.5 KiB
YAML
139 lines
5.5 KiB
YAML
|
|
---
|
||
|
|
# Devis d'identite — RELEVE seul. Ne modifie rien (D-23 : un devis se lit d'abord).
|
||
|
|
#
|
||
|
|
# Le playbook collecte deux dictionnaires — ce que le depot DECLARE, ce que la machine
|
||
|
|
# PORTE — et les depose en JSON sur le controleur. La comparaison est faite par
|
||
|
|
# `scripts/devis_identite.py` : elle n'a rien a faire en Jinja, et le depot a deja
|
||
|
|
# cette forme (devis_opnsense, devis_sdn : Python raisonne, Ansible releve).
|
||
|
|
#
|
||
|
|
# Pourquoi ce devis existe. Les 30 preuves de `prouver.py` sont STATIQUES : elles
|
||
|
|
# montrent que le depot est coherent avec lui-meme. Aucune ne demande au systeme
|
||
|
|
# deploye s'il ressemble a ce que le depot annonce. Les quatre defauts du 2026-08-08
|
||
|
|
# etaient tous de ce second type — chacun trouve en relisant apres avoir ecrit,
|
||
|
|
# aucun signale par un test.
|
||
|
|
#
|
||
|
|
# make identite-plan
|
||
|
|
|
||
|
|
- name: Devis d'identité — relever le déclaré et le réel
|
||
|
|
hosts: serveur_keycloak
|
||
|
|
become: true
|
||
|
|
gather_facts: false
|
||
|
|
|
||
|
|
vars:
|
||
|
|
kc: "http://localhost:8080"
|
||
|
|
devis_identite_sortie: "{{ playbook_dir }}/../../instance/devis-identite.json"
|
||
|
|
|
||
|
|
tasks:
|
||
|
|
# Les valeurs DECLAREES vivent dans les defauts du role. On les charge plutot que
|
||
|
|
# de les recopier ici : un devis qui redeclare ce qu'il verifie ne verifie rien.
|
||
|
|
- name: Charger les valeurs déclarées par le rôle Keycloak
|
||
|
|
ansible.builtin.include_vars:
|
||
|
|
dir: "{{ playbook_dir }}/../../roles/serveur_keycloak/defaults"
|
||
|
|
|
||
|
|
- name: Résoudre la politique de mot de passe (déclaration unique)
|
||
|
|
ansible.builtin.include_role:
|
||
|
|
name: resoudre_politique_mdp
|
||
|
|
|
||
|
|
# Meme raison : les DN de l'annuaire ne se recopient pas, ils se resolvent.
|
||
|
|
- name: Résoudre la connexion à l'annuaire
|
||
|
|
ansible.builtin.include_role:
|
||
|
|
name: resoudre_annuaire
|
||
|
|
|
||
|
|
- name: Charger le registre des applications
|
||
|
|
ansible.builtin.include_vars:
|
||
|
|
file: "{{ setops_plan_dir }}/applications.yml"
|
||
|
|
|
||
|
|
- name: Obtenir un jeton d'administration
|
||
|
|
ansible.builtin.uri:
|
||
|
|
url: "{{ kc }}/realms/master/protocol/openid-connect/token"
|
||
|
|
method: POST
|
||
|
|
body_format: form-urlencoded
|
||
|
|
body:
|
||
|
|
grant_type: password
|
||
|
|
client_id: admin-cli
|
||
|
|
username: "{{ serveur_keycloak_admin_user }}"
|
||
|
|
password: "{{ serveur_keycloak_admin_password }}"
|
||
|
|
register: devis_jeton
|
||
|
|
no_log: true
|
||
|
|
|
||
|
|
- name: Lire le realm
|
||
|
|
ansible.builtin.uri:
|
||
|
|
url: "{{ kc }}/admin/realms/{{ serveur_keycloak_realm }}"
|
||
|
|
headers:
|
||
|
|
Authorization: "Bearer {{ devis_jeton.json.access_token }}"
|
||
|
|
register: devis_realm
|
||
|
|
no_log: true
|
||
|
|
|
||
|
|
- name: Lire la fédération LDAP
|
||
|
|
ansible.builtin.uri:
|
||
|
|
url: "{{ kc }}/admin/realms/{{ serveur_keycloak_realm }}/components?type=org.keycloak.storage.UserStorageProvider"
|
||
|
|
headers:
|
||
|
|
Authorization: "Bearer {{ devis_jeton.json.access_token }}"
|
||
|
|
register: devis_fed
|
||
|
|
no_log: true
|
||
|
|
|
||
|
|
- name: Lire les mappeurs de la fédération
|
||
|
|
ansible.builtin.uri:
|
||
|
|
url: >-
|
||
|
|
{{ kc }}/admin/realms/{{ serveur_keycloak_realm }}/components?parent={{
|
||
|
|
devis_fed.json[0].id }}&type=org.keycloak.storage.ldap.mappers.LDAPStorageMapper
|
||
|
|
headers:
|
||
|
|
Authorization: "Bearer {{ devis_jeton.json.access_token }}"
|
||
|
|
register: devis_mappeurs
|
||
|
|
no_log: true
|
||
|
|
|
||
|
|
- name: Lire la politique de mot de passe de l'annuaire
|
||
|
|
community.general.ldap_search:
|
||
|
|
dn: "ou=policies,{{ resoudre_annuaire_base_dn }}"
|
||
|
|
scope: onelevel
|
||
|
|
filter: "(objectClass=pwdPolicy)"
|
||
|
|
server_uri: "ldapi:///"
|
||
|
|
register: devis_ppolicy
|
||
|
|
changed_when: false
|
||
|
|
|
||
|
|
# Un compte sans adresse ne peut pas recevoir de lien de reinitialisation : pour
|
||
|
|
# lui, « mot de passe oublie » est un ecran qui ne mene nulle part, et le seul
|
||
|
|
# recours redevient l'exploitant manipulant le mot de passe d'autrui.
|
||
|
|
- name: Lire les comptes de l'annuaire
|
||
|
|
community.general.ldap_search:
|
||
|
|
dn: "{{ resoudre_annuaire_users_dn }}"
|
||
|
|
scope: onelevel
|
||
|
|
filter: "(objectClass=inetOrgPerson)"
|
||
|
|
attrs: ["uid", "mail", "givenName"]
|
||
|
|
server_uri: "ldapi:///"
|
||
|
|
register: devis_comptes
|
||
|
|
changed_when: false
|
||
|
|
|
||
|
|
- name: Déposer le relevé sur le contrôleur
|
||
|
|
ansible.builtin.copy:
|
||
|
|
dest: "{{ devis_identite_sortie }}"
|
||
|
|
mode: "0600"
|
||
|
|
content: "{{ {
|
||
|
|
'hote': inventory_hostname,
|
||
|
|
'realm': serveur_keycloak_realm,
|
||
|
|
'declare': {
|
||
|
|
'passwordPolicy': resoudre_politique_mdp_keycloak,
|
||
|
|
'brute': resoudre_politique_mdp_brute,
|
||
|
|
'ppolicy': resoudre_politique_mdp_ldap,
|
||
|
|
'durcissement': serveur_keycloak_ldap_durcissement,
|
||
|
|
'mappeurs': serveur_keycloak_ldap_attributs,
|
||
|
|
'editMode': serveur_keycloak_ldap_edit_mode,
|
||
|
|
'resetPasswordAllowed': serveur_keycloak_reset_mot_de_passe | bool,
|
||
|
|
'smtpHost': applications[serveur_keycloak_smtp_app].hote ~ '.' ~ domaine_interne,
|
||
|
|
},
|
||
|
|
'reel': {
|
||
|
|
'realm': devis_realm.json,
|
||
|
|
'federation': devis_fed.json[0].config,
|
||
|
|
'mappeurs': dict(devis_mappeurs.json | map(attribute='name') | list
|
||
|
|
| zip(devis_mappeurs.json | map(attribute='config') | list)),
|
||
|
|
'ppolicy': (devis_ppolicy.results | first) | default({}),
|
||
|
|
'comptes': devis_comptes.results,
|
||
|
|
},
|
||
|
|
} | to_nice_json }}"
|
||
|
|
delegate_to: localhost
|
||
|
|
become: false
|
||
|
|
|
||
|
|
- name: Indiquer le relevé
|
||
|
|
ansible.builtin.debug:
|
||
|
|
msg: "Relevé déposé : {{ devis_identite_sortie }} — comparaison par scripts/devis_identite.py"
|