# 03 — Zitadel (Identity Provider) > Zitadel est le **cœur de l'authentification**. Tous les outils se loggent via lui. --- ## 🎯 Architecture Zitadel ⚠️ **Spécificité importante** : Zitadel se déploie via un **docker-compose complet** qui inclut : - Le serveur API Zitadel - L'UI de login (login v2) - Postgres dédié (séparé du Postgres principal) - Un Traefik dédié interne (séparé du Traefik principal !) → Le Traefik principal de Seize **route uniquement** vers le Traefik interne de Zitadel via la règle `Host(sso.seizeconsulting.com)`. ``` ┌───────────────────────────────────┐ │ Réseau Docker "zitadel" │ │ │ Traefik │ ┌──────────┐ ┌──────────────┐ │ principal ─────▶│ │ Traefik │───▶│ Zitadel │ │ (web) │ │ interne │ │ - API │ │ │ │ │ │ - Login UI │ │ │ └──────────┘ └──────┬───────┘ │ │ │ │ │ ┌───────▼──────┐ │ │ │ Postgres │ │ │ │ (zitadel) │ │ │ └──────────────┘ │ └───────────────────────────────────┘ ``` --- ## 📁 Structure ``` ~/docker/zitadel/ ├── docker-compose.yml # Multi-services (proxy + api + login + db) ├── .env # Configuration et secrets └── machinekey/ # Clés des service accounts (à backup) ``` --- ## 📄 docker-compose.yml (résumé) ⚠️ Le fichier officiel de Zitadel fait ~150 lignes. Voir `configs/zitadel/docker-compose.yml.template` pour la version complète. Services inclus : - `proxy` (Traefik interne) - `zitadel-api` (le moteur Zitadel) - `zitadel-login` (UI de connexion v2) - `postgres` (database dédiée) ### Volumes critiques à backuper ```yaml volumes: - ./postgres-data:/var/lib/postgresql/data # ⚠️ CRITIQUE - ./machinekey:/machinekey # ⚠️ CRITIQUE ``` --- ## 📄 .env (variables clés) ```env # Domaine d'accès ZITADEL_EXTERNALDOMAIN=sso.seizeconsulting.com ZITADEL_EXTERNALPORT=443 ZITADEL_EXTERNALSECURE=true ZITADEL_TLS_ENABLED=false # TLS géré par Traefik externe # Master key (⚠️ NE JAMAIS perdre, NE JAMAIS changer après init) ZITADEL_MASTERKEY=<32-char-random-key> # Postgres ZITADEL_DATABASE_POSTGRES_HOST=postgres ZITADEL_DATABASE_POSTGRES_PORT=5432 ZITADEL_DATABASE_POSTGRES_DATABASE=zitadel ZITADEL_DATABASE_POSTGRES_USER_USERNAME=zitadel ZITADEL_DATABASE_POSTGRES_USER_PASSWORD= ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME=postgres ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD= # Admin initial ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME=zitadel-admin ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD= # Traefik image (pour le proxy interne) TRAEFIK_IMAGE=traefik:v3.6.8 TRAEFIK_DASHBOARD_ENABLED=false TRAEFIK_LOG_LEVEL=INFO TRAEFIK_ACCESSLOG_ENABLED=false PROXY_HTTP_PUBLISHED_PORT=80 ``` ⚠️ **`ZITADEL_MASTERKEY` est immuable** une fois l'instance initialisée. Le perdre = pouvoir reconstruire from scratch uniquement. --- ## 🚀 Premier démarrage ### 1. Préparer l'environnement ```bash mkdir -p ~/docker/zitadel/{postgres-data,machinekey} cd ~/docker/zitadel # Copier docker-compose.yml et .env depuis les templates ``` ### 2. Lancer ```bash docker compose up -d ``` ### 3. Suivre les logs (premier démarrage = 1-2 min) ```bash docker compose logs -f zitadel-api ``` Attendre le message : ``` init step done: type=instance_setup ``` ### 4. Tester l'UI Navigateur : `https://sso.seizeconsulting.com` → Doit afficher la page de login Zitadel. ### 5. Se logger en admin - Username : `zitadel-admin@zitadel.sso.seizeconsulting.com` - Password : celui défini dans `.env` `ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD` ⚠️ **Changer le mdp immédiatement** au premier login. --- ## ⚙️ Configuration post-install via UI ### 1. Default Settings → Policies Aller dans **Default Settings** (icône ⚙️ en haut à droite). #### Password Complexity - ☑️ Min length : 14 - ☑️ Has uppercase - ☑️ Has lowercase - ☑️ Has number - ☑️ Has symbol #### Lockout Policy - ☑️ Max password attempts : 5 - ☑️ Show lockout failures (sécurité : ne pas révéler les comptes) #### MFA (Force MFA pour tous) - ☑️ Force MFA : Enabled - ☑️ MFA Init methods : TOTP, U2F, OTP Email ### 2. Branding - Logo Seize - Couleurs : `--c-accent: #008A81` - Texte personnalisé ### 3. SMTP Provider (à faire quand admin M365 dispo) Default Settings → Notifications → SMTP Provider : ``` Host : smtp.office365.com:587 Username : noreply@seizeconsulting.com Password : From : noreply@seizeconsulting.com TLS : ✅ ``` ### 4. Créer un Project "Infra Seize" Menu Projects → New : - Name : `Infra Seize` - Type : Owned project Project ID à noter : sera utilisé dans tous les scripts. ### 5. Créer le service account `furious-import-service` Voir [06-import-furious.md](./06-import-furious.md). --- ## 🔐 Gestion des Administrators IAM Pour ajouter un user/service account comme admin de toute l'instance : 1. Default Settings → en haut à droite, cliquer sur **"+"** à côté des avatars 2. Page "Administrators" → **"+ New"** 3. Sélectionner l'user 4. Cocher les **rôles minimum nécessaires** : - `IAM_USER_MANAGER` : pour gérer les users via API - `IAM_ORG_MANAGER` : pour gérer les organisations - ❌ Éviter `IAM_OWNER` (trop puissant) --- ## 📊 Volumes critiques à backuper | Volume | Contenu | Criticité | |---|---|---| | `postgres-data/` | Base Zitadel (users, projects, sessions) | 🔴 CRITIQUE | | `machinekey/` | Clés des service accounts | 🔴 CRITIQUE | | `.env` | Secrets de config + MASTERKEY | 🔴 CRITIQUE | ### Backup recommandé ```bash # Backup quotidien automatique (cron) 0 3 * * * docker exec zitadel-postgres-1 pg_dump -U zitadel zitadel > /home/admin/backups/zitadel-$(date +\%Y\%m\%d).sql ``` --- ## 🐛 Troubleshooting ### "Service zitadel-api ne démarre pas" Causes possibles : 1. Postgres pas prêt → attendre 30s et `docker compose restart zitadel-api` 2. `.env` mal configuré → vérifier les variables 3. Migration DB échouée → `docker compose logs zitadel-api | grep -i error` ### "Master key mismatch" ⚠️ **Très grave** : ZITADEL_MASTERKEY a changé alors que l'instance était déjà init. Solution : - Soit retrouver l'ancienne clé - Soit restore depuis backup - Soit reset complet (perte de toutes les données) → Ne jamais changer ZITADEL_MASTERKEY après le premier démarrage. ### "Login impossible pour un user" Vérifier : 1. User existe : Console → Users → Search 2. User actif (pas désactivé) 3. Email vérifié (sinon le login peut bloquer) 4. MFA bien configuré (si forcé au niveau policy) 5. Pas de lockout actif (Failed login attempts) ### "Le scope `urn:zitadel:iam:org:project:roles` ne retourne pas les rôles" Vérifier : 1. Project setting **"Return user roles during authentication"** est coché 2. App setting **"User roles inside ID Token"** est coché 3. Auth Token Type = **JWT** (pas Bearer Token) 4. OAuth2-Proxy demande bien ce scope dans `OAUTH2_PROXY_SCOPE` ### "Service account peut pas créer de users (401/403)" Vérifier : 1. Service account a bien le rôle `IAM_USER_MANAGER` (dans Default Settings → Administrators) 2. Clé JSON valide et non expirée 3. Token JWT signé correctement par le script Python --- ## 📚 Liens utiles - Documentation Zitadel : https://zitadel.com/docs - API v2 reference : https://zitadel.com/docs/apis/resources/user_service_v2 - Self-hosting guide : https://zitadel.com/docs/self-hosting/deploy/overview - Custom claims (Actions V2) : https://zitadel.com/docs/concepts/features/actions_v2