seize-infra-doc/docs/05-applications.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

359 lines
10 KiB
Markdown

# 05 — Applications déployées
> Détails de chaque application protégée par SSO.
---
## 📋 Vue d'ensemble
| App | Image Docker | SSO via | Port interne | URL |
|---|---|---|---|---|
| Gitea | `gitea/gitea:1.22` | OIDC natif | 3000 (HTTP), 22 (SSH) | git.seizeconsulting.com |
| n8n | `n8nio/n8n:latest` | OAuth2-Proxy | 5678 | n8n.seizeconsulting.com |
| Portainer | `portainer/portainer-ce:latest` | OAuth2-Proxy | 9000 | portainer.seizeconsulting.com |
| Code Server | `lscr.io/linuxserver/code-server:latest` | OAuth2-Proxy | 8443 | code.seizeconsulting.com |
| Uptime Kuma | `louislam/uptime-kuma:1` | OAuth2-Proxy | 3001 | status.seizeconsulting.com |
---
## 🐙 Gitea
### Spécificité : SSO OIDC natif
Contrairement aux autres, Gitea **ne passe PAS par OAuth2-Proxy**. Il a sa propre intégration OIDC.
### docker-compose.yml (résumé)
Voir `configs/gitea/docker-compose.yml.template`.
```yaml
services:
gitea:
image: gitea/gitea:1.22
container_name: gitea
environment:
USER_UID: 1000
USER_GID: 1000
GITEA__database__DB_TYPE: postgres
GITEA__database__HOST: postgres:5432
GITEA__database__NAME: gitea
GITEA__database__USER: gitea
GITEA__database__PASSWD: ${GITEA_DB_PASSWORD}
GITEA__server__DOMAIN: git.seizeconsulting.com
GITEA__server__ROOT_URL: https://git.seizeconsulting.com/
GITEA__server__SSH_DOMAIN: git.seizeconsulting.com
# Auto-registration via OIDC
GITEA__oauth2_client__ENABLE_AUTO_REGISTRATION: "true"
GITEA__oauth2_client__USERNAME: preferred_username
GITEA__oauth2_client__ACCOUNT_LINKING: auto
# Désactiver le register manuel (SSO uniquement)
GITEA__service__DISABLE_REGISTRATION: "true"
volumes:
- ./data:/data
- /etc/timezone:/etc/timezone:ro
- /etc/localtime:/etc/localtime:ro
ports:
- "22:22" # SSH Git
labels:
- "traefik.enable=true"
- "traefik.http.routers.gitea.rule=Host(`git.seizeconsulting.com`)"
- "traefik.http.routers.gitea.entrypoints=websecure"
- "traefik.http.routers.gitea.tls.certresolver=letsencrypt"
- "traefik.http.services.gitea.loadbalancer.server.port=3000"
networks:
- web
- backend
```
### Configuration SSO côté Gitea (après premier login)
1. Aller sur `https://git.seizeconsulting.com` → setup initial
2. Créer un compte admin Gitea (local, sera utilisé pour configurer le reste)
3. Site Administration → Authentication Sources → Add :
- Type : **OAuth2**
- Authentication Name : `Zitadel`
- OAuth2 Provider : **OpenID Connect**
- Client ID : `<de Zitadel>`
- Client Secret : `<de Zitadel>`
- OpenID Connect Auto Discovery URL : `https://sso.seizeconsulting.com/.well-known/openid-configuration`
- Skip Local 2FA : ✅ (Zitadel gère MFA)
4. **Save**
### Configuration côté Zitadel
Créer une app dans Projects → Infra Seize → Applications :
- Type : Web
- Authentication Method : Basic
- Grant Type : Authorization Code
- Redirect URL : `https://git.seizeconsulting.com/user/oauth2/Zitadel/callback`
- Post-logout Redirect : `https://git.seizeconsulting.com/`
- Token Settings : JWT + User profile info dans ID Token
### Caractéristiques
-**Auto-registration** : à la 1ère connexion via SSO, le compte Gitea est auto-créé
-**Username = trigramme** (lu depuis `preferred_username` Zitadel)
-**Registration manuelle désactivée** : SSO obligatoire pour les nouveaux users
### Rôles RBAC
Gitea n'utilise **pas** les rôles Zitadel directement. Les permissions Gitea sont gérées en interne (organizations, teams, repos). Pour l'instant, **tous les users ont accès en lecture** sur les repos publics.
À configurer plus tard : créer des **organizations** par BU et donner accès en fonction.
---
## ⚙️ n8n
### docker-compose.yml (résumé)
```yaml
services:
n8n:
image: n8nio/n8n:latest
container_name: n8n
environment:
DB_TYPE: postgresdb
DB_POSTGRESDB_HOST: postgres
DB_POSTGRESDB_PORT: 5432
DB_POSTGRESDB_DATABASE: n8n
DB_POSTGRESDB_USER: n8n
DB_POSTGRESDB_PASSWORD: ${N8N_DB_PASSWORD}
N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY}
N8N_HOST: n8n.seizeconsulting.com
N8N_PORT: 5678
N8N_PROTOCOL: https
WEBHOOK_URL: https://n8n.seizeconsulting.com/
# ⚠️ Pas de labels Traefik ici : c'est OAuth2-Proxy qui est exposé
networks:
- web
- backend
```
### Particularités
- ⚠️ **N8N_ENCRYPTION_KEY** : critique pour décrypter les workflows et credentials. **À sauvegarder absolument**.
- L'auth n8n native est désactivée car OAuth2-Proxy fait l'auth en amont.
- Les **workflows** sont stockés dans Postgres (base `n8n`).
### Limitation RBAC
n8n CE (Community Edition) **ne supporte pas le RBAC granulaire** :
- Tous les users authentifiés ont accès à TOUS les workflows
- Pas de notion de "team" ou "project" en CE
→ C'est pourquoi le RBAC se fait **côté intranet** (cacher la carte aux non-autorisés). Voir [DECISIONS.md D7](../DECISIONS.md).
Pour vrai RBAC :
- Soit migrer vers **Activepieces** (gratuit, multi-tenant natif)
- Soit acheter **n8n Enterprise** (~12k€/an)
---
## 🐳 Portainer
### docker-compose.yml (résumé)
```yaml
services:
portainer:
image: portainer/portainer-ce:latest
container_name: portainer
volumes:
- /var/run/docker.sock:/var/run/docker.sock # ⚠️ Accès complet à Docker !
- ./data:/data
networks:
- web
```
### Particularités
- ⚠️ **Accès au socket Docker** : Portainer a un contrôle **total** sur tous les conteneurs du serveur. À protéger absolument derrière SSO.
- Auth Portainer native = créée au premier login, à protéger.
- **RBAC interne** dans Portainer CE = très limité.
### Limitation RBAC
Portainer CE :
- 1 seul utilisateur admin
- Pas d'organisations/teams
→ RBAC sur l'intranet uniquement. Si besoin de vrai RBAC : **Portainer Business** (~1800€/an) ou migration vers **Komodo**.
---
## 💻 Code Server
### docker-compose.yml (résumé)
```yaml
services:
code-server:
image: lscr.io/linuxserver/code-server:latest
container_name: code-server
environment:
PUID: 1000
PGID: 1000
TZ: Europe/Paris
PASSWORD: ${CODE_PASSWORD} # Fallback si SSO down
SUDO_PASSWORD: ${CODE_PASSWORD}
DEFAULT_WORKSPACE: /config/workspace
volumes:
- ./config:/config
networks:
- web
```
### Particularités
- VS Code dans le navigateur
- L'OAuth2-Proxy gère l'auth en amont, mais Code Server a aussi son propre mdp en fallback (`CODE_PASSWORD`)
- Workspaces partagés dans `./config/workspace/`
### Limitation RBAC
Pas de notion de "team" ou "workspace par user" en local. Tout user accède au même workspace.
→ Pour vrai RBAC : **OpenVSCode Server** (multi-user natif).
---
## 📈 Uptime Kuma
### docker-compose.yml (résumé)
```yaml
services:
uptime-kuma:
image: louislam/uptime-kuma:1
container_name: uptime-kuma
volumes:
- ./data:/app/data
networks:
- web
```
### Particularités
- Outil de monitoring (HTTP/TCP/Ping checks)
- Statuspages publiques possibles (mais on les laisse derrière SSO ici)
- 1 seul user admin
### Configuration recommandée
Une fois SSO en place, **désactiver le compte admin local** ou changer le mdp en quelque chose de très long (le SSO suffit).
### Limitation RBAC
Pareil que les autres : 1 seul user, pas de RBAC.
→ Pour vrai RBAC : **Gatus** (config-as-code, multi-tenant).
---
## 🏠 Intranet (page d'accueil)
### docker-compose.yml
```yaml
services:
intranet:
image: nginx:alpine
container_name: intranet
restart: unless-stopped
volumes:
- ./index.html:/usr/share/nginx/html/index.html:ro
- ./logo.png:/usr/share/nginx/html/logo.png:ro
- ./roles-mapping.json:/usr/share/nginx/html/roles-mapping.json:ro
- ./nginx-rbac.conf:/etc/nginx/nginx.conf:ro
networks:
- web
```
### Caractéristiques
- Simple nginx avec un HTML statique
- **Filtrage RBAC côté JavaScript** (voir [07-rbac-intranet.md](./07-rbac-intranet.md))
- Nginx fait du `sub_filter` pour injecter l'email user dans l'HTML
- L'HTML cache les cartes selon le rôle
### Fichiers critiques
| Fichier | Usage |
|---|---|
| `index.html` | Le HTML avec les cartes et le JavaScript RBAC |
| `roles-mapping.json` | Mapping `email → role` (généré par script Python) |
| `nginx-rbac.conf` | Config nginx avec `sub_filter` pour injecter `__USER_EMAIL__` |
| `logo.png` | Logo Seize |
---
## 🗄️ PostgreSQL (principal)
### docker-compose.yml
```yaml
services:
postgres:
image: postgres:16-alpine
container_name: postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: postgres
volumes:
- ./data:/var/lib/postgresql/data
networks:
- backend
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
```
### Particularités
- Postgres **mutualisé** entre Gitea et n8n (databases séparées dans la même instance)
- Pas exposé publiquement (réseau `backend` uniquement)
- ⚠️ **Postgres Zitadel est séparé** (dans son propre docker-compose)
### Databases hébergées
| Database | Owner | Service |
|---|---|---|
| postgres | postgres | (admin) |
| gitea | gitea | Gitea |
| n8n | n8n | n8n |
| authentik | authentik | Authentik (obsolète) |
---
## 📦 Volumes critiques par app
| App | Volume | Quoi |
|---|---|---|
| Gitea | `./data` | Repos, config, attachments |
| Portainer | `./data` | Compose stacks, snapshots |
| Code Server | `./config` | Workspace, settings, plugins |
| Uptime Kuma | `./data` | Monitors, history, statuspages |
| Postgres | `./data` | Toutes les DBs (sauf Zitadel) |
| Zitadel | `./postgres-data` + `./machinekey` | Auth complète |
---
## 🔄 Ajouter une nouvelle app — checklist
Voir [OPERATIONS.md](../OPERATIONS.md) section "Ajouter un nouvel outil".
1. ✅ DNS record A `<app>.seizeconsulting.com`
2. ✅ Créer `~/docker/<app>/` avec docker-compose.yml
3. ✅ Créer l'app dans Zitadel (Project Infra Seize)
4. ✅ Récupérer Client ID + Secret
5. ✅ Créer OAuth2-Proxy dédié `~/docker/oauth2-proxy-<app>/`
6. ✅ Tester le login
7. ✅ Ajouter la carte dans `~/docker/intranet/index.html` avec `data-app="<app>"`
8. ✅ Ajouter la ligne dans la matrice RBAC du JavaScript
9. ✅ Restart intranet
10. ✅ Tester avec différents profils