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>
242 lines
8.6 KiB
YAML
242 lines
8.6 KiB
YAML
---
|
|
|
|
# L'URL PUBLIQUE de l'IdP se derive de l'exposition declaree au plan, elle ne se
|
|
# fabrique pas : `keycloak.<domaine>` n'est publie nulle part (voir resoudre_idp).
|
|
- name: Resoudre le fournisseur d'identite (role partage)
|
|
ansible.builtin.include_role:
|
|
name: resoudre_idp
|
|
vars:
|
|
resoudre_idp_realm: "{{ serveur_forgejo_oidc_realm }}"
|
|
- name: Refuser de fermer la connexion locale sur un Forgejo anterieur a la v10
|
|
# `ENABLE_INTERNAL_SIGNIN` a ete ajoute en v10 (suivi amont, issue 7476). Sur une
|
|
# version anterieure il est ignore EN SILENCE : le role croirait avoir ferme la porte
|
|
# alors qu'elle reste ouverte. On refuse plutot que de laisser croire.
|
|
ansible.builtin.assert:
|
|
that:
|
|
- serveur_forgejo_version is version('10.0.0', '>=')
|
|
fail_msg: >-
|
|
serveur_forgejo_connexion_locale=false exige Forgejo >= 10.0.0
|
|
(ici {{ serveur_forgejo_version }}) : le reglage serait ignore sans erreur.
|
|
Mettre a jour, ou assumer la connexion locale en la passant a true.
|
|
when: not (serveur_forgejo_connexion_locale | bool)
|
|
|
|
- name: Exiger les secrets Forgejo (Vault)
|
|
ansible.builtin.assert:
|
|
that:
|
|
- serveur_forgejo_secret_key | length > 0
|
|
- serveur_forgejo_internal_token | length > 0
|
|
- serveur_forgejo_admin_password | length > 0
|
|
fail_msg: "secret_key, internal_token et admin_password sont requis (Ansible Vault)."
|
|
|
|
- name: Resoudre la base de donnees depuis le registre (role partage)
|
|
ansible.builtin.include_role:
|
|
name: resoudre_base
|
|
vars:
|
|
resoudre_base_groupe: "{{ serveur_forgejo_groupe }}"
|
|
|
|
- name: Adopter les facts de base pour Forgejo
|
|
ansible.builtin.set_fact:
|
|
serveur_forgejo_entree: "{{ resoudre_base_entree }}"
|
|
serveur_forgejo_db_password: "{{ resoudre_base_db_password }}"
|
|
serveur_forgejo_db_host: "{{ resoudre_base_db_host }}"
|
|
serveur_forgejo_db_port: "{{ resoudre_base_db_port }}"
|
|
no_log: true
|
|
|
|
- name: Creer l'utilisateur systeme git
|
|
ansible.builtin.user:
|
|
name: "{{ serveur_forgejo_utilisateur }}"
|
|
system: true
|
|
shell: /bin/bash
|
|
home: "/home/{{ serveur_forgejo_utilisateur }}"
|
|
create_home: true
|
|
comment: "Git Version Control"
|
|
|
|
- name: Telecharger le binaire Forgejo
|
|
ansible.builtin.get_url:
|
|
url: "{{ serveur_forgejo_url }}"
|
|
dest: "/usr/local/bin/forgejo-{{ serveur_forgejo_version }}"
|
|
owner: root
|
|
group: root
|
|
mode: "0755"
|
|
|
|
- name: Activer la version courante du binaire
|
|
ansible.builtin.file:
|
|
src: "/usr/local/bin/forgejo-{{ serveur_forgejo_version }}"
|
|
dest: "{{ serveur_forgejo_binaire }}"
|
|
state: link
|
|
notify: Redemarrer forgejo
|
|
|
|
- name: Creer les repertoires de donnees
|
|
ansible.builtin.file:
|
|
path: "{{ serveur_forgejo_data }}/{{ item }}"
|
|
state: directory
|
|
owner: "{{ serveur_forgejo_utilisateur }}"
|
|
group: "{{ serveur_forgejo_utilisateur }}"
|
|
mode: "0750"
|
|
loop:
|
|
- ""
|
|
- custom
|
|
- data
|
|
- log
|
|
|
|
- name: Creer le repertoire de configuration
|
|
ansible.builtin.file:
|
|
path: "{{ serveur_forgejo_config_dir }}"
|
|
state: directory
|
|
owner: root
|
|
group: "{{ serveur_forgejo_utilisateur }}"
|
|
mode: "0770"
|
|
|
|
- name: Deployer app.ini
|
|
ansible.builtin.template:
|
|
src: app.ini.j2
|
|
dest: "{{ serveur_forgejo_config }}"
|
|
owner: "{{ serveur_forgejo_utilisateur }}" # Forgejo persiste des secrets générés (oauth2 JWT) → doit pouvoir écrire
|
|
group: "{{ serveur_forgejo_utilisateur }}"
|
|
mode: "0640"
|
|
no_log: true
|
|
notify: Redemarrer forgejo
|
|
|
|
- name: Deployer l'identite visuelle (logo, favicon, accent aurore, accueil)
|
|
ansible.builtin.copy:
|
|
src: custom/
|
|
dest: "{{ serveur_forgejo_data }}/custom/"
|
|
owner: "{{ serveur_forgejo_utilisateur }}"
|
|
group: "{{ serveur_forgejo_utilisateur }}"
|
|
mode: "0644"
|
|
directory_mode: "0755"
|
|
when: serveur_forgejo_branding | bool
|
|
notify: Redemarrer forgejo
|
|
|
|
- name: Deployer l'unite systemd forgejo
|
|
ansible.builtin.template:
|
|
src: forgejo.service.j2
|
|
dest: /etc/systemd/system/forgejo.service
|
|
owner: root
|
|
group: root
|
|
mode: "0644"
|
|
notify: Redemarrer forgejo
|
|
|
|
- name: Activer et demarrer Forgejo
|
|
when: not ansible_check_mode
|
|
ansible.builtin.systemd:
|
|
name: "{{ serveur_forgejo_service }}"
|
|
enabled: true
|
|
state: started
|
|
daemon_reload: true
|
|
|
|
- name: Appliquer les redemarrages Forgejo (config a jour) avant admin/OAuth2
|
|
ansible.builtin.meta: flush_handlers
|
|
|
|
- name: Attendre que Forgejo reponde (migrations terminees)
|
|
ansible.builtin.wait_for:
|
|
host: 127.0.0.1
|
|
port: "{{ serveur_forgejo_http_port }}"
|
|
timeout: 120
|
|
when: not ansible_check_mode
|
|
|
|
- name: Creer le compte administrateur (une fois)
|
|
ansible.builtin.shell:
|
|
cmd: >-
|
|
{{ serveur_forgejo_binaire }} admin user create
|
|
--admin --username {{ serveur_forgejo_admin_user }}
|
|
--email {{ serveur_forgejo_admin_email }}
|
|
--password '{{ serveur_forgejo_admin_password }}'
|
|
--config {{ serveur_forgejo_config }}
|
|
&& touch {{ serveur_forgejo_data }}/.admin-created
|
|
creates: "{{ serveur_forgejo_data }}/.admin-created"
|
|
become: true
|
|
become_user: "{{ serveur_forgejo_utilisateur }}"
|
|
environment:
|
|
GITEA_WORK_DIR: "{{ serveur_forgejo_data }}"
|
|
no_log: true
|
|
|
|
- name: Configurer la source OAuth2 SSO (Keycloak, idempotent)
|
|
ansible.builtin.shell:
|
|
executable: /bin/bash
|
|
cmd: |
|
|
set -euo pipefail
|
|
FJ="{{ serveur_forgejo_binaire }} --config {{ serveur_forgejo_config }}"
|
|
# Les reglages de GROUPE sont RECONCILIES, pas seulement poses a la creation :
|
|
# `add-oauth` une fois puis plus rien laissait un cablage perime vivre
|
|
# indefiniment — c'est ce qui est arrive a la federation LDAP de Keycloak, qui
|
|
# a pointe un hote inexistant pendant des semaines (2026-08-07).
|
|
OPTS_GROUPE=""
|
|
{% if serveur_forgejo_oidc_groupe_admin | length > 0 %}
|
|
OPTS_GROUPE="--group-claim-name {{ serveur_forgejo_oidc_groupe_claim }} --admin-group {{ serveur_forgejo_oidc_groupe_admin }}"
|
|
{% endif %}
|
|
ID=$($FJ admin auth list 2>/dev/null \
|
|
| awk -v n="{{ serveur_forgejo_oidc_nom }}" '$2 == n {print $1}' | head -1)
|
|
if [ -z "$ID" ]; then
|
|
$FJ admin auth add-oauth \
|
|
--name "{{ serveur_forgejo_oidc_nom }}" \
|
|
--provider openidConnect \
|
|
--key "{{ serveur_forgejo_oidc_client_id }}" \
|
|
--secret "$OIDC_SECRET" \
|
|
--auto-discover-url "{{ serveur_forgejo_oidc_discovery }}" \
|
|
$OPTS_GROUPE >/dev/null
|
|
echo SETOPS_CHANGED
|
|
else
|
|
# `update-oauth` est idempotent cote Forgejo : il reecrit les memes valeurs
|
|
# sans effet de bord. On ne peut pas comparer avant/apres (la CLI n'expose
|
|
# pas le detail d'une source), donc on ne signale PAS `changed`.
|
|
$FJ admin auth update-oauth --id "$ID" \
|
|
--auto-discover-url "{{ serveur_forgejo_oidc_discovery }}" \
|
|
$OPTS_GROUPE >/dev/null
|
|
echo SETOPS_OK
|
|
fi
|
|
environment:
|
|
OIDC_SECRET: "{{ serveur_forgejo_oidc_client_secret }}"
|
|
GITEA_WORK_DIR: "{{ serveur_forgejo_data }}"
|
|
become: true
|
|
become_user: "{{ serveur_forgejo_utilisateur }}"
|
|
register: serveur_forgejo_oauth
|
|
changed_when: "'SETOPS_CHANGED' in serveur_forgejo_oauth.stdout"
|
|
no_log: true
|
|
when:
|
|
- serveur_forgejo_oidc_actif | bool
|
|
- 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
|