Forgejo au SSO OIDC (2e app SSO) — éprouvé sur forge-01

serveur_forgejo (10.0.0) : PostgreSQL via registre, exposé par l'edge
(auto-dérivé), source OAuth2 vers Keycloak (add-oauth idempotent), client
OIDC forgejo via serveur_keycloak_clients, auto-enregistrement OIDC
(identités depuis l'annuaire seulement).

Prouvé : testmail (LDAP) → « Se connecter avec Chezlepro » → compte
auto-créé, connecté au tableau de bord.

5 bugs de 1er déploiement corrigés : dépendance sendmail→postfix ;
app.ini propriété git (persiste secrets) ; ordre admin/migrations
(flush_handlers + wait_for) ; HTTP_ADDR 0.0.0.0 (edge distant) ;
auto-enregistrement OIDC.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Daniel Allaire 2026-07-03 15:52:38 -04:00
parent fa945de5a7
commit e214dcf4ed
5 changed files with 83 additions and 4 deletions

View file

@ -3,6 +3,19 @@
## 2026-07-03
### Ajouté
- **Forgejo branché au SSO OIDC (« Se connecter avec Chezlepro ») — 2e app SSO, prouvée.**
`serveur_forgejo` (10.0.0) éprouvé sur `forge-01` (🔧→⭐), adossé à PostgreSQL (base `forgejo`
auto-provisionnée depuis le registre), exposé par l'edge (vhost + cert SAN + A PowerDNS + alias
plancher, tout auto-dérivé de `expose`). **Source OAuth2** vers Keycloak
(`forgejo admin auth add-oauth`, idempotent, realm `chezlepro`), client OIDC `forgejo`
enregistré via `serveur_keycloak_clients`. Auto-enregistrement OIDC (`[oauth2_client]
ENABLE_AUTO_REGISTRATION` + `ALLOW_ONLY_EXTERNAL_REGISTRATION` : identités depuis l'annuaire
seulement). **Prouvé** (flux authorization code headless) : `testmail` (LDAP) se connecte,
**compte auto-créé** (`testmail@lab.chezlepro.internal`), atterrit sur le tableau de bord.
**5 bugs de 1er déploiement corrigés** : dépendance périmée `serveur_sendmail`→`serveur_postfix`
(le vrai MTA) ; `app.ini` doit appartenir au user `git` (Forgejo persiste des secrets générés) ;
ordre admin/migrations (`flush_handlers` + `wait_for` avant `admin user create`) ; `HTTP_ADDR`
`127.0.0.1`→`0.0.0.0` (l'edge nginx est sur un autre hôte, 502 sinon) ; auto-enregistrement OIDC.
- **PowerDNS — A d'exposition auto-dérivés (le DNS de la Phase 3 des bindings).** `serveur_powerdns`
génère désormais, dans la zone interne, un enregistrement A pour chaque FQDN d'exposition (champ
`expose` des applications) vers l'**edge qui le sert** (`domaines.edge`) — via

View file

@ -66,8 +66,8 @@ groupes:
requiert_groupes_actifs:
- serveur_postgresql
- serveur_nginx
- serveur_sendmail
raison: "Forgejo depend d'une base, d'une publication HTTP(S) et du courriel."
- serveur_postfix
raison: "Forgejo depend d'une base, d'une publication HTTP(S) et d'un relais courriel (MTA Postfix)."
surveillance: "Verifier HTTP(S), base, files Git et envoi courriel."
serveur_nextcloud:

View file

@ -13,6 +13,9 @@ serveur_forgejo_service: "forgejo"
# Publication (derriere serveur_nginx, TLS a l'edge).
serveur_forgejo_hostname: "forge.{{ domaine_interne }}"
# Adresse d'ecoute : 0.0.0.0 car l'edge nginx est sur un AUTRE hote (le distant doit
# joindre le backend). A restreindre par pare-feu (nftables) au reseau interne / a l'edge.
serveur_forgejo_http_addr: "0.0.0.0"
serveur_forgejo_http_port: 3000
# Base de donnees : resolue depuis le registre par le groupe consommateur.
@ -28,3 +31,13 @@ serveur_forgejo_internal_token: "{{ vault_forgejo_internal_token | default('') }
serveur_forgejo_admin_user: "forgejo-admin"
serveur_forgejo_admin_email: "admin@{{ domaine_interne }}"
serveur_forgejo_admin_password: "{{ vault_forgejo_admin | default('') }}" # rempli depuis la voute (vault_forgejo_admin)
# --- SSO OIDC (Keycloak, realm applicatif) — « Se connecter avec Chezlepro » ---
# Requiert client_pki (confiance step_ca) + résolution de l'hôte Keycloak (plancher/DNS).
# Le client OIDC doit exister dans le realm (serveur_keycloak_clients).
serveur_forgejo_oidc_actif: true
serveur_forgejo_oidc_nom: "chezlepro" # slug du callback : /user/oauth2/<nom>/callback
serveur_forgejo_oidc_client_id: "forgejo"
serveur_forgejo_oidc_client_secret: "{{ vault_forgejo_oidc | default('') }}" # voûte (vault_forgejo_oidc)
serveur_forgejo_oidc_realm: "chezlepro"
serveur_forgejo_oidc_discovery: "https://keycloak.{{ domaine_interne }}/realms/{{ serveur_forgejo_oidc_realm }}/.well-known/openid-configuration"

View file

@ -88,7 +88,7 @@
ansible.builtin.template:
src: app.ini.j2
dest: "{{ serveur_forgejo_config }}"
owner: root
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
@ -111,6 +111,16 @@
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: >-
@ -126,3 +136,32 @@
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 }}"
if $FJ admin auth list 2>/dev/null | grep -qw "{{ serveur_forgejo_oidc_nom }}"; then
echo SETOPS_OK
else
$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 }}" >/dev/null
echo SETOPS_CHANGED
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

View file

@ -7,7 +7,7 @@ WORK_PATH = {{ serveur_forgejo_data }}
[server]
DOMAIN = {{ serveur_forgejo_hostname }}
ROOT_URL = https://{{ serveur_forgejo_hostname }}/
HTTP_ADDR = 127.0.0.1
HTTP_ADDR = {{ serveur_forgejo_http_addr }}
HTTP_PORT = {{ serveur_forgejo_http_port }}
SSH_DOMAIN = {{ serveur_forgejo_hostname }}
@ -24,7 +24,21 @@ SECRET_KEY = {{ serveur_forgejo_secret_key }}
INTERNAL_TOKEN = {{ serveur_forgejo_internal_token }}
[service]
{% if serveur_forgejo_oidc_actif %}
; Identites depuis l'annuaire via le SSO uniquement : pas d'inscription locale,
; mais auto-enregistrement des utilisateurs OIDC.
DISABLE_REGISTRATION = false
ALLOW_ONLY_EXTERNAL_REGISTRATION = true
{% else %}
DISABLE_REGISTRATION = true
{% endif %}
{% if serveur_forgejo_oidc_actif %}
[oauth2_client]
ENABLE_AUTO_REGISTRATION = true
USERNAME = preferred_username
ACCOUNT_LINKING = auto
{% endif %}
[mailer]
ENABLED = true