- 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
12 KiB
06 — Import des utilisateurs depuis Furious Squad
Procédure complète qui a permis d'importer 88 collaborateurs Seize de Furious vers Zitadel le 5 juin 2026.
🎯 Objectif
Synchroniser les 88 collaborateurs Seize actifs depuis Furious Squad (source de vérité RH) vers Zitadel (Identity Provider), avec :
- 1 compte Zitadel par collaborateur
- Metadata Furious préservées (job_title, manager, BU, etc.)
- Mots de passe temporaires générés
- Possibilité d'attribuer des rôles RBAC ensuite
🏗️ Architecture du process
Furious API (REST)
│
│ HTTP Basic Auth (FURIOUS_USERNAME:PASSWORD)
▼
read-all-users.sh ──────────► furious-users-raw.json
│
│
▼
import-furious-to-zitadel.py
│
┌───────────────┼───────────────┐
│ │ │
dry-run test prod
(rien) (3 users) (85 users)
│
▼
Zitadel API v2 ──── service account
│ furious-import-service
▼
88 users créés
│
▼
users-credentials.csv (mdps temporaires)
│
▼
distribution-teams.csv (3 colonnes)
│
▼
Distribution manuelle via Teams
📁 Structure des scripts
~/furious-to-zitadel/
├── .env # FURIOUS_USERNAME, PASSWORD, etc.
├── venv/ # Environnement Python
├── zitadelfuriousimportkey.json # ⚠️ Clé service account (chmod 600)
│
├── read-all-users.sh # Lecture Furious → JSON
├── test-auth.sh # Test connexion API Furious
├── test-1-user.sh # Test lecture d'un user spécifique
│
├── import-furious-to-zitadel.py # ⭐ Script principal d'import
├── merge-duplicates.py # Fusion des doublons (HKA, PSP, ...)
├── reset-test-users-password.py # Reset mdp des users de test
├── extract-distribution-csv.py # Génère CSV pour distribution
├── generate-roles-mapping.py # Génère JSON mapping email → rôle
├── assign-roles.py # Attribue les rôles dans Zitadel
│
├── furious-users-raw.json # Données brutes Furious
├── users-credentials.csv # 89 lignes avec mdps
├── distribution-teams.csv # 88 lignes pour Teams
├── roles-mapping.json # 87 mappings email → rôle
└── import.log # Logs d'exécution
📄 Configuration .env
FURIOUS_USERNAME=<creer_dans_furious_config>
FURIOUS_PASSWORD=<creer_dans_furious_config>
FURIOUS_API_URL=https://seize-consulting.furious-squad.com/api/v2
⚠️ chmod 600 .env
🔑 Création du compte API Furious
1. Connexion Furious
Connexion à https://seize-consulting.furious-squad.com avec un compte admin.
2. Configuration → Générer un utilisateur d'API
- Nom :
import-zitadel(ou similaire) - Permissions :
- ☑️ User > Search (lecture seule)
- ❌ Tout le reste (principe du moindre privilège)
- Generate
3. Récupérer les identifiants
Format identifiant : <nom>.<6chiffres> (exemple : import-zitadel.123456)
- Mot de passe généré aléatoirement.
⚠️ Sauvegarder immédiatement dans le gestionnaire de mots de passe.
4. Tester
cd ~/furious-to-zitadel
source venv/bin/activate
./test-auth.sh
# Doit retourner un JSON avec une réponse valide (pas 401/403)
🤖 Création du service account Zitadel
1. Console Zitadel → Users → New
- Type : Service user
- Username :
furious-import-service - Access Token Type : JWT (important !)
2. Ajouter au rôle IAM_USER_MANAGER
- Aller dans Default Settings (top-right) → Administrators → New
- Sélectionner le service user
furious-import-service - Cocher IAM_USER_MANAGER
- ❌ Ne PAS cocher IAM_OWNER
3. Générer la clé JSON
- Profil du service user → Keys → New
- Type : JSON
- Expiration : 1 an (ou jamais selon besoin)
- Download immediately → fichier
<userId>.json - ⚠️ La clé n'est jamais re-affichée
4. Transférer sur le serveur
# Depuis le PC (Windows PowerShell ou Linux)
scp 375992380685287427.json hedi@<server>:~/furious-to-zitadel/zitadelfuriousimportkey.json
# Sur le serveur
ssh hedi@<server>
chmod 600 ~/furious-to-zitadel/zitadelfuriousimportkey.json
🐍 Environnement Python
cd ~/furious-to-zitadel
python3 -m venv venv
source venv/bin/activate
pip install requests pyjwt cryptography
🚀 Procédure d'import — pas à pas
Étape 1 — Lire les users depuis Furious
cd ~/furious-to-zitadel
source venv/bin/activate
./read-all-users.sh
→ Génère furious-users-raw.json (29 Ko, 94 users dont 88 actifs).
Étape 2 — Test d'authentification Zitadel
# Test que la clé Zitadel marche
python3 -c "
import json
data = json.load(open('zitadelfuriousimportkey.json'))
print('UserId:', data.get('userId'))
print('KeyId:', data.get('keyId'))
print('Type:', data.get('type'))
"
Étape 3 — Dry-run (simulation, aucune écriture)
python3 import-furious-to-zitadel.py --mode dry-run
→ Affiche ce que ferait le script sans rien créer.
Doit afficher :
[DRY-RUN] Would create: yves.canauxdebonfils@seizeconsulting.com (Yves Canaux de Bonfils)
[DRY-RUN] Would create: oussama.azzabi@seizeconsulting.com (Oussama Azzabi)
...
Total : 88 users would be created
Étape 4 — Test sur 3 users
python3 import-furious-to-zitadel.py --mode test
→ Crée 3 users dans Zitadel (les furious_id 1, 2, 3).
Vérification dans Zitadel UI : Console → Users → vérifier que les 3 users sont créés avec leurs metadata.
Étape 5 — Import production
⚠️ Étape sensible — ne pas interrompre.
python3 import-furious-to-zitadel.py --mode prod | tee -a import.log
→ Crée les 85 users restants. Durée : ~2 minutes.
Logs en temps réel + sauvegarde dans import.log.
Étape 6 — Vérification
# Compter les users créés dans Zitadel via API
python3 -c "
# Voir le script pour récupérer le count
"
# Compter les lignes du CSV de credentials
wc -l users-credentials.csv
# Doit afficher : 89 (1 header + 88 users)
🔀 Gestion des doublons
Contexte
4 anciens admins existaient déjà dans Zitadel avant l'import :
- HKA (Hedi Kalboussi) → ID
375119988404518915 - PSP (Philippe Spoljaric) → ID
375120224527056899 - PYT (Pierre-Yves Tachon) → ID
375778940960112643 - Jules (Jules Bataille) → ID
375777592659148803
L'import a créé des doublons avec leurs emails complets.
Stratégie
Voir DECISIONS.md D5. En bref :
- Garder l'ancien compte (avec MFA configuré)
- Supprimer le nouveau doublon
- Copier les metadata Furious du nouveau vers l'ancien (pour pas perdre l'info)
Exécution
# 1. Éditer le script merge-duplicates.py pour adapter le mapping
nano merge-duplicates.py
# Configurer la variable DUPLICATES :
DUPLICATES = [
{
"keep_user_id": "375119988404518915", # HKA ancien
"delete_email": "hedi.kalboussi@seizeconsulting.com",
"furious_id": 5,
},
# ... 3 autres
]
# 2. Lancer
python3 merge-duplicates.py
→ Pour chaque doublon :
- Lit le user "nouveau" via email
- Copie ses metadata sur l'ancien
- Supprime le nouveau
🎭 Attribution des rôles RBAC
Prérequis
Avant d'attribuer des rôles, créer les 8 rôles dans Zitadel (Project Infra Seize).
Voir 07-rbac-intranet.md pour la création des rôles.
Mapping job_title → rôle
Voir matrices/job-title-to-role.csv pour la matrice complète. Résumé :
JOB_TITLE_TO_ROLE = {
"président": "direction",
"directeur": "direction",
"directeur associé": "direction",
"senior manager": "manager",
"sénior manager": "manager",
"manager": "manager",
"manager bi": "manager",
"expert": "expert",
"expert n2": "expert",
"consultant expert niveau 1": "expert",
"consultant sénior": "consultant_senior",
"consultant expérimenté": "consultant_senior",
"consultant expérimentée": "consultant_senior",
"consultant junior": "consultant_junior",
"stagiaire": "stagiaire",
"assistante": "support",
# ... etc
}
# Cas spécial : status="apprenti" → role="alternant"
Exécution
# 1. Générer le mapping email → role
python3 generate-roles-mapping.py
# 2. Attribuer les rôles dans Zitadel
python3 assign-roles.py
→ Le script :
- Lit chaque user actif Furious
- Détermine son rôle (via mapping job_title ou status)
- Cherche le user dans Zitadel par email
- Lui attribue le rôle via API
POST /v1/users/{id}/grants
Vérification : Console Zitadel → Users → 1 user → Authorizations → doit voir le rôle attribué.
📊 Format CSV produit
users-credentials.csv (sensible, à protéger)
email,prenom,nom,trigramme,furious_id,zitadel_user_id,mdp_temporaire
yves.canauxdebonfils@seizeconsulting.com,Yves,Canaux de Bonfils,YCB,1,375990xxxxxxxxxxx,Y8sR3kp9XmF2
...
distribution-teams.csv (pour distribution mdp)
Nom complet,Email,Mot de passe
Yves Canaux de Bonfils,yves.canauxdebonfils@seizeconsulting.com,Y8sR3kp9XmF2
...
⚠️ Anti-patterns à éviter
- ❌ Ne PAS sauter le dry-run : permet de détecter des erreurs avant impact prod
- ❌ Ne PAS importer avec rôles directement : importer d'abord, attribuer ensuite (cf. D6)
- ❌ Ne PAS donner IAM_OWNER au service account : utiliser IAM_USER_MANAGER
- ❌ Ne PAS oublier de supprimer le CSV après distribution des mdps
- ❌ Ne PAS coller les identifiants Furious dans une conversation IA
🔄 Synchronisation périodique (à mettre en place)
Aujourd'hui, l'import est manuel (one-shot du 5 juin). À l'avenir :
Option recommandée : workflow n8n quotidien
Workflow n8n à 3h du matin :
- HTTP Request vers Furious : récupérer la liste des users
- HTTP Request vers Zitadel : récupérer la liste des users actuels
- Code node : calculer le diff
- Switch :
- Nouveau dans Furious → POST Zitadel pour créer
- Départ dans Furious (departure_date != "0000-00-00") → PATCH Zitadel pour désactiver
- Changement job_title → PATCH metadata + réattribuer rôle
- Slack/Teams notification : résumé du sync
⏱️ Estimation : 1 journée de dev n8n.
🐛 Troubleshooting import
"Erreur 401 lors de l'auth Zitadel"
Causes possibles :
- Clé JSON corrompue → re-télécharger depuis Zitadel
- Service account n'a plus le rôle IAM_USER_MANAGER → re-attribuer
- Token JWT mal généré → vérifier que
pyjwtest bien installé
"User déjà existant" lors de l'import
Normal pour les doublons. Le script import-furious-to-zitadel.py skip les users existants par défaut.
"Erreur 400 sur certains users"
Causes courantes :
- Email invalide (espace, caractères spéciaux) dans Furious → corriger dans Furious
- Mot de passe ne respecte pas la policy → le script génère mdp 16 chars random
- Username déjà pris → choisir un autre format (email complet par exemple)
"Le script lit les bonnes données mais Zitadel ne les voit pas"
Vérifier la réponse HTTP retournée par chaque création :
python3 import-furious-to-zitadel.py --mode test --verbose
📚 Voir aussi
- 07-rbac-intranet.md — Suite de l'import : attribution des rôles RBAC
- 03-zitadel-setup.md — Création du service account Zitadel
- ../matrices/job-title-to-role.csv — Matrice de mapping