- 6 docs racine (README, HANDOVER, ARCHITECTURE, DECISIONS, INSTALL, OPERATIONS) - 9 docs thématiques dans docs/ - 10 templates docker-compose dans configs/ - 7 scripts Python/Shell d'import Furious vers Zitadel - 2 matrices RBAC Etat infra au 5 juin 2026 : - 88 users Furious importes dans Zitadel - 8 roles RBAC crees et attribues - Intranet filtre les cartes selon role (Approche A) - 7 outils SSO operationnels
13 KiB
ARCHITECTURE — Vue d'ensemble technique
Comprendre comment tout s'imbrique dans l'infra Seize.
🏗️ Vue d'ensemble
Internet
│
│ HTTPS (443) / HTTP (80)
▼
┌──────────────────────┐
│ Traefik (proxy) │
│ - Let's Encrypt │
│ - Routing par Host │
└──────────┬───────────┘
│
┌──────────────┬─────────┼─────────┬──────────────┐
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
┌──────────┐ ┌─────────────┐ ... ┌─────────────┐ ┌─────────────┐
│ Zitadel │ │ OAuth2-Proxy│ │ OAuth2-Proxy│ │ Gitea │
│ (sso.*) │ │ (intranet) │ │ (n8n) │ │ (git.*) SSO │
│ │ │ │ │ │ │ integré │
└────┬─────┘ └──────┬──────┘ └──────┬──────┘ └─────────────┘
│ │ │
│ Auth OIDC │ Forward proxy │ Forward proxy
│ ▼ ▼
│ ┌───────────┐ ┌───────────┐
│ │ Intranet │ │ n8n │
│ │ (nginx) │ │ │
│ │ + RBAC JS │ │ │
│ └───────────┘ └─────┬─────┘
│ │
│ │
▼ ▼
┌──────────┐ ┌──────────┐
│ Postgres │ │ Postgres │
│ (zitadel)│ │ (n8n) │
└──────────┘ └──────────┘
🌐 Réseaux Docker
| Réseau | Type | Utilisé par |
|---|---|---|
web |
external | Traefik, tous les services exposés publiquement |
backend |
external | Postgres, Redis, et services backend internes |
zitadel |
local | Zitadel + son Traefik dédié + Postgres |
proxy |
bridge | Réseau auxiliaire (vérifier usage) |
⚠️ Important : Zitadel a son propre réseau + son propre Traefik (intégré dans son docker-compose). Il est totalement isolé du Traefik principal pour des raisons de sécurité. Le Traefik principal route uniquement vers le Traefik Zitadel sur sso.seizeconsulting.com.
🔐 Flux d'authentification SSO
Flux complet pour un user accédant à l'intranet
1. User → https://intranet.seizeconsulting.com
│
▼
2. Traefik principal → route vers OAuth2-Proxy "intranet"
│
▼
3. OAuth2-Proxy vérifie le cookie de session
│
┌────┴────┐
│ Pas de │
│ session │
▼ │
4. OAuth2-Proxy redirige vers Zitadel
(URL : /oauth2/start → Zitadel login)
│
▼
5. User saisit ses identifiants Zitadel + MFA
│
▼
6. Zitadel valide + génère un code OIDC
│
▼
7. Redirect vers OAuth2-Proxy /oauth2/callback?code=xxx
│
▼
8. OAuth2-Proxy échange le code contre un token JWT
(avec scope : openid email profile urn:zitadel:iam:org:project:roles)
│
▼
9. OAuth2-Proxy stocke le token + cookie de session
│
▼
10. OAuth2-Proxy → forward request vers nginx (intranet)
avec headers :
- X-Forwarded-User: <user_id>
- X-Forwarded-Email: hedi.kalboussi@seizeconsulting.com
- X-Forwarded-Preferred-Username: HKA
- Authorization: Bearer <jwt_token>
│
▼
11. nginx lit le header X-Forwarded-Email
Substitue __USER_EMAIL__ par la vraie valeur dans index.html (sub_filter)
│
▼
12. Browser reçoit l'HTML avec const USER_EMAIL = "hedi.kalboussi@..."
│
▼
13. JavaScript :
- Fetch /roles-mapping.json
- Lookup userEmail → role (ex: "consultant_junior")
- Cache les cartes que ce rôle n'a pas le droit de voir
│
▼
14. User voit uniquement les cartes autorisées
🗂️ Structure des dossiers Docker sur le serveur
/home/hedi/docker/
├── traefik/ # Reverse proxy principal
│ ├── docker-compose.yml
│ ├── traefik.yml # Config statique
│ ├── dynamic.yml # Config dynamique (middlewares, etc.)
│ └── letsencrypt/ # Certificats TLS auto
│
├── zitadel/ # IDP Zitadel (avec son propre Traefik)
│ ├── docker-compose.yml # Multi-services (proxy + login + api + db)
│ ├── .env # Tous les secrets Zitadel
│ └── machinekey/ # Clés service accounts
│
├── postgres/ # Postgres principal (Gitea, n8n, Authentik historique)
│ ├── docker-compose.yml
│ └── data/ # Persistance
│
├── redis/ # Plus utilisé (Authentik historique)
│
├── intranet/ # ⭐ Page d'accueil avec RBAC
│ ├── docker-compose.yml
│ ├── index.html # HTML avec data-app="xxx" + script RBAC
│ ├── roles-mapping.json # Mapping email → rôle (généré par script)
│ ├── nginx-rbac.conf # nginx avec sub_filter pour __USER_EMAIL__
│ └── logo.png
│
├── gitea/ # Forge Git avec SSO Zitadel intégré
│ ├── docker-compose.yml
│ ├── .env
│ └── data/
│
├── n8n/ # Workflows
│ ├── docker-compose.yml
│ ├── .env
│ └── data/
│
├── portainer/ # Gestion Docker
│ ├── docker-compose.yml
│ └── data/
│
├── code-server/ # VS Code dans le navigateur
│ ├── docker-compose.yml
│ ├── .env
│ └── config/
│
├── uptime-kuma/ # Monitoring
│ ├── docker-compose.yml
│ └── data/
│
├── oauth2-proxy/ # ⭐ OAuth2-Proxy pour l'intranet
│ ├── docker-compose.yml
│ └── .env
│
├── oauth2-proxy-n8n/ # OAuth2-Proxy pour n8n
│ ├── docker-compose.yml
│ └── .env
│
├── oauth2-proxy-portainer/ # OAuth2-Proxy pour Portainer
│ ├── docker-compose.yml
│ └── .env
│
├── oauth2-proxy-code/ # OAuth2-Proxy pour Code Server
│ ├── docker-compose.yml
│ └── .env
│
├── oauth2-proxy-status/ # OAuth2-Proxy pour Uptime Kuma
│ ├── docker-compose.yml
│ └── .env
│
├── authentik/ # ❌ Plus utilisé (à archiver/supprimer)
│
├── whoami/ # Test debug (à garder ou supprimer)
│
└── ctop/ # Outil CLI monitoring conteneurs
🎭 Le pattern "OAuth2-Proxy par outil"
Pourquoi ce pattern ?
Chaque outil (n8n, Portainer, etc.) a son propre OAuth2-Proxy dédié. C'est volontaire :
✅ Avantages :
- Configuration différenciée par outil (scopes, callbacks, etc.)
- Pas de SPOF : si un OAuth2-Proxy crash, les autres outils marchent
- Plus simple à débugger
- Permet d'avoir des secrets/clients OIDC différents
❌ Inconvénients :
- 5 conteneurs OAuth2-Proxy en plus (impact RAM minime)
- 5 configurations à maintenir
Anatomie d'un OAuth2-Proxy
Pour chaque outil, on a :
- Un dossier
~/docker/oauth2-proxy-<outil>/ - Un
docker-compose.ymlavec labels Traefik routant<outil>.seizeconsulting.com→ OAuth2-Proxy port 4180 - Un
.envavec :OAUTH2_PROXY_PROVIDER=oidcOAUTH2_PROXY_CLIENT_ID=<id_zitadel>OAUTH2_PROXY_CLIENT_SECRET=<secret_zitadel>OAUTH2_PROXY_OIDC_ISSUER_URL=https://sso.seizeconsulting.comOAUTH2_PROXY_REDIRECT_URL=https://<outil>.seizeconsulting.com/oauth2/callbackOAUTH2_PROXY_UPSTREAMS=http://<outil>:<port>OAUTH2_PROXY_COOKIE_SECRET=<32_chars_random>OAUTH2_PROXY_SCOPE=openid email profile urn:zitadel:iam:org:project:roles
- Une App créée dans Zitadel (project "Infra Seize") avec les bons callbacks
Détails complets dans docs/04-oauth2-proxy-pattern.md.
🧬 Le bug Traefik historique (à connaître)
Symptôme initial : tous les outils SSO étaient déconnectés à chaque requête.
Cause : Traefik supprimait par défaut le header Cookie quand il faisait un ForwardAuth vers OAuth2-Proxy. Du coup OAuth2-Proxy ne voyait pas le cookie de session et redirigeait vers login à chaque fois.
Fix : ajouter dans ~/docker/traefik/dynamic.yml :
http:
middlewares:
oauth2-headers:
forwardAuth:
address: "http://oauth2-proxy:4180/oauth2/auth"
authRequestHeaders:
- Cookie # ← LIGNE CRITIQUE
- Authorization
authResponseHeaders:
- X-Auth-Request-User
- X-Auth-Request-Email
→ Sans Cookie dans authRequestHeaders, rien ne fonctionne.
🎯 RBAC : architecture choisie (Approche A)
1. Furious Squad (source de vérité RH)
│
│ API GraphQL-like
▼
2. Scripts Python d'import (~/furious-to-zitadel/)
│
▼
3. Zitadel : 88 users avec metadata custom
│
▼
4. Script generate-roles-mapping.py
→ génère /docker/intranet/roles-mapping.json
│
▼
5. Intranet (nginx + sub_filter)
→ injecte __USER_EMAIL__ depuis X-Forwarded-Email
→ JavaScript lookup dans roles-mapping.json
→ cache/affiche les cartes selon rôle
Pourquoi Approche A (et pas RBAC complet sur chaque outil) ?
Détails dans DECISIONS.md, section "RBAC Approche A".
TL;DR : 0€, 2-3h de boulot, suffisant pour Seize (88 employés majoritairement non-techniques).
📊 Volumes critiques à backuper
| Données | Volume / Chemin | Criticité |
|---|---|---|
| Base PostgreSQL Zitadel | ~/docker/zitadel/.../data/postgres/ |
🔴 Critique |
| Base PostgreSQL Gitea/n8n | ~/docker/postgres/data/ |
🔴 Critique |
| Données Gitea (repos) | ~/docker/gitea/data/ |
🔴 Critique |
| Données Portainer | ~/docker/portainer/data/ |
🟡 Important |
| Données Uptime Kuma | ~/docker/uptime-kuma/data/ |
🟡 Important |
| Données n8n | volume Docker n8n_data |
🟡 Important |
| Données Code Server | ~/docker/code-server/config/ |
🟢 Récupérable |
| Certificats Let's Encrypt | ~/docker/traefik/letsencrypt/ |
🟢 Auto-régénéré |
| Scripts d'import + clés | ~/furious-to-zitadel/ |
🔴 Critique |
⚠️ Aucun backup automatique en place au moment de la passation. À mettre en priorité.
🔧 Outils CLI utiles installés
| Outil | Usage |
|---|---|
docker |
Gestion conteneurs |
docker compose |
Orchestration |
ctop |
Top des conteneurs (consommation ressources) |
sudo journalctl |
Logs système |
htop |
Top processus |
python3 + venv |
Pour les scripts d'import |
🌍 DNS — Records configurés (chez le registrar)
Tous les sous-domaines pointent vers 151.115.148.243 :
| Record | Type | Valeur |
|---|---|---|
seizeconsulting.com |
A | 151.115.148.243 |
sso.seizeconsulting.com |
A | 151.115.148.243 |
intranet.seizeconsulting.com |
A | 151.115.148.243 |
git.seizeconsulting.com |
A | 151.115.148.243 |
n8n.seizeconsulting.com |
A | 151.115.148.243 |
portainer.seizeconsulting.com |
A | 151.115.148.243 |
code.seizeconsulting.com |
A | 151.115.148.243 |
status.seizeconsulting.com |
A | 151.115.148.243 |
traefik.seizeconsulting.com |
A | 151.115.148.243 |
app.seizeconsulting.com |
A | 151.115.148.243 |
⚠️ Ne PAS oublier d'ajouter un record DNS si tu ajoutes un nouvel outil. Sinon Let's Encrypt échoue.