J'ai repete toute la journee qu'un SITE n'est pas un plan. C'etait faux : j'en
reconstruisais un morceau par morceau dans underlay.yml sans le nommer. Ce qui est vrai,
c'est qu'un site ne DERIVE pas — il declare ses adresses parce qu'il EST le terrain — et
ne passe donc pas par `instancier`. Mais ne pas deriver n'est pas ne pas avoir de plan.
SITE-Chezlepro/plan/{10-intrants,serveurs,applications}.yml ; underlay.yml ne garde que
la fabric. Ce qui est MESURE d'un cote, ce qui est VOULU de l'autre. Les groupes viennent
du registre des applications, les gardes ont suivi le plan (4 controles negatifs).
Huit defauts, tous invisibles chez un tenant parce qu'il a toujours tout :
- client_pki codait `infra-pki-01` EN DUR — vrai par coincidence de nomenclature ;
- aucun moyen pour un service non-root de lire la cle (Forgejo tourne en `git`) ;
- le certificat, PUBLIC par nature, restait en 0600 ;
- l'unite Forgejo n'avait pas d'ExecReload : un cert renouvele aurait ete servi perime ;
- le role ne savait pas servir TLS lui-meme (il y avait toujours un edge) ;
- le cert ne couvrait pas le nom de SERVICE, faute d'`expose:` ;
- les registres se chargeaient en tout-ou-rien : sans domaines.yml, plancher vide ;
- le flux declarait 3000 en dur.
Le message accusait presque toujours autre chose : le DNS quand c'etait un nom faux, une
permission de fichier quand c'etait un port privilegie, rien du tout quand le plancher
s'ecrivait vide.
ROOT_URL est gravee dans les URL de clonage : la forge sert desormais sur 443, avec
CAP_NET_BIND_SERVICE, et son URL n'a plus de port.
Verifie depuis le reseau : Verify return code 0, https://forge.genese.internal/ -> 200.
42 preuves vertes, flux coherents (34 roles, 92 flux).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
98 lines
3.8 KiB
Django/Jinja
98 lines
3.8 KiB
Django/Jinja
; Gere par Set-OPS (role serveur_forgejo). Ne pas editer a la main.
|
|
APP_NAME = {{ serveur_forgejo_app_name }}
|
|
RUN_USER = {{ serveur_forgejo_utilisateur }}
|
|
RUN_MODE = prod
|
|
WORK_PATH = {{ serveur_forgejo_data }}
|
|
|
|
[server]
|
|
DOMAIN = {{ serveur_forgejo_hostname }}
|
|
{# ROOT_URL EST GRAVEE DANS LES URL DE CLONAGE, les webhooks et les courriels. Un port
|
|
qui n'est pas celui du schema y reste pour toujours : chaque ecosysteme descendant
|
|
porterait `:3000` dans son `origin`. On ne l'ecrit donc que s'il est vraiment atypique. #}
|
|
ROOT_URL = https://{{ serveur_forgejo_hostname }}{{ (':' ~ serveur_forgejo_http_port | string) if (serveur_forgejo_tls and serveur_forgejo_http_port | int != 443) else '' }}/
|
|
HTTP_ADDR = {{ serveur_forgejo_http_addr }}
|
|
HTTP_PORT = {{ serveur_forgejo_http_port }}
|
|
{% if serveur_forgejo_tls %}
|
|
; TLS SERVI PAR LA FORGE ELLE-MEME : il n'y a pas d'edge devant elle. Le certificat est
|
|
; celui de la MACHINE, pose et renouvele par `client_pki` depuis l'AC interne.
|
|
PROTOCOL = https
|
|
CERT_FILE = {{ serveur_forgejo_tls_cert }}
|
|
KEY_FILE = {{ serveur_forgejo_tls_cle }}
|
|
{% endif %}
|
|
SSH_DOMAIN = {{ serveur_forgejo_hostname }}
|
|
|
|
[database]
|
|
{% if serveur_forgejo_bd == 'sqlite' %}
|
|
; Un FICHIER, pas un serveur. Il vit dans les donnees de Forgejo, donc la sauvegarde
|
|
; existante l'emporte deja — rien de special a prevoir.
|
|
DB_TYPE = sqlite3
|
|
PATH = {{ serveur_forgejo_db_chemin }}
|
|
{% else %}
|
|
DB_TYPE = postgres
|
|
HOST = {{ serveur_forgejo_db_host }}:{{ serveur_forgejo_db_port | default(5432) }}
|
|
NAME = {{ serveur_forgejo_entree.base }}
|
|
USER = {{ serveur_forgejo_entree.proprietaire }}
|
|
PASSWD = {{ serveur_forgejo_db_password }}
|
|
SSL_MODE = {{ serveur_forgejo_db_sslmode | default('disable') }}
|
|
{% endif %}
|
|
|
|
[security]
|
|
INSTALL_LOCK = true
|
|
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
|
|
{# `| bool` obligatoire : sans lui, une valeur transmise en CHAINE (« false » via
|
|
`-e`, ou un group_vars non typé) est vraie au sens Jinja et le bloc ne sort JAMAIS —
|
|
la connexion locale resterait ouverte en silence. Verifie par rendu reel. #}
|
|
{% if not serveur_forgejo_connexion_locale | bool %}
|
|
; Connexion interne fermee : le SSO est le seul chemin. Le compte local
|
|
; survit et se rattrape par `forgejo admin user change-password` (sudo).
|
|
ENABLE_INTERNAL_SIGNIN = false
|
|
ENABLE_BASIC_AUTHENTICATION = false
|
|
{% endif %}
|
|
{% 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
|
|
PROTOCOL = smtp
|
|
SMTP_ADDR = {{ serveur_forgejo_smtp }}
|
|
SMTP_PORT = 25
|
|
FROM = forge@{{ domaine_interne }}
|
|
|
|
[ui]
|
|
DEFAULT_THEME = {{ serveur_forgejo_theme }}
|
|
|
|
[ui.meta]
|
|
DESCRIPTION = {{ serveur_forgejo_meta_description }}
|
|
|
|
; --- Secret JWT : appartient au SERVICE, relu par le role -------------------------
|
|
; Forgejo genere ce secret au premier demarrage et l'ajoute lui-meme a la fin du
|
|
; fichier. Le gabarit ne le portait pas : chaque rendu l'EFFACAIT donc, Forgejo en
|
|
; generait un nouveau au redemarrage, et le passage suivant recommencait — autrement dit,
|
|
; chaque deploiement faisait tourner le secret JWT de la forge et invalidait les jetons
|
|
; qu'elle avait emis. Trouve par le passage d'idempotence du 2026-08-09 : seule ligne
|
|
; differente entre deux rendus.
|
|
;
|
|
; Le role le RELIT avant de rendre (tache « Relire le secret JWT ») et le repose ici.
|
|
; Vide au premier deploiement : Forgejo le genere alors, et les rendus suivants le
|
|
; conservent.
|
|
[oauth2]
|
|
{% if serveur_forgejo_jwt_secret | default("") %}
|
|
JWT_SECRET = {{ serveur_forgejo_jwt_secret }}
|
|
{% endif %}
|
|
|