2026-08-08 11:24:02 -04:00
|
|
|
---
|
|
|
|
|
# URI de retour APRES DECONNEXION, par client.
|
|
|
|
|
#
|
|
|
|
|
# Keycloak les valide separement des URI de rappel : un client peut donc se connecter
|
|
|
|
|
# parfaitement et echouer a la deconnexion, sur un « We are sorry… invalid redirect uri »
|
|
|
|
|
# qui ne dit pas de quelle liste il parle. Constate le 2026-08-08 sur Nextcloud — et
|
|
|
|
|
# AUCUN des quatre clients ne declarait cet attribut ; Nextcloud etait seulement le seul
|
|
|
|
|
# a envoyer une URI de retour.
|
|
|
|
|
#
|
|
|
|
|
# DERIVEE de `web_origins`, qui porte deja l'URL de base du service : la connaissance
|
|
|
|
|
# existe, il n'y a pas a la reecrire. `/*` couvre la page d'accueil et les chemins de
|
|
|
|
|
# retour que chaque application choisit.
|
|
|
|
|
#
|
|
|
|
|
# Par l'API et non `kcadm -s` : `attributes` est une MAP, et sur une map kcadm accepte
|
|
|
|
|
# la commande, sort en succes et n'ecrit rien (mesure du meme jour sur `smtpServer`).
|
|
|
|
|
# On relit systematiquement apres avoir 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
|
|
|
# Jeton FRAIS : celui de `politique-mdp.yml` a plus de six fichiers d'age, et il vit
|
|
|
|
|
# 60 s. C'est ce qui faisait echouer cette lecture sur toute construction NEUVE — et
|
|
|
|
|
# passer au rejeu, une fois la flotte convergee. Voir `jeton-admin.yml`.
|
|
|
|
|
- name: Reprendre un jeton d'administration avant de lire les clients
|
|
|
|
|
ansible.builtin.include_tasks: jeton-admin.yml
|
|
|
|
|
|
2026-08-08 11:24:02 -04:00
|
|
|
- name: Lire les clients du realm
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: "http://localhost:8080/admin/realms/{{ serveur_keycloak_realm }}/clients"
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
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
|
|
|
status_code: [200]
|
2026-08-08 11:24:02 -04:00
|
|
|
register: serveur_keycloak_clients_actuels
|
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
|
|
|
# `no_log` protege le jeton porte par l'en-tete. Il masquait aussi la CAUSE : le
|
|
|
|
|
# 2026-08-10, cet appel a echoue deux fois sur « the output has been hidden », et il a
|
|
|
|
|
# fallu remonter jusqu'a l'age du jeton pour comprendre. On extrait donc le verdict.
|
2026-08-08 11:24:02 -04:00
|
|
|
no_log: true
|
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
|
|
|
failed_when: false
|
|
|
|
|
|
|
|
|
|
- name: Dire pourquoi la lecture des clients a échoué, si elle a échoué
|
|
|
|
|
ansible.builtin.fail:
|
|
|
|
|
msg: >-
|
|
|
|
|
Keycloak a refuse la lecture des clients du realme
|
|
|
|
|
« {{ serveur_keycloak_realm }} » (HTTP
|
|
|
|
|
{{ serveur_keycloak_clients_actuels.status | default('?') }}).
|
|
|
|
|
Un 401 signifie un jeton perime — verifier que `jeton-admin.yml` est bien inclus
|
|
|
|
|
juste avant cet appel.
|
|
|
|
|
when: serveur_keycloak_clients_actuels.status | default(0) != 200
|
2026-08-08 11:24:02 -04:00
|
|
|
|
|
|
|
|
- name: Composer les URI de déconnexion attendues
|
|
|
|
|
ansible.builtin.set_fact:
|
|
|
|
|
serveur_keycloak_deconnexion: >-
|
|
|
|
|
{{ dict(serveur_keycloak_clients | map(attribute='clientId') | list
|
|
|
|
|
| zip(serveur_keycloak_clients
|
|
|
|
|
| map(attribute='web_origins')
|
|
|
|
|
| map('map', 'regex_replace', '/?$', '/*')
|
|
|
|
|
| map('join', '##') | list)) }}
|
|
|
|
|
|
|
|
|
|
- name: Déclarer l'URI de retour après déconnexion
|
|
|
|
|
ansible.builtin.uri:
|
|
|
|
|
url: >-
|
|
|
|
|
http://localhost:8080/admin/realms/{{ serveur_keycloak_realm
|
|
|
|
|
}}/clients/{{ item.id }}
|
|
|
|
|
method: PUT
|
|
|
|
|
status_code: [204]
|
|
|
|
|
headers:
|
|
|
|
|
Authorization: "Bearer {{ serveur_keycloak_pol_jeton.json.access_token }}"
|
|
|
|
|
body_format: json
|
|
|
|
|
body: >-
|
|
|
|
|
{{ item | combine({'attributes': (item.attributes | default({}))
|
|
|
|
|
| combine({'post.logout.redirect.uris': serveur_keycloak_deconnexion[item.clientId]})}) }}
|
|
|
|
|
loop: "{{ serveur_keycloak_clients_actuels.json }}"
|
|
|
|
|
loop_control:
|
|
|
|
|
label: "{{ item.clientId }}"
|
portabilite : le repli nftables survivait a la bascule et annulait tout
Le socle pose l'un de DEUX fichiers dans /etc/nftables.conf : le ruleset
derive (table setops_flux) s'il existe, sinon un gabarit de repli plat (table
setops_filter) qui n'ouvre que le 22. Ce sont des ALTERNATIVES, jamais des
couches.
Mais le rechargement est `nft -f`, qui AJOUTE sans purger, et le fichier
derive retirait setops_flux — jamais setops_filter. Un hote passe du repli au
derive gardait donc DEUX chaines input sur le meme hook, toutes deux en
policy drop. Le paquet traverse les deux : seule l'intersection de leurs
accept passait.
Symptome parfaitement trompeur : AC debout, 8443 en ecoute, regle posee et
acceptante, ICMP entre les deux VM a 0,15 ms — et step ca bootstrap qui
expire. Il a fallu lire le ruleset entier pour voir la seconde table.
Le fichier derive retire desormais les DEUX tables (le repli portait deja
flush ruleset). Pas de flush ruleset cote derive : choix du depot pour ne pas
detruire de tables etrangeres, respecte.
Ce qui l'avait rendu possible : `make reconstruire` ne generait JAMAIS les
flux. `make flux` en est maintenant la premiere etape.
Et `no_log` a masque la cause trois fois dans la journee — dont au terme d'un
deploiement de 157 taches. Les taches concernees extraient desormais le
verdict a part (ce qui a echoue, quel code, quel message) sans toucher aux
en-tetes. Une garde qui protege un secret ne doit pas emporter le diagnostic.
Verifie : TLS OK depuis infra-dns-01 vers l'AC, une seule table nftables,
13/14 hotes deployes sans echec, prouver.py 34 OK, ansible-lint production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 12:24:41 -04:00
|
|
|
# `no_log` protege le JETON porte par l'en-tete — on ne peut pas simplement l'enlever.
|
|
|
|
|
# Mais il masquait aussi la CAUSE : le 2026-08-10, l'echec s'est lu « the output has
|
|
|
|
|
# been hidden » sur le tout dernier appel d'un deploiement de 157 taches. On journalise
|
|
|
|
|
# donc le verdict a part, en n'extrayant que ce qui ne revele rien.
|
2026-08-08 11:24:02 -04:00
|
|
|
no_log: true
|
portabilite : le repli nftables survivait a la bascule et annulait tout
Le socle pose l'un de DEUX fichiers dans /etc/nftables.conf : le ruleset
derive (table setops_flux) s'il existe, sinon un gabarit de repli plat (table
setops_filter) qui n'ouvre que le 22. Ce sont des ALTERNATIVES, jamais des
couches.
Mais le rechargement est `nft -f`, qui AJOUTE sans purger, et le fichier
derive retirait setops_flux — jamais setops_filter. Un hote passe du repli au
derive gardait donc DEUX chaines input sur le meme hook, toutes deux en
policy drop. Le paquet traverse les deux : seule l'intersection de leurs
accept passait.
Symptome parfaitement trompeur : AC debout, 8443 en ecoute, regle posee et
acceptante, ICMP entre les deux VM a 0,15 ms — et step ca bootstrap qui
expire. Il a fallu lire le ruleset entier pour voir la seconde table.
Le fichier derive retire desormais les DEUX tables (le repli portait deja
flush ruleset). Pas de flush ruleset cote derive : choix du depot pour ne pas
detruire de tables etrangeres, respecte.
Ce qui l'avait rendu possible : `make reconstruire` ne generait JAMAIS les
flux. `make flux` en est maintenant la premiere etape.
Et `no_log` a masque la cause trois fois dans la journee — dont au terme d'un
deploiement de 157 taches. Les taches concernees extraient desormais le
verdict a part (ce qui a echoue, quel code, quel message) sans toucher aux
en-tetes. Une garde qui protege un secret ne doit pas emporter le diagnostic.
Verifie : TLS OK depuis infra-dns-01 vers l'AC, une seule table nftables,
13/14 hotes deployes sans echec, prouver.py 34 OK, ansible-lint production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 12:24:41 -04:00
|
|
|
register: serveur_keycloak_deconnexion_res
|
|
|
|
|
failed_when: false
|
2026-08-08 11:24:02 -04:00
|
|
|
changed_when: true
|
|
|
|
|
when:
|
|
|
|
|
- item.clientId in serveur_keycloak_deconnexion
|
|
|
|
|
- (item.attributes | default({})).get('post.logout.redirect.uris', '')
|
|
|
|
|
!= serveur_keycloak_deconnexion[item.clientId]
|
portabilite : le repli nftables survivait a la bascule et annulait tout
Le socle pose l'un de DEUX fichiers dans /etc/nftables.conf : le ruleset
derive (table setops_flux) s'il existe, sinon un gabarit de repli plat (table
setops_filter) qui n'ouvre que le 22. Ce sont des ALTERNATIVES, jamais des
couches.
Mais le rechargement est `nft -f`, qui AJOUTE sans purger, et le fichier
derive retirait setops_flux — jamais setops_filter. Un hote passe du repli au
derive gardait donc DEUX chaines input sur le meme hook, toutes deux en
policy drop. Le paquet traverse les deux : seule l'intersection de leurs
accept passait.
Symptome parfaitement trompeur : AC debout, 8443 en ecoute, regle posee et
acceptante, ICMP entre les deux VM a 0,15 ms — et step ca bootstrap qui
expire. Il a fallu lire le ruleset entier pour voir la seconde table.
Le fichier derive retire desormais les DEUX tables (le repli portait deja
flush ruleset). Pas de flush ruleset cote derive : choix du depot pour ne pas
detruire de tables etrangeres, respecte.
Ce qui l'avait rendu possible : `make reconstruire` ne generait JAMAIS les
flux. `make flux` en est maintenant la premiere etape.
Et `no_log` a masque la cause trois fois dans la journee — dont au terme d'un
deploiement de 157 taches. Les taches concernees extraient desormais le
verdict a part (ce qui a echoue, quel code, quel message) sans toucher aux
en-tetes. Une garde qui protege un secret ne doit pas emporter le diagnostic.
Verifie : TLS OK depuis infra-dns-01 vers l'AC, une seule table nftables,
13/14 hotes deployes sans echec, prouver.py 34 OK, ansible-lint production.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-08-10 12:24:41 -04:00
|
|
|
|
|
|
|
|
- name: Dire quels clients Keycloak a refusés, et pourquoi
|
|
|
|
|
ansible.builtin.fail:
|
|
|
|
|
msg: >-
|
|
|
|
|
Keycloak a refuse la mise a jour des URI de deconnexion pour :
|
|
|
|
|
{{ refuses | map(attribute='item.clientId') | list | join(', ') }}.
|
|
|
|
|
Codes rendus : {{ refuses | map(attribute='status') | list }}.
|
|
|
|
|
Messages : {{ refuses | map(attribute='msg') | map('string')
|
|
|
|
|
| map('truncate', 160) | list }}.
|
|
|
|
|
vars:
|
|
|
|
|
refuses: >-
|
|
|
|
|
{{ (serveur_keycloak_deconnexion_res.results | default([]))
|
|
|
|
|
| rejectattr('skipped', 'defined')
|
|
|
|
|
| selectattr('status', 'defined')
|
|
|
|
|
| rejectattr('status', 'equalto', 204) | list }}
|
|
|
|
|
when: refuses | length > 0
|