- 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
436 lines
12 KiB
Markdown
436 lines
12 KiB
Markdown
# 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`
|
|
|
|
```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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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)
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
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.**
|
|
|
|
```bash
|
|
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
|
|
|
|
```bash
|
|
# 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](../DECISIONS.md). 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
|
|
|
|
```bash
|
|
# 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 :
|
|
1. Lit le user "nouveau" via email
|
|
2. Copie ses metadata sur l'ancien
|
|
3. 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](./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é :
|
|
|
|
```python
|
|
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
|
|
|
|
```bash
|
|
# 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 :
|
|
1. Lit chaque user actif Furious
|
|
2. Détermine son rôle (via mapping job_title ou status)
|
|
3. Cherche le user dans Zitadel par email
|
|
4. 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)
|
|
|
|
```csv
|
|
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)
|
|
|
|
```csv
|
|
Nom complet,Email,Mot de passe
|
|
Yves Canaux de Bonfils,yves.canauxdebonfils@seizeconsulting.com,Y8sR3kp9XmF2
|
|
...
|
|
```
|
|
|
|
---
|
|
|
|
## ⚠️ Anti-patterns à éviter
|
|
|
|
1. ❌ **Ne PAS sauter le dry-run** : permet de détecter des erreurs avant impact prod
|
|
2. ❌ **Ne PAS importer avec rôles directement** : importer d'abord, attribuer ensuite (cf. D6)
|
|
3. ❌ **Ne PAS donner IAM_OWNER au service account** : utiliser IAM_USER_MANAGER
|
|
4. ❌ **Ne PAS oublier de supprimer le CSV** après distribution des mdps
|
|
5. ❌ **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 :
|
|
1. **HTTP Request** vers Furious : récupérer la liste des users
|
|
2. **HTTP Request** vers Zitadel : récupérer la liste des users actuels
|
|
3. **Code node** : calculer le diff
|
|
4. **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
|
|
5. **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 :
|
|
1. Clé JSON corrompue → re-télécharger depuis Zitadel
|
|
2. Service account n'a plus le rôle IAM_USER_MANAGER → re-attribuer
|
|
3. Token JWT mal généré → vérifier que `pyjwt` est 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 :
|
|
1. **Email invalide** (espace, caractères spéciaux) dans Furious → corriger dans Furious
|
|
2. **Mot de passe ne respecte pas la policy** → le script génère mdp 16 chars random
|
|
3. **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 :
|
|
```bash
|
|
python3 import-furious-to-zitadel.py --mode test --verbose
|
|
```
|
|
|
|
---
|
|
|
|
## 📚 Voir aussi
|
|
|
|
- [07-rbac-intranet.md](./07-rbac-intranet.md) — Suite de l'import : attribution des rôles RBAC
|
|
- [03-zitadel-setup.md](./03-zitadel-setup.md) — Création du service account Zitadel
|
|
- [../matrices/job-title-to-role.csv](../matrices/job-title-to-role.csv) — Matrice de mapping
|