diff --git a/CHANGELOG.md b/CHANGELOG.md index 3b80374..6e3b71d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,45 @@ # CHANGELOG — Set-OPS +## 2026-10-03 (67) — Keycloak 26.7.5 et oauth2-proxy v7.15.5 ; deux montées qui n'auraient rien monté + +**Demande de l'exploitant** : mettre à jour Keycloak et oauth2-proxy, premiers du relevé des +logiciels en retard (Keycloak 26.7.1 : quatre correctifs de retard, chacun corrigeant plusieurs +CVE ; oauth2-proxy v7.15.3 : deux, tous deux de sécurité). + +**Deux défauts trouvés en préparant, avant tout déploiement — les deux rôles ne savaient pas +MONTER.** Ils ne faisaient jusque-là que des premières installations. +- **oauth2-proxy** décidait sur la seule PRÉSENCE du binaire : changer la version sur une + machine installée ne faisait rien. Le rôle demande désormais sa version au binaire. +- **Keycloak** avait un repère par version (`.kc-built-`), mais l'extraction portait + `creates: bin/kc.sh` : sautée, puis `kc.sh build` sur les ANCIENS fichiers, puis repère de + la NOUVELLE version — la machine se serait dite en 26.7.5 en restant en 26.7.1. Et extraire + par-dessus ne suffit pas : les bibliothèques portent leur version dans leur nom, les deux + générations auraient coexisté. Lors d'une montée, le rôle arrête Keycloak, retire la + distribution précédente (`data/` gardée), extrait, puis repose sa configuration et son + thème comme à l'installation. + +**oauth2-proxy installait sans rien vérifier.** Empreinte SHA-256 de l'archive écrite dans le +rôle (`serveur_oauth2_proxy_sha256`), après relecture : la somme publiée par le projet +recalculée sur l'archive. Une archive qui ne la porte pas — dépôt du site ou Internet — est +retirée du cache et refusée. Keycloak, lui, vérifiait déjà sa signature PGP : 26.7.5 est signée +par la clé épinglée (`861AB50E…`), contrôlé avant déploiement. + +**Appliqué** : dépôt de binaires du site garni des deux versions (les runners n'auront pas à +sortir) ; puis les deux locataires. Relu chez chacun : Keycloak 26.7.5 démarré en 6 s après la +mise à jour automatique de sa base, aucune bibliothèque 26.7.1 restante, aucune erreur ; +oauth2-proxy v7.15.5 sur `mon-01` et `ops-01` ; vigie et console renvoient vers la connexion +Keycloak, issuer juste ; sondes `identite`, `passerelle`, `vigie`, `console-ops` au vert. +Interruption de l'identité : environ une minute par locataire, pendant le remplacement. + +**À savoir** : le rôle Keycloak n'est pas simulable jusqu'au bout — `courriel-realm.yml` +échoue en `--check` faute de jeton d'administration, avec ou sans ce changement. L'extraction +est sautée en simulation (l'archive n'y est pas copiée). + +**Vu au passage** : `web-dorsal-01` (Chezlepro) rapporte une sauvegarde VIDE depuis la +reconstruction du 2026-10-01 — légitime s'il n'héberge encore aucun site, à confirmer. + +**Validation** : `ansible-lint` (0 violation), `make verifier` conforme (83/83). + ## 2026-10-03 (66) — Les épingles tiennent, cache ou pas **Demande de l'exploitant** : faire respecter les épingles de `paquets-tiers.yml`. diff --git a/roles/serveur_keycloak/defaults/main.yml b/roles/serveur_keycloak/defaults/main.yml index 27cb9fa..2716d75 100644 --- a/roles/serveur_keycloak/defaults/main.yml +++ b/roles/serveur_keycloak/defaults/main.yml @@ -1,6 +1,8 @@ --- # Distribution Keycloak (Quarkus). Verifier/ajuster la version sur keycloak.org/downloads. -serveur_keycloak_version: "26.7.1" +# 26.7.5 (2026-10-03) : quatre versions de correctifs apres 26.7.1, chacune corrigeant +# plusieurs CVE. La branche 26.8 existe ; on reste sur la correction de la meme branche. +serveur_keycloak_version: "26.7.5" serveur_keycloak_url: "https://github.com/keycloak/keycloak/releases/download/{{ serveur_keycloak_version }}/keycloak-{{ serveur_keycloak_version }}.tar.gz" serveur_keycloak_java_paquet: "default-jre-headless" @@ -204,7 +206,7 @@ serveur_keycloak_cache_local: "{{ setops_cache_artefacts | default(lookup('env', # d'authenticite compte le plus. # # Continuite constatee le 2026-08-10 : cette meme cle a signe 26.0.7 (la version alors en -# production), 26.3.0, 26.6.2 et 26.7.1. +# production), 26.3.0, 26.6.2 et 26.7.1 — puis 26.7.5, verifiee le 2026-10-03. # # ANCRE (2026-08-11) — l'empreinte est PUBLIEE PAR LE PROJET sur https://www.keycloak.org/keys, # sous l'UID « Keycloak Bot ». Ce canal (keycloak.org) est diff --git a/roles/serveur_keycloak/tasks/main.yml b/roles/serveur_keycloak/tasks/main.yml index 10c02c2..bc7a19c 100644 --- a/roles/serveur_keycloak/tasks/main.yml +++ b/roles/serveur_keycloak/tasks/main.yml @@ -226,6 +226,58 @@ mode: "0644" when: not serveur_keycloak_archive_present.stat.exists +# UNE NOUVELLE VERSION REMPLACE L'ANCIENNE, ELLE NE S'Y SUPERPOSE PAS (2026-10-03). +# +# L'extraction portait `creates: bin/kc.sh` : sur une machine deja installee, elle etait +# SAUTEE. `kc.sh build` tournait alors sur les anciens fichiers, puis posait le repere de la +# NOUVELLE version — la machine se serait dite en 26.7.5 en restant en 26.7.1. Trouve en +# preparant cette montee, avant tout deploiement. +# +# Et extraire par-dessus ne suffit pas : les bibliotheques portent leur version dans leur +# nom (`lib/lib/main/*-26.7.1.jar`), les deux generations coexisteraient sur le classpath. +# On retire donc la distribution precedente. Ce que le role pose lui-meme dans ce +# repertoire — `conf/keycloak.conf`, le theme, le repere — l'est APRES l'extraction ; on ne +# garde que `data/` (fichiers de travail) et le repertoire de travail d'Ansible. +- name: Une autre version est-elle en place ? + ansible.builtin.stat: + path: "{{ serveur_keycloak_home }}/bin/kc.sh" + register: serveur_keycloak_distribution + when: not serveur_keycloak_archive_present.stat.exists + +- name: Mise a jour — arreter Keycloak avant de remplacer sa distribution + ansible.builtin.systemd: + name: "{{ serveur_keycloak_service }}" + state: stopped + when: + - not serveur_keycloak_archive_present.stat.exists + - serveur_keycloak_distribution.stat.exists | default(false) + +- name: Mise a jour — retirer la distribution precedente (data/ gardee) + ansible.builtin.command: + argv: + - find + - "{{ serveur_keycloak_home }}" + - -mindepth + - "1" + - -maxdepth + - "1" + - "!" + - -name + - data + - "!" + - -name + - .ansible + - -exec + - rm + - -rf + - -- + - "{}" + - + + changed_when: true + when: + - not serveur_keycloak_archive_present.stat.exists + - serveur_keycloak_distribution.stat.exists | default(false) + - name: Extraire Keycloak ansible.builtin.unarchive: src: "/tmp/keycloak-{{ serveur_keycloak_version }}.tar.gz" @@ -234,7 +286,10 @@ extra_opts: ["--strip-components=1"] owner: "{{ serveur_keycloak_utilisateur }}" group: "{{ serveur_keycloak_utilisateur }}" - creates: "{{ serveur_keycloak_home }}/bin/kc.sh" + # En simulation, l'archive n'a pas ete copiee dans /tmp : rien a extraire. + when: + - not serveur_keycloak_archive_present.stat.exists + - not ansible_check_mode - name: Deployer keycloak.conf (config non sensible) ansible.builtin.template: diff --git a/roles/serveur_oauth2_proxy/defaults/main.yml b/roles/serveur_oauth2_proxy/defaults/main.yml index 978825c..885d3e7 100644 --- a/roles/serveur_oauth2_proxy/defaults/main.yml +++ b/roles/serveur_oauth2_proxy/defaults/main.yml @@ -3,7 +3,15 @@ # application sans OIDC natif. L'app reçoit l'utilisateur via en-têtes (auth « external »). # Binaire Go statique depuis les releases GitHub (pas d'apt). Requiert client_pki (confiance # step_ca pour joindre Keycloak) + résolution de l'hôte Keycloak. -serveur_oauth2_proxy_version: "v7.15.3" +# v7.15.5 (2026-10-03) : deux versions de correctifs apres v7.15.3, toutes deux de securite. +serveur_oauth2_proxy_version: "v7.15.5" +# L'EMPREINTE DE L'ARCHIVE, ECRITE ICI ET NON LUE A COTE DU TELECHARGEMENT (2026-10-03). +# Le role installait le binaire de la passerelle SSO sans rien verifier. La somme publiee +# par le projet (`*-sha256sum.txt`, meme canal que l'archive) a ete recalculee sur l'archive +# le jour meme ; l'ecrire dans le depot fige ce qui a ete relu, et une archive remplacee +# plus tard — sur GitHub ou dans le depot de binaires du site — est REFUSEE. +# Changer de version = changer cette ligne, apres la meme relecture. +serveur_oauth2_proxy_sha256: "f63f94bf72c5f46ab002a0a275aa8b3cf19b4d828aed08a13978cb9a62c3a1fd" serveur_oauth2_proxy_archive: "oauth2-proxy-{{ serveur_oauth2_proxy_version }}.linux-amd64.tar.gz" serveur_oauth2_proxy_url: >- https://github.com/oauth2-proxy/oauth2-proxy/releases/download/{{ diff --git a/roles/serveur_oauth2_proxy/tasks/main.yml b/roles/serveur_oauth2_proxy/tasks/main.yml index 175e384..ea285b9 100644 --- a/roles/serveur_oauth2_proxy/tasks/main.yml +++ b/roles/serveur_oauth2_proxy/tasks/main.yml @@ -63,10 +63,23 @@ # dans /tmp : /tmp se vide, et elle repartait du controleur a chaque deploiement (`changed` # sans raison). Le binaire est exactement ce que l'extraction attend (`creates`) : present, # il n'y a rien a apporter. Meme correction que `serveur_keycloak`. +# +# LA VERSION, PAS LA SEULE PRESENCE (2026-10-03). Le repere etait l'existence du binaire : +# changer `serveur_oauth2_proxy_version` sur une machine deja installee ne faisait RIEN — +# ni telechargement, ni extraction. On demande donc au binaire sa version. +- name: Quelle version d'oauth2-proxy est en place ? + ansible.builtin.command: + argv: ["{{ serveur_oauth2_proxy_binaire }}", "--version"] + register: serveur_oauth2_proxy_version_posee + changed_when: false + failed_when: false + check_mode: false + - name: L artefact de cette version est-il deja pose ? - ansible.builtin.stat: - path: "{{ serveur_oauth2_proxy_binaire }}" - register: serveur_oauth2_proxy_archive_present + ansible.builtin.set_fact: + serveur_oauth2_proxy_a_jour: >- + {{ (serveur_oauth2_proxy_version_posee.rc | default(1) == 0) + and ((serveur_oauth2_proxy_version ~ ' ') in (serveur_oauth2_proxy_version_posee.stdout | default('') ~ ' ')) }} # Le controleur telecharge, puis pousse par SSH — la cible ne tire jamais d'Internet. # Motif explique en detail dans `roles/serveur_nextcloud/tasks/installer.yml`. @@ -77,7 +90,7 @@ mode: "0700" delegate_to: localhost become: false - when: not serveur_oauth2_proxy_archive_present.stat.exists + when: not (serveur_oauth2_proxy_a_jour | bool) # --- LE DEPOT DU SITE D'ABORD, L'INTERNET ENSUITE (2026-09-12) ---------------- # @@ -102,7 +115,7 @@ failed_when: false when: - setops_depot_binaires | default('') | length > 0 - - not serveur_oauth2_proxy_archive_present.stat.exists + - not (serveur_oauth2_proxy_a_jour | bool) - name: L artefact est-il déjà dans le cache du contrôleur ? ansible.builtin.stat: @@ -110,7 +123,7 @@ register: serveur_oauth2_proxy_cache_present delegate_to: localhost become: false - when: not serveur_oauth2_proxy_archive_present.stat.exists + when: not (serveur_oauth2_proxy_a_jour | bool) - name: Télécharger oauth2-proxy dans le cache du contrôleur (une seule fois) ansible.builtin.get_url: @@ -120,15 +133,50 @@ delegate_to: localhost become: false when: - - not serveur_oauth2_proxy_archive_present.stat.exists + - not (serveur_oauth2_proxy_a_jour | bool) - not (serveur_oauth2_proxy_cache_present.stat.exists | default(false)) +# QUELLE QUE SOIT LA PROVENANCE — depot du site ou Internet — l'archive du cache doit avoir +# l'empreinte relue (defaults/main.yml). Une archive qui ne l'a pas est retiree du cache, +# pour ne pas la reproposer au passage suivant. +- name: Mesurer l'archive oauth2-proxy du cache + ansible.builtin.stat: + path: "{{ serveur_oauth2_proxy_cache_local }}/oauth2-proxy-{{ serveur_oauth2_proxy_version }}.tar.gz" + checksum_algorithm: sha256 + delegate_to: localhost + become: false + register: serveur_oauth2_proxy_archive_mesuree + when: not (serveur_oauth2_proxy_a_jour | bool) + +- name: Retirer du cache une archive dont l'empreinte ne correspond pas + ansible.builtin.file: + path: "{{ serveur_oauth2_proxy_cache_local }}/oauth2-proxy-{{ serveur_oauth2_proxy_version }}.tar.gz" + state: absent + delegate_to: localhost + become: false + when: + - not (serveur_oauth2_proxy_a_jour | bool) + - serveur_oauth2_proxy_archive_mesuree.stat.exists | default(false) + - serveur_oauth2_proxy_archive_mesuree.stat.checksum | default('') != serveur_oauth2_proxy_sha256 + +- name: Refuser une archive oauth2-proxy dont l'empreinte ne correspond pas + ansible.builtin.assert: + that: + - serveur_oauth2_proxy_archive_mesuree.stat.checksum | default('') == serveur_oauth2_proxy_sha256 + fail_msg: >- + L'archive oauth2-proxy {{ serveur_oauth2_proxy_version }} n'a pas l'empreinte relue + ({{ serveur_oauth2_proxy_sha256[:12] }}…) : obtenue + {{ (serveur_oauth2_proxy_archive_mesuree.stat.checksum | default('absente'))[:12] }}. + Elle a ete retiree du cache. Ne pas contourner : relire la publication avant de + changer l'empreinte. + when: not (serveur_oauth2_proxy_a_jour | bool) + - name: Déposer oauth2-proxy sur l hôte depuis le cache ansible.builtin.copy: src: "{{ serveur_oauth2_proxy_cache_local }}/oauth2-proxy-{{ serveur_oauth2_proxy_version }}.tar.gz" dest: "/tmp/oauth2-proxy-{{ serveur_oauth2_proxy_version }}.tar.gz" mode: "0644" - when: not serveur_oauth2_proxy_archive_present.stat.exists + when: not (serveur_oauth2_proxy_a_jour | bool) - name: Extraire le binaire oauth2-proxy ansible.builtin.unarchive: @@ -139,7 +187,10 @@ owner: root group: root mode: "0755" - creates: "{{ serveur_oauth2_proxy_binaire }}" + # En simulation, l'archive n'a pas ete copiee dans /tmp : rien a extraire. + when: + - not (serveur_oauth2_proxy_a_jour | bool) + - not ansible_check_mode notify: Redémarrer oauth2-proxy - name: Créer le répertoire de configuration