seize-infra-doc/docs/02-traefik-setup.md
Hedi Kalboussi 1e90a85359 Documentation initiale infra Seize — passation J7
- 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
2026-06-05 17:49:43 +00:00

256 lines
7.4 KiB
Markdown

# 02 — Traefik (Reverse Proxy)
> Traefik est le **point d'entrée** unique de l'infrastructure. Il route le trafic vers les bons conteneurs et gère les certificats TLS automatiquement.
---
## 🎯 Rôle de Traefik
| Fonction | Description |
|---|---|
| **Reverse proxy** | Route `<sous-domaine>.seizeconsulting.com` → conteneur correspondant |
| **TLS termination** | Certificats Let's Encrypt automatiques pour tous les sous-domaines |
| **HTTP → HTTPS redirect** | Force le HTTPS partout |
| **ForwardAuth middleware** | Délègue l'auth à OAuth2-Proxy pour le SSO |
| **Dashboard** | UI admin sur `traefik.seizeconsulting.com` |
---
## 📁 Structure
```
~/docker/traefik/
├── docker-compose.yml
├── traefik.yml # Config statique (entrypoints, providers)
├── dynamic.yml # Config dynamique (middlewares, routers manuels)
└── letsencrypt/
└── acme.json # Certificats stockés (chmod 600)
```
---
## 📄 docker-compose.yml
```yaml
services:
traefik:
image: traefik:v3.7.1
container_name: traefik
restart: unless-stopped
command:
- "--api.dashboard=true"
- "--api.insecure=false"
- "--providers.docker=true"
- "--providers.docker.exposedbydefault=false"
- "--providers.docker.network=web"
- "--providers.file.filename=/etc/traefik/dynamic.yml"
- "--providers.file.watch=true"
- "--entrypoints.web.address=:80"
- "--entrypoints.websecure.address=:443"
- "--entrypoints.web.http.redirections.entrypoint.to=websecure"
- "--entrypoints.web.http.redirections.entrypoint.scheme=https"
- "--certificatesresolvers.letsencrypt.acme.email=admin@seizeconsulting.com"
- "--certificatesresolvers.letsencrypt.acme.storage=/letsencrypt/acme.json"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge=true"
- "--certificatesresolvers.letsencrypt.acme.httpchallenge.entrypoint=web"
- "--log.level=INFO"
- "--accesslog=true"
ports:
- "80:80"
- "443:443"
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro
- ./letsencrypt:/letsencrypt
- ./dynamic.yml:/etc/traefik/dynamic.yml:ro
networks:
- web
labels:
# Dashboard sur traefik.seizeconsulting.com
- "traefik.enable=true"
- "traefik.http.routers.traefik.rule=Host(`traefik.seizeconsulting.com`)"
- "traefik.http.routers.traefik.entrypoints=websecure"
- "traefik.http.routers.traefik.tls.certresolver=letsencrypt"
- "traefik.http.routers.traefik.service=api@internal"
- "traefik.http.routers.traefik.middlewares=traefik-auth"
# Basic auth pour le dashboard (à remplacer par OAuth2-Proxy plus tard si on veut SSO)
- "traefik.http.middlewares.traefik-auth.basicauth.users=admin:$$apr1$$xxxxxxxx$$xxxxxxxxxxxxxxxxxxxxxxx"
networks:
web:
external: true
```
⚠️ **Remplacer** :
- `admin@seizeconsulting.com` par votre email Let's Encrypt
- Le hash basicauth via `htpasswd -nb admin <mdp>`
---
## 📄 dynamic.yml (middlewares ForwardAuth)
```yaml
http:
middlewares:
# Middleware ForwardAuth générique pour les outils protégés par OAuth2-Proxy
oauth2-headers:
forwardAuth:
address: "http://oauth2-proxy:4180/oauth2/auth"
trustForwardHeader: true
# ⚠️ LIGNE CRITIQUE : sans 'Cookie', le SSO ne marche pas
authRequestHeaders:
- Cookie
- Authorization
- X-Forwarded-Host
- X-Forwarded-Proto
- X-Forwarded-Uri
authResponseHeaders:
- X-Auth-Request-User
- X-Auth-Request-Email
- X-Auth-Request-Preferred-Username
- X-Auth-Request-Groups
- X-Auth-Request-Access-Token
- X-Forwarded-User
- X-Forwarded-Email
- X-Forwarded-Preferred-Username
- X-Forwarded-Groups
- Authorization
```
⚠️ **Le `Cookie` dans `authRequestHeaders` est ESSENTIEL** — sans ça, le SSO casse complètement (cf. [DECISIONS.md D3](../DECISIONS.md)).
---
## 🚀 Démarrage
```bash
cd ~/docker/traefik
# Créer l'acme.json
touch letsencrypt/acme.json
chmod 600 letsencrypt/acme.json
# Lancer
docker compose up -d
# Vérifier les logs
docker compose logs -f
# Ctrl+C pour quitter
```
### Vérifications
```bash
# Conteneur tourne ?
docker ps | grep traefik
# Logs propres ?
docker logs --tail 30 traefik 2>&1 | grep -i "error\|level=error"
# Accès au dashboard ?
curl -sI https://traefik.seizeconsulting.com
# Doit retourner 401 (demande de basic auth)
```
---
## 🌐 Comment ajouter un service derrière Traefik
### Méthode 1 — Labels Docker (recommandé)
Sur le `docker-compose.yml` du service à exposer, ajouter ces labels :
```yaml
services:
myservice:
image: ...
networks:
- web
labels:
- "traefik.enable=true"
- "traefik.http.routers.myservice.rule=Host(`myservice.seizeconsulting.com`)"
- "traefik.http.routers.myservice.entrypoints=websecure"
- "traefik.http.routers.myservice.tls.certresolver=letsencrypt"
- "traefik.http.services.myservice.loadbalancer.server.port=8080" # port interne du service
networks:
web:
external: true
```
⚠️ **Important** : le service doit être sur le réseau `web` partagé avec Traefik.
### Méthode 2 — Avec SSO (via OAuth2-Proxy)
Pour les services qui n'ont pas de SSO natif, on ajoute OAuth2-Proxy entre Traefik et le service. Voir [04-oauth2-proxy-pattern.md](./04-oauth2-proxy-pattern.md).
---
## 🐛 Troubleshooting
### "Certificat Let's Encrypt en échec"
Symptômes : navigateur dit "Connexion non sécurisée".
Causes possibles :
1. **DNS pas propagé** : `dig +short sub.seizeconsulting.com` doit retourner l'IP du serveur
2. **Ports 80/443 bloqués** : firewall + cloud provider
3. **Rate limit Let's Encrypt** : trop de tentatives, attendre 1h
4. **acme.json corrompu** :
```bash
sudo rm letsencrypt/acme.json
sudo touch letsencrypt/acme.json
sudo chmod 600 letsencrypt/acme.json
docker compose restart
```
### "404 page not found" sur un sous-domaine
Causes possibles :
1. Le service ciblé n'a pas les bons labels Traefik
2. Le service n'est pas sur le réseau `web`
3. Le port interne du service est incorrect dans `loadbalancer.server.port`
4. La règle `Host(...)` est mal écrite (vérifier les backticks)
Vérifier dans le dashboard Traefik : `https://traefik.seizeconsulting.com` → Routers, Services.
### "Bad Gateway 502"
Causes possibles :
1. Le service backend est down
2. Le service écoute sur un port différent de celui annoncé à Traefik
3. Le service écoute sur 127.0.0.1 au lieu de 0.0.0.0
```bash
# Vérifier que le service répond bien sur le port interne attendu
docker exec -it traefik wget -qO- http://myservice:8080
```
### "Le SSO ne marche plus depuis 5 min"
Vérifier la config ForwardAuth :
```bash
grep -A 10 "oauth2-headers" ~/docker/traefik/dynamic.yml
# La ligne "- Cookie" doit être présente dans authRequestHeaders
```
---
## 🔄 Mise à jour Traefik
```bash
cd ~/docker/traefik
docker compose pull
docker compose up -d
```
⚠️ Avant une **major version** (v2 → v3 par exemple) :
- Lire le CHANGELOG
- Tester en local d'abord
- Backup de `acme.json`
---
## 📚 Liens utiles
- Documentation Traefik : https://doc.traefik.io/traefik/
- Référence des middlewares : https://doc.traefik.io/traefik/middlewares/overview/
- ForwardAuth doc : https://doc.traefik.io/traefik/middlewares/http/forwardauth/