feat(forgejo): Git self-host en miroir de GitHub (git.funklab.online, SSO Authentik) (#96)

- k8s/apps/forgejo : deployment (image forgejo:11, config par env), service, PVC nfs,
  IngressRoute interne (git.lab.local) + publique (git.funklab.online + middlewares
  security-headers/ratelimit), Application ArgoCD (ns ai, recurse)
- base PostgreSQL `forgejo` sur storage-01 (rôle postgresql)
- vault : vault_pg_forgejo_password + vault_forgejo_oauth_client_secret
- doc admin/k8s/forgejo.md (archi, OIDC, création du miroir, pièges) + index + CLAUDE.md

GitHub reste la source de vérité (pull-mirror lecture seule) — ArgoCD inchangé.

Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
ALI YESILKAYA 2026-07-07 23:20:33 +02:00 committed by GitHub
parent fe0aa89ffa
commit 224c06041e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
12 changed files with 498 additions and 163 deletions

View file

@ -66,6 +66,7 @@
| [k8s/n8n.md](k8s/n8n.md) | n8n — automatisation, workflows actifs, credentials |
| [k8s/open-webui.md](k8s/open-webui.md) | Open WebUI — chat web, backend LiteLLM |
| [k8s/ghostfolio.md](k8s/ghostfolio.md) | Ghostfolio — suivi de portefeuille (PostgreSQL s01 + Redis) |
| [k8s/forgejo.md](k8s/forgejo.md) | Forgejo — Git self-host, miroir de GitHub (git.funklab.online, SSO) |
| [k8s/auth-portal.md](k8s/auth-portal.md) | Authentik + Guacamole — architecture, déploiement, accès Internet, pièges |
| [k8s/auth-portal-admin.md](k8s/auth-portal-admin.md) | Portail — administration : utilisateurs, machines, apps du hub, révocation |
| [k8s/public-domain.md](k8s/public-domain.md) | Domaine public `funklab.online` — HTTPS Let's Encrypt, apps exposées, ajout d'app |

126
admin/k8s/forgejo.md Normal file
View file

@ -0,0 +1,126 @@
# Forgejo — Git self-host (miroir de GitHub)
Forge Git **Forgejo** dans le cluster, exposée dans le hub (`git.funklab.online`, SSO
Authentik) et configurée en **miroir lecture seule** du dépôt GitHub `Funk-lab`.
GitHub reste la **source de vérité** (ArgoCD continue d'y tirer, rien n'est modifié) ;
Forgejo en fournit une copie locale synchronisée + une UI + de la résilience.
Namespace : **`ai`**. Base **PostgreSQL sur storage-01** (pattern Ghostfolio/n8n).
## Vue d'ensemble
```
GitHub (Funk-lab, source de vérité)
│ pull-mirror (toutes les ~10 min, HTTPS + PAT lecture)
Forgejo (cluster, ns ai) ──HTTPS──▶ git.funklab.online (SSO Authentik) / git.lab.local (LAN)
└─ dépôts sur PVC nfs `forgejo-data` ; métadonnées sur PostgreSQL s01 (base `forgejo`)
```
- **Sens de synchro** : GitHub → Forgejo uniquement (miroir). On ne pousse pas depuis
Forgejo. ArgoCD n'est pas touché (il tire toujours `git@github.com:...Funk-lab`).
- **Clone HTTPS uniquement** (`DISABLE_SSH=true`) — pas de port 22 supplémentaire exposé.
## Composants
- **Deployment** `forgejo` (`k8s/apps/forgejo/`) : image `codeberg.org/forgejo/forgejo:11`,
config **par variables d'env** `FORGEJO__section__CLE` (pas d'app.ini versionné).
- **PVC** `forgejo-data` (RWO, nfs, 10Gi) monté sur `/data` : dépôts git + `app.ini`
généré (dont `INTERNAL_TOKEN` persistant).
- **PostgreSQL** sur storage-01 : base + user `forgejo` (rôle Ansible `postgresql`).
- **IngressRoutes** : `git.lab.local` (interne, web) + `git.funklab.online` (websecure,
Let's Encrypt, + middlewares `security-headers`/`ratelimit`).
## Secrets
Vault Ansible (`make vault-view`) :
| Variable | Usage |
|---|---|
| `vault_pg_forgejo_password` | Base PG `forgejo` (= clé `pg-password` du secret k8s) |
| `vault_forgejo_oauth_client_secret` | Client secret OIDC Forgejo côté Authentik |
Secret k8s (créé à la main, **hors git**, comme les autres apps) :
```bash
kubectl -n ai create secret generic forgejo-secret \
--from-literal=pg-password='<vault_pg_forgejo_password>' \
--from-literal=secret-key="$(openssl rand -base64 32)"
```
> `secret-key` chiffre les données sensibles internes de Forgejo — le fixer via le
> secret (plutôt que le laisser régénérer) garde les sessions stables entre redéploiements.
## Déploiement (ordre)
1. **Base** : `ansible-playbook -i inventory.yml playbooks/storage-01.yml --tags postgresql`
(crée la base + user `forgejo`).
2. **Secret k8s** ci-dessus (avant le 1er sync, sinon `CreateContainerConfigError`).
3. **Merge sur `main`** → ArgoCD crée l'Application `forgejo` (~3 min).
4. **OIDC + admin + miroir** : étapes ci-dessous (config en base, hors IaC).
## Configuration OIDC (Authentik + Forgejo)
### Côté Authentik (UI)
1. *Providers → Create → OAuth2/OpenID Provider* :
- Name `forgejo`, flow `implicit-consent`, **Client type : Confidential**
- Client ID `forgejo` · Client Secret = `vault_forgejo_oauth_client_secret`
- **Redirect URI (Strict)** : `https://git.funklab.online/user/oauth2/authentik/callback`
- Signing Key : le certificat self-signed
2. *Applications → Create* : Name `Forgejo`, **slug `forgejo`**, provider `forgejo`,
Launch URL `https://git.funklab.online`
3. *Bindings* → lier un groupe (ou ouvert). Membres de **`lab-admins`** → admin Forgejo.
### Côté Forgejo (CLI, une fois)
La source d'auth OIDC s'ajoute par commande (config en base — pas d'admin préalable requis) :
```bash
kubectl -n ai exec deploy/forgejo -- forgejo admin auth add-oauth \
--name authentik \
--provider openidConnect \
--key forgejo \
--secret '<vault_forgejo_oauth_client_secret>' \
--auto-discover-url https://auth.funklab.online/application/o/forgejo/.well-known/openid-configuration \
--group-claim-name groups \
--admin-group lab-admins \
--scopes openid --scopes profile --scopes email
```
Ensuite : `https://git.funklab.online` → bouton **« Se connecter avec authentik »**.
Le **premier** utilisateur créé devient admin ; via `--admin-group lab-admins`, tout
membre du groupe est admin. (Break-glass sans SSO : créer un admin local
`kubectl -n ai exec deploy/forgejo -- forgejo admin user create --admin ...`.)
## Créer le miroir de Funk-lab
Une fois connecté (admin) : **+ → New Migration → GitHub** :
- Clone Address : `https://github.com/Alkatrazz24/Funk-lab.git`
- Cocher **« This repository will be a mirror »**
- Le dépôt étant **privé**, renseigner un **PAT GitHub en lecture seule**
(*Settings GitHub → Developer settings → Fine-grained token*, scope `Contents: read`
sur `Funk-lab`)
- Owner : ton compte · Intervalle de synchro : `10m` (défaut modifiable)
Forgejo re-tire alors GitHub automatiquement. Forcer une synchro : page du dépôt →
*Settings → Mirror Settings → Synchronize Now*.
> Alternative API (au lieu de l'UI) : `POST /api/v1/repos/migrate` avec `"mirror": true`
> et `"auth_token": "<PAT>"` (jeton Forgejo perso en en-tête).
## Pièges / notes
1. **Miroir = lecture seule** : ne pas committer dans Forgejo, les changements seraient
écrasés au prochain pull. Le workflow reste GitHub (PR) → ArgoCD.
2. **Repo privé** → PAT GitHub obligatoire à la création du miroir (sinon `authentication
required`). Le PAT est stocké chiffré par Forgejo en base.
3. **Config en base** (source OIDC, miroir) hors IaC — comme Authentik/Guacamole. Backup
PG = gap connu.
4. **`git.funklab.online` déjà résolu** par le wildcard OVH + dnsmasq split-horizon —
aucun ajout DNS. Le cert Let's Encrypt s'émet au 1er accès (HTTP-01).
5. **PVC RWO + `strategy: Recreate`** : un seul pod monte `/data`. Ne pas passer en
plusieurs réplicas sans stockage RWX + config HA.
6. **Dépannage OIDC** : `kubectl -n ai logs deploy/forgejo | grep -i oauth`. Redirect URI
au caractère près et slug Authentik = `forgejo` (sinon discovery 404, cf. auth-portal).

View file

@ -99,6 +99,7 @@ Authentik (`https://auth.funklab.online`) et directement par leur URL.
| **Open WebUI** | `openwebui.funklab.online` | SSO OIDC | `https://openwebui.funklab.online/oauth/oidc/callback` |
| **Argo CD** | `argocd.funklab.online` | SSO OIDC (lab-admins→admin) | `https://argocd.funklab.online/auth/callback` |
| **n8n** | `n8n.funklab.online` | **login natif** (SSO = Enterprise, indispo en communautaire) | — |
| **Forgejo** (Git, miroir GitHub) | `git.funklab.online` | SSO OIDC (lab-admins→admin) | `https://git.funklab.online/user/oauth2/authentik/callback` |
- Chaque app OIDC : provider Authentik **Confidential**, client secret archivé au vault
(`vault_<app>_oauth_client_secret` / `vault_argocd_oidc_client_secret`) et dans un