rotation : les comptes de secours peuvent enfin changer de mot de passe
Le runbook promettait cette rotation ; le code ne savait pas la faire. Les trois roles ne posaient le mot de passe qu'a la CREATION — regenerer la voute aurait produit le mensonge silencieux corrige toute la journee. Chaque role sait desormais CHANGER un mot de passe existant, idempotent par empreinte du secret applique. Pour Nextcloud le secret passe par l'environnement, pas par la ligne de commande ou il serait visible dans la table des processus. `grafana-cli` ecrivait dans une base FANTOME en annoncant « changed successfully » a chaque fois : il prend `paths.data` a `<homepath>/data`, le paquet Debian range la base dans /var/lib/grafana. Demasque par le champ `updated` du compte, reste a l'heure du deploiement initial malgre quatre reinitialisations « reussies ». Un message de succes n'est pas une preuve ; l'etat l'est. Verifie par authentification reelle : Grafana 200, Nextcloud 200. Forgejo ferme l'API par doctrine (D-41) — seule preuve disponible : le retour de la commande. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
parent
df8ffb68d6
commit
91d3a736e7
7 changed files with 187 additions and 0 deletions
39
CHANGELOG.md
39
CHANGELOG.md
|
|
@ -2,6 +2,45 @@
|
||||||
|
|
||||||
## 2026-08-06 — le chemin nord-sud devient dérivable
|
## 2026-08-06 — le chemin nord-sud devient dérivable
|
||||||
|
|
||||||
|
### La rotation des comptes de secours devient possible — elle ne l'était pas
|
||||||
|
|
||||||
|
Le runbook §6.6 promettait de régénérer les comptes de secours ; **le code ne savait pas le
|
||||||
|
faire**. Les trois rôles ne posaient le mot de passe qu'à la *création* :
|
||||||
|
|
||||||
|
```
|
||||||
|
grafana GF_SECURITY_ADMIN_PASSWORD n'agit qu'à la création du compte
|
||||||
|
forgejo admin user create `creates: .admin-created` — une seule fois
|
||||||
|
nextcloud maintenance:install seulement à l'installation
|
||||||
|
```
|
||||||
|
|
||||||
|
Régénérer la voûte sans cela aurait produit exactement le mensonge silencieux corrigé toute
|
||||||
|
la journée : la voûte dit une chose, le service en a une autre.
|
||||||
|
|
||||||
|
Chaque rôle sait désormais **changer** un mot de passe existant, avec une idempotence par
|
||||||
|
**empreinte du secret appliqué** — on ne peut pas relire un hachage, donc on mémorise ce qu'on
|
||||||
|
a posé. Pour Nextcloud, le secret passe par l'environnement (`--password-from-env`) et non par
|
||||||
|
la ligne de commande, où il serait visible dans la table des processus.
|
||||||
|
|
||||||
|
### `grafana-cli` écrivait dans une base fantôme
|
||||||
|
|
||||||
|
Et disait « Admin password changed successfully ✔ » à chaque fois.
|
||||||
|
|
||||||
|
La CLI prend `paths.data` par défaut à `<homepath>/data` ; le paquet Debian range la base dans
|
||||||
|
`/var/lib/grafana`. Elle créait donc `/usr/share/grafana/data/grafana.db`, y écrivait, et
|
||||||
|
annonçait le succès — pendant que le serveur lisait l'autre fichier.
|
||||||
|
|
||||||
|
**Ce qui l'a démasqué** : le champ `updated` du compte, resté à l'heure du déploiement initial
|
||||||
|
malgré quatre réinitialisations « réussies ». Un message de succès n'est pas une preuve ;
|
||||||
|
l'état l'est. `--configOverrides=cfg:default.paths.data=…` est désormais imposé.
|
||||||
|
|
||||||
|
**Vérifié par authentification réelle** : Grafana `200`, Nextcloud `200`. Pour Forgejo,
|
||||||
|
`ENABLE_BASIC_AUTHENTICATION = false` ferme l'API par doctrine (D-41) — la seule preuve
|
||||||
|
disponible est le retour de la commande, qui confirme le changement.
|
||||||
|
|
||||||
|
Quatre secrets régénérés : `vault_grafana_admin`, `vault_forgejo_admin`,
|
||||||
|
`vault_nextcloud_admin`, `vault_sysadmin_amorcage`.
|
||||||
|
|
||||||
|
|
||||||
### Icinga Web 2 cesse de nommer des personnes
|
### Icinga Web 2 cesse de nommer des personnes
|
||||||
|
|
||||||
Le dernier `porte_par: liste-uid` du catalogue. `serveur_icingaweb2_admins` valait un `uid`
|
Le dernier `porte_par: liste-uid` du catalogue. `serveur_icingaweb2_admins` valait un `uid`
|
||||||
|
|
|
||||||
|
|
@ -82,3 +82,6 @@ serveur_forgejo_db_sslrootcert: "/etc/step/certs/root_ca.crt"
|
||||||
# LDAP (group-ldap-mapper). Voir docs/autorisation.md.
|
# LDAP (group-ldap-mapper). Voir docs/autorisation.md.
|
||||||
serveur_forgejo_oidc_groupe_claim: "groups"
|
serveur_forgejo_oidc_groupe_claim: "groups"
|
||||||
serveur_forgejo_oidc_groupe_admin: "sysadmin"
|
serveur_forgejo_oidc_groupe_admin: "sysadmin"
|
||||||
|
|
||||||
|
# Empreinte du mot de passe admin APPLIQUE (rotation). Voir tasks/main.yml.
|
||||||
|
serveur_forgejo_marqueur_admin: "/etc/forgejo/.setops-admin-sha256"
|
||||||
|
|
|
||||||
|
|
@ -196,3 +196,47 @@
|
||||||
when:
|
when:
|
||||||
- serveur_forgejo_oidc_actif | bool
|
- serveur_forgejo_oidc_actif | bool
|
||||||
- not ansible_check_mode
|
- not ansible_check_mode
|
||||||
|
|
||||||
|
# --- ROTATION DU COMPTE DE SECOURS -------------------------------------------
|
||||||
|
# `admin user create` porte `creates: .admin-created` : il ne tourne qu'UNE fois.
|
||||||
|
# Changer la voute ne changeait donc rien, et la voute se mettait a mentir. Meme
|
||||||
|
# raisonnement que pour Grafana — idempotence par EMPREINTE du secret applique.
|
||||||
|
- name: Empreinte du mot de passe admin en place
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ serveur_forgejo_marqueur_admin }}"
|
||||||
|
register: serveur_forgejo_marque
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Appliquer le mot de passe du compte de secours (rotation)
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- "{{ serveur_forgejo_binaire }}"
|
||||||
|
- "--config"
|
||||||
|
- "{{ serveur_forgejo_config }}"
|
||||||
|
- admin
|
||||||
|
- user
|
||||||
|
- change-password
|
||||||
|
- "--username"
|
||||||
|
- "{{ serveur_forgejo_admin_user }}"
|
||||||
|
- "--password"
|
||||||
|
- "{{ serveur_forgejo_admin_password }}"
|
||||||
|
environment:
|
||||||
|
GITEA_WORK_DIR: "{{ serveur_forgejo_data }}"
|
||||||
|
become: true
|
||||||
|
become_user: "{{ serveur_forgejo_utilisateur }}"
|
||||||
|
changed_when: true
|
||||||
|
no_log: true
|
||||||
|
when: >-
|
||||||
|
(serveur_forgejo_marque.content | default('') | b64decode | trim)
|
||||||
|
!= (serveur_forgejo_admin_password | hash('sha256'))
|
||||||
|
|
||||||
|
- name: Retenir l'empreinte appliquee
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ serveur_forgejo_admin_password | hash('sha256') }}\n"
|
||||||
|
dest: "{{ serveur_forgejo_marqueur_admin }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
|
||||||
|
|
@ -50,3 +50,11 @@ serveur_grafana_oidc_role_path: "contains(roles[*], 'grafana-admin') && 'Admin'
|
||||||
serveur_grafana_depot_cle_url: "https://apt.grafana.com/gpg-full.key"
|
serveur_grafana_depot_cle_url: "https://apt.grafana.com/gpg-full.key"
|
||||||
serveur_grafana_depot_cle_fichier: "/etc/apt/keyrings/grafana.asc"
|
serveur_grafana_depot_cle_fichier: "/etc/apt/keyrings/grafana.asc"
|
||||||
serveur_grafana_depot_source: "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main"
|
serveur_grafana_depot_source: "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main"
|
||||||
|
|
||||||
|
# Empreinte du mot de passe admin APPLIQUE — permet la rotation sans lire le secret
|
||||||
|
# en place (impossible : il est hache). Voir tasks/main.yml.
|
||||||
|
serveur_grafana_marqueur_admin: "/etc/grafana/.setops-admin-sha256"
|
||||||
|
|
||||||
|
# Chemins du paquet Debian — la CLI ne les devine pas (voir tasks/main.yml).
|
||||||
|
serveur_grafana_homepath: "/usr/share/grafana"
|
||||||
|
serveur_grafana_donnees: "/var/lib/grafana"
|
||||||
|
|
|
||||||
|
|
@ -102,3 +102,53 @@
|
||||||
enabled: true
|
enabled: true
|
||||||
state: started
|
state: started
|
||||||
daemon_reload: true
|
daemon_reload: true
|
||||||
|
|
||||||
|
# --- ROTATION DU COMPTE DE SECOURS -------------------------------------------
|
||||||
|
# `GF_SECURITY_ADMIN_PASSWORD` n'agit qu'a la CREATION du compte : changer la voute
|
||||||
|
# ne changeait rien, et la voute se mettait a mentir en silence. Le runbook de
|
||||||
|
# reprise (docs/autorisation.md §6) promet pourtant cette rotation — c'est ce qui
|
||||||
|
# transforme une livraison en transfert. Constate le 2026-08-07.
|
||||||
|
#
|
||||||
|
# Idempotence par EMPREINTE : on garde le sha256 du secret applique. Tant qu'il ne
|
||||||
|
# change pas, on ne touche a rien ; des qu'il change, on reapplique. On ne peut pas
|
||||||
|
# lire le mot de passe en place, donc on memorise ce qu'on a pose.
|
||||||
|
- name: Empreinte du mot de passe admin en place
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ serveur_grafana_marqueur_admin }}"
|
||||||
|
register: serveur_grafana_marque
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Appliquer le mot de passe du compte de secours (rotation)
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- grafana-cli
|
||||||
|
- "--homepath={{ serveur_grafana_homepath }}"
|
||||||
|
# `paths.data` DOIT etre impose : la CLI le prend par defaut a
|
||||||
|
# `<homepath>/data`, alors que le paquet Debian range la base dans
|
||||||
|
# /var/lib/grafana. Sans lui, la CLI cree une base FANTOME, y ecrit, et
|
||||||
|
# annonce « Admin password changed successfully » — pendant que le serveur
|
||||||
|
# lit l'autre. Constate le 2026-08-07 : le compte n'avait pas bouge depuis
|
||||||
|
# le deploiement initial, malgre quatre reinitialisations « reussies ».
|
||||||
|
- "--configOverrides=cfg:default.paths.data={{ serveur_grafana_donnees }}"
|
||||||
|
- admin
|
||||||
|
- reset-admin-password
|
||||||
|
- "{{ serveur_grafana_admin_password }}"
|
||||||
|
no_log: true
|
||||||
|
# La tache ne s'execute QUE si l'empreinte differe : quand elle tourne, elle
|
||||||
|
# change reellement le mot de passe.
|
||||||
|
changed_when: true
|
||||||
|
when: >-
|
||||||
|
(serveur_grafana_marque.content | default('') | b64decode | trim)
|
||||||
|
!= (serveur_grafana_admin_password | hash('sha256'))
|
||||||
|
notify: Redemarrer grafana
|
||||||
|
|
||||||
|
- name: Retenir l'empreinte appliquee
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ serveur_grafana_admin_password | hash('sha256') }}\n"
|
||||||
|
dest: "{{ serveur_grafana_marqueur_admin }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
|
||||||
|
|
@ -112,3 +112,6 @@ serveur_nextcloud_bruteforce_whitelist: "{{ (sous_reseau_admin | default('')) }}
|
||||||
# verse les membres du groupe d'habilitation.
|
# verse les membres du groupe d'habilitation.
|
||||||
serveur_nextcloud_oidc_groupe_claim: "groups"
|
serveur_nextcloud_oidc_groupe_claim: "groups"
|
||||||
serveur_nextcloud_oidc_groupe_admin: "sysadmin"
|
serveur_nextcloud_oidc_groupe_admin: "sysadmin"
|
||||||
|
|
||||||
|
# Empreinte du mot de passe admin APPLIQUE (rotation). Voir tasks/configurer.yml.
|
||||||
|
serveur_nextcloud_marqueur_admin: "/etc/setops-nextcloud-admin-sha256"
|
||||||
|
|
|
||||||
|
|
@ -77,3 +77,43 @@
|
||||||
when:
|
when:
|
||||||
- serveur_nextcloud_bruteforce_whitelist | length > 0
|
- serveur_nextcloud_bruteforce_whitelist | length > 0
|
||||||
- "'/' in serveur_nextcloud_bruteforce_whitelist"
|
- "'/' in serveur_nextcloud_bruteforce_whitelist"
|
||||||
|
|
||||||
|
# --- ROTATION DU COMPTE DE SECOURS -------------------------------------------
|
||||||
|
# `maintenance:install --admin-pass` ne tourne qu'a l'INSTALLATION. Changer la
|
||||||
|
# voute ne changeait rien. `user:resetpassword` lit le secret dans l'environnement
|
||||||
|
# (`--password-from-env`) : il ne passe donc pas par la ligne de commande, ou il
|
||||||
|
# serait visible dans la table des processus.
|
||||||
|
- name: Empreinte du mot de passe admin en place
|
||||||
|
ansible.builtin.slurp:
|
||||||
|
src: "{{ serveur_nextcloud_marqueur_admin }}"
|
||||||
|
register: serveur_nextcloud_marque
|
||||||
|
failed_when: false
|
||||||
|
changed_when: false
|
||||||
|
no_log: true
|
||||||
|
|
||||||
|
- name: Appliquer le mot de passe du compte de secours (rotation)
|
||||||
|
ansible.builtin.command:
|
||||||
|
argv:
|
||||||
|
- php
|
||||||
|
- "{{ serveur_nextcloud_racine }}/occ"
|
||||||
|
- "user:resetpassword"
|
||||||
|
- "--password-from-env"
|
||||||
|
- "{{ serveur_nextcloud_admin_user }}"
|
||||||
|
environment:
|
||||||
|
OC_PASS: "{{ serveur_nextcloud_admin_password }}"
|
||||||
|
become: true
|
||||||
|
become_user: "{{ serveur_nextcloud_utilisateur | default('www-data') }}"
|
||||||
|
changed_when: true
|
||||||
|
no_log: true
|
||||||
|
when: >-
|
||||||
|
(serveur_nextcloud_marque.content | default('') | b64decode | trim)
|
||||||
|
!= (serveur_nextcloud_admin_password | hash('sha256'))
|
||||||
|
|
||||||
|
- name: Retenir l'empreinte appliquee
|
||||||
|
ansible.builtin.copy:
|
||||||
|
content: "{{ serveur_nextcloud_admin_password | hash('sha256') }}\n"
|
||||||
|
dest: "{{ serveur_nextcloud_marqueur_admin }}"
|
||||||
|
owner: root
|
||||||
|
group: root
|
||||||
|
mode: "0600"
|
||||||
|
no_log: true
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue