- 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
513 lines
14 KiB
Markdown
513 lines
14 KiB
Markdown
# OPERATIONS — Maintenance et opérations courantes
|
||
|
||
> Procédures pour maintenir, dépanner, et faire évoluer l'infrastructure Seize.
|
||
|
||
---
|
||
|
||
## 🔍 Vérifications quotidiennes (5 min/jour)
|
||
|
||
### Healthcheck rapide
|
||
|
||
```bash
|
||
# Tous les conteneurs sont-ils Up ?
|
||
sudo docker ps --format "table {{.Names}}\t{{.Status}}" | grep -v "Up"
|
||
# → Aucune ligne sauf le header = tout va bien
|
||
|
||
# Tous les sous-domaines répondent-ils en HTTPS ?
|
||
for domain in sso intranet git n8n portainer code status; do
|
||
echo -n "$domain : "
|
||
curl -sk -o /dev/null -w "%{http_code}\n" "https://$domain.seizeconsulting.com"
|
||
done
|
||
# → 200 ou 302 sur chaque ligne = OK
|
||
# → 500, 502, 503 = problème
|
||
|
||
# Espace disque restant
|
||
df -h /
|
||
# → Surveiller si > 80% utilisé
|
||
```
|
||
|
||
### Logs récents
|
||
|
||
```bash
|
||
# Logs Traefik (erreurs uniquement)
|
||
sudo docker logs --tail 100 traefik 2>&1 | grep -i "error\|warn"
|
||
|
||
# Logs Zitadel (erreurs)
|
||
sudo docker logs --tail 100 zitadel-zitadel-api-1 2>&1 | grep -i "error\|level=err"
|
||
|
||
# Logs OAuth2-Proxy intranet (erreurs récentes)
|
||
sudo docker logs --tail 100 oauth2-proxy 2>&1 | grep -i "error"
|
||
```
|
||
|
||
---
|
||
|
||
## 📦 Backups
|
||
|
||
### ⚠️ État actuel : AUCUN backup automatique
|
||
|
||
À mettre en place en priorité.
|
||
|
||
### Procédure backup manuel (à exécuter avant grosse modif)
|
||
|
||
```bash
|
||
# Créer un dossier de backup daté
|
||
BACKUP_DIR=~/backups/$(date +%Y%m%d-%H%M%S)
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
# Backup Postgres (Gitea, n8n)
|
||
docker exec postgres pg_dumpall -U postgres > $BACKUP_DIR/postgres.sql
|
||
|
||
# Backup Postgres Zitadel (sa propre instance)
|
||
docker exec zitadel-postgres-1 pg_dumpall -U postgres > $BACKUP_DIR/postgres-zitadel.sql
|
||
|
||
# Backup volumes Docker (Gitea data, etc.)
|
||
sudo tar czf $BACKUP_DIR/gitea-data.tar.gz -C ~/docker/gitea data/
|
||
sudo tar czf $BACKUP_DIR/uptime-data.tar.gz -C ~/docker/uptime-kuma data/
|
||
sudo tar czf $BACKUP_DIR/portainer-data.tar.gz -C ~/docker/portainer data/
|
||
|
||
# Backup configs (.env, docker-compose.yml)
|
||
tar czf $BACKUP_DIR/configs.tar.gz -C ~/docker .
|
||
|
||
# Backup scripts furious-to-zitadel
|
||
tar czf $BACKUP_DIR/furious-scripts.tar.gz -C ~/ furious-to-zitadel/
|
||
|
||
echo "✅ Backup terminé dans $BACKUP_DIR"
|
||
ls -lh $BACKUP_DIR
|
||
```
|
||
|
||
### Procédure backup automatique (à mettre en place)
|
||
|
||
Voir [docs/09-troubleshooting.md](./docs/09-troubleshooting.md) section Backup automatisé.
|
||
|
||
---
|
||
|
||
## 🔄 Mises à jour
|
||
|
||
### Mise à jour d'un service Docker
|
||
|
||
```bash
|
||
cd ~/docker/<service>
|
||
docker compose pull
|
||
docker compose up -d
|
||
```
|
||
|
||
### Vérifier qu'une mise à jour ne casse rien
|
||
|
||
```bash
|
||
# 1. Backup avant
|
||
~/backup-manual.sh # script à créer si pas existant
|
||
|
||
# 2. Pull la nouvelle image
|
||
docker compose pull
|
||
|
||
# 3. Restart
|
||
docker compose down
|
||
docker compose up -d
|
||
|
||
# 4. Vérifier les logs
|
||
docker compose logs -f
|
||
# Ctrl+C pour quitter
|
||
|
||
# 5. Tester le service (login, fonctionnalités principales)
|
||
```
|
||
|
||
### Mises à jour critiques à surveiller
|
||
|
||
| Service | Risque | Procédure |
|
||
|---|---|---|
|
||
| Traefik | Changement breaking config | Lire le CHANGELOG avant |
|
||
| Zitadel | Schema DB peut changer | Backup obligatoire avant |
|
||
| Postgres | Migration majeure | Backup + lire migration guide |
|
||
| OAuth2-Proxy | Changement de scopes/headers | Tester en dry-run |
|
||
|
||
---
|
||
|
||
## ➕ Ajouter un nouvel outil
|
||
|
||
### Procédure standard (~1h)
|
||
|
||
#### 1. Ajouter le record DNS
|
||
|
||
Chez le registrar : créer record A `<outil>.seizeconsulting.com` → IP du serveur.
|
||
|
||
#### 2. Déployer l'outil (sans SSO)
|
||
|
||
```bash
|
||
mkdir -p ~/docker/<outil>
|
||
cd ~/docker/<outil>
|
||
|
||
# Créer docker-compose.yml
|
||
cat > docker-compose.yml << EOF
|
||
services:
|
||
<outil>:
|
||
image: <image>:<tag>
|
||
container_name: <outil>
|
||
restart: unless-stopped
|
||
networks:
|
||
- web
|
||
# PAS de labels Traefik ici → c'est OAuth2-Proxy qui sera exposé
|
||
networks:
|
||
web:
|
||
external: true
|
||
EOF
|
||
|
||
docker compose up -d
|
||
```
|
||
|
||
#### 3. Créer l'application dans Zitadel
|
||
|
||
Console Zitadel → Projects → Infra Seize → New application :
|
||
- Type : **Web**
|
||
- Authentication Method : **Basic**
|
||
- Grant Types : **Authorization Code**
|
||
- Redirect URL : `https://<outil>.seizeconsulting.com/oauth2/callback`
|
||
- Token Settings :
|
||
- Auth Token Type : **JWT**
|
||
- User roles inside ID Token : ✅
|
||
- Include user's profile info in the ID Token : ✅
|
||
- Add user roles to the access token : ✅
|
||
|
||
Récupérer : **Client ID** + **Client Secret**.
|
||
|
||
#### 4. Déployer un OAuth2-Proxy dédié
|
||
|
||
```bash
|
||
mkdir -p ~/docker/oauth2-proxy-<outil>
|
||
cd ~/docker/oauth2-proxy-<outil>
|
||
|
||
# docker-compose.yml (adapter depuis configs/oauth2-proxy/docker-compose.yml.template)
|
||
# .env (adapter depuis configs/oauth2-proxy/.env.example)
|
||
```
|
||
|
||
`.env` (variables à remplacer) :
|
||
```env
|
||
OAUTH2_PROXY_PROVIDER=oidc
|
||
OAUTH2_PROXY_CLIENT_ID=<de Zitadel>
|
||
OAUTH2_PROXY_CLIENT_SECRET=<de Zitadel>
|
||
OAUTH2_PROXY_COOKIE_SECRET=<32 chars random>
|
||
OAUTH2_PROXY_OIDC_ISSUER_URL=https://sso.seizeconsulting.com
|
||
OAUTH2_PROXY_REDIRECT_URL=https://<outil>.seizeconsulting.com/oauth2/callback
|
||
OAUTH2_PROXY_UPSTREAMS=http://<outil>:<port_interne>
|
||
OAUTH2_PROXY_SCOPE=openid email profile urn:zitadel:iam:org:project:roles
|
||
OAUTH2_PROXY_EMAIL_DOMAINS=*
|
||
OAUTH2_PROXY_COOKIE_DOMAINS=.seizeconsulting.com
|
||
OAUTH2_PROXY_COOKIE_SECURE=true
|
||
OAUTH2_PROXY_HTTP_ADDRESS=0.0.0.0:4180
|
||
OAUTH2_PROXY_REVERSE_PROXY=true
|
||
OAUTH2_PROXY_PASS_AUTHORIZATION_HEADER=true
|
||
OAUTH2_PROXY_PASS_ACCESS_TOKEN=true
|
||
OAUTH2_PROXY_SET_AUTHORIZATION_HEADER=true
|
||
OAUTH2_PROXY_SET_XAUTHREQUEST=true
|
||
OAUTH2_PROXY_WHITELIST_DOMAINS=.seizeconsulting.com
|
||
OAUTH2_PROXY_SKIP_PROVIDER_BUTTON=true
|
||
```
|
||
|
||
`chmod 600 .env` + `docker compose up -d`.
|
||
|
||
#### 5. Ajouter une carte sur l'intranet
|
||
|
||
Éditer `~/docker/intranet/index.html` et ajouter une nouvelle carte dans la section `<a class="service-card">` :
|
||
|
||
```html
|
||
<a class="service-card" data-app="<outil>" data-color="<color>" href="https://<outil>.seizeconsulting.com" target="_blank" rel="noopener">
|
||
<div class="card-header">
|
||
<div class="card-icon"><!-- SVG icon --></div>
|
||
<div class="card-arrow"><!-- SVG arrow --></div>
|
||
</div>
|
||
<div class="card-body">
|
||
<div class="card-title"><Nom de l'outil></div>
|
||
<div class="card-desc">Description courte</div>
|
||
<div class="card-meta">
|
||
<span class="card-url"><outil>.seizeconsulting.com</span>
|
||
<span class="card-tag">Catégorie</span>
|
||
</div>
|
||
</div>
|
||
</a>
|
||
```
|
||
|
||
#### 6. Mettre à jour la matrice RBAC dans le JavaScript
|
||
|
||
Éditer le `<script>` RBAC dans `index.html` :
|
||
|
||
```javascript
|
||
const ACCESS_MATRIX = {
|
||
"portainer": ["direction", "manager"],
|
||
"status": ["direction"],
|
||
// ...
|
||
"<outil>": ["direction", "manager"], // ← Ajouter ta nouvelle ligne
|
||
};
|
||
```
|
||
|
||
#### 7. Restart de l'intranet
|
||
|
||
```bash
|
||
cd ~/docker/intranet
|
||
docker compose down
|
||
docker compose up -d
|
||
```
|
||
|
||
#### 8. Tester
|
||
|
||
Se logger en incognito avec un user ayant accès → vérifier que la carte s'affiche et que le clic mène à l'outil avec SSO.
|
||
|
||
---
|
||
|
||
## 🗑️ Retirer un outil
|
||
|
||
### Procédure inverse de l'ajout
|
||
|
||
```bash
|
||
# 1. Arrêter l'outil et son OAuth2-Proxy
|
||
cd ~/docker/<outil>
|
||
docker compose down
|
||
|
||
cd ~/docker/oauth2-proxy-<outil>
|
||
docker compose down
|
||
|
||
# 2. Archiver les configs (au cas où)
|
||
mv ~/docker/<outil> ~/docker/<outil>.archived-$(date +%Y%m%d)
|
||
mv ~/docker/oauth2-proxy-<outil> ~/docker/oauth2-proxy-<outil>.archived-$(date +%Y%m%d)
|
||
|
||
# 3. Supprimer l'application dans Zitadel
|
||
# Console → Projects → Infra Seize → Applications → <outil> → Delete
|
||
|
||
# 4. Retirer la carte sur l'intranet (HTML + matrice RBAC)
|
||
# Éditer ~/docker/intranet/index.html
|
||
# Restart : docker compose restart intranet
|
||
|
||
# 5. Optionnel : retirer le record DNS chez le registrar
|
||
```
|
||
|
||
---
|
||
|
||
## 👥 Gestion des utilisateurs
|
||
|
||
### Ajouter un nouveau user manuellement
|
||
|
||
Quand un nouveau collaborateur arrive et n'est pas encore dans Furious :
|
||
|
||
```
|
||
Console Zitadel → Users → New → Human user :
|
||
- Email : prenom.nom@seizeconsulting.com
|
||
- Username : <trigramme> (ex: ABC)
|
||
- Prénom, Nom
|
||
- Cocher : Email verified, Password change required
|
||
- Generate password : oui (mdp temporaire 16 chars)
|
||
```
|
||
|
||
⚠️ **Distribuer le mdp via Teams privé** au nouveau collaborateur.
|
||
|
||
### Désactiver un user (départ)
|
||
|
||
```
|
||
Console Zitadel → Users → <user> → Actions → Deactivate
|
||
```
|
||
|
||
⚠️ **Ne PAS supprimer** le user : ses traces dans les outils (commits Gitea, workflows n8n, etc.) seraient orphelines. Désactiver suffit.
|
||
|
||
### Changer le rôle d'un user
|
||
|
||
#### Méthode UI (1 user)
|
||
|
||
```
|
||
Console Zitadel → Users → <user> → Authorizations → Edit roles
|
||
```
|
||
|
||
#### Méthode script (plusieurs users)
|
||
|
||
1. Mettre à jour le mapping dans `assign-roles.py` (variable `JOB_TITLE_TO_ROLE`)
|
||
2. Lancer :
|
||
```bash
|
||
cd ~/furious-to-zitadel
|
||
source venv/bin/activate
|
||
python3 assign-roles.py
|
||
```
|
||
|
||
⚠️ Le script **ajoute** les rôles, il ne **retire pas** les anciens. Pour retirer, utiliser l'UI ou un script custom.
|
||
|
||
### Synchronisation périodique avec Furious
|
||
|
||
Workflow recommandé (à mettre en place) :
|
||
|
||
1. **Tous les jours** : un cron exécute `read-all-users.sh` pour récupérer les users Furious
|
||
2. **Compare** avec les users Zitadel actuels
|
||
3. **Pour chaque diff** :
|
||
- Nouveau dans Furious → créer dans Zitadel
|
||
- Départ détecté dans Furious (`departure_date != "0000-00-00"`) → désactiver dans Zitadel
|
||
- Changement de `job_title` → réattribuer le rôle
|
||
|
||
⚠️ **Pas encore automatisé**. À mettre en place via n8n.
|
||
|
||
---
|
||
|
||
## 🔐 Rotation des secrets
|
||
|
||
### Quand rotater ?
|
||
|
||
- 🔴 **Immédiatement** : si secret exposé (dans un commit Git, conversation IA, etc.)
|
||
- 🟡 **Tous les 6 mois** : pratique de bonne hygiène
|
||
- 🟢 **Tous les ans** : pour les secrets très internes (postgres root, etc.)
|
||
|
||
### Procédure pour un secret OAuth2-Proxy (Client Secret Zitadel)
|
||
|
||
```bash
|
||
# 1. Aller dans Zitadel : Projects → Infra Seize → Applications → <outil>
|
||
# 2. Cliquer "Generate Client Secret" → copier le nouveau secret
|
||
# 3. Mettre à jour le .env d'OAuth2-Proxy
|
||
|
||
cd ~/docker/oauth2-proxy-<outil>
|
||
# Éditer .env, remplacer OAUTH2_PROXY_CLIENT_SECRET
|
||
# Sauvegarder dans le gestionnaire de mots de passe
|
||
|
||
# 4. Restart OAuth2-Proxy
|
||
docker compose down
|
||
docker compose up -d
|
||
```
|
||
|
||
### Procédure pour la clé service account Zitadel
|
||
|
||
```bash
|
||
# 1. Console Zitadel → Users → furious-import-service → Keys
|
||
# 2. Supprimer l'ancienne clé (et l'invalider)
|
||
# 3. Créer une nouvelle clé (Type : JSON)
|
||
# 4. Télécharger la nouvelle clé immédiatement
|
||
|
||
# 5. Remplacer sur le serveur
|
||
scp <nouvelle_cle>.json admin@<serveur>:~/furious-to-zitadel/zitadelfuriousimportkey.json
|
||
ssh admin@<serveur>
|
||
chmod 600 ~/furious-to-zitadel/zitadelfuriousimportkey.json
|
||
|
||
# 6. Tester les scripts
|
||
cd ~/furious-to-zitadel
|
||
source venv/bin/activate
|
||
python3 assign-roles.py # Doit fonctionner avec la nouvelle clé
|
||
```
|
||
|
||
### Procédure pour Postgres (Gitea/n8n)
|
||
|
||
⚠️ **À faire HORS heures de bureau** car les services s'arrêteront temporairement.
|
||
|
||
```bash
|
||
# 1. Générer un nouveau mdp
|
||
NEW_PWD=$(openssl rand -base64 32 | tr -d '+/=' | head -c 32)
|
||
echo "Nouveau mdp : $NEW_PWD"
|
||
# → Sauvegarder dans le gestionnaire de mots de passe
|
||
|
||
# 2. Changer le mdp dans Postgres
|
||
docker exec -it postgres psql -U postgres -c "ALTER USER gitea WITH PASSWORD '$NEW_PWD';"
|
||
|
||
# 3. Mettre à jour le .env de Gitea
|
||
nano ~/docker/gitea/.env
|
||
# Remplacer GITEA_DB_PASSWORD=$NEW_PWD
|
||
|
||
# 4. Restart Gitea
|
||
cd ~/docker/gitea
|
||
docker compose down
|
||
docker compose up -d
|
||
|
||
# 5. Tester Gitea
|
||
curl -sI https://git.seizeconsulting.com # Doit retourner 200 ou 302
|
||
```
|
||
|
||
---
|
||
|
||
## 🐛 Troubleshooting commun
|
||
|
||
Voir [docs/09-troubleshooting.md](./docs/09-troubleshooting.md) pour une liste exhaustive.
|
||
|
||
### "Mon SSO ne fonctionne plus, l'user est redirigé en boucle"
|
||
|
||
→ Probablement le bug Traefik authRequestHeaders=Cookie. Vérifier que `~/docker/traefik/dynamic.yml` contient bien `Cookie` dans `authRequestHeaders` du middleware ForwardAuth.
|
||
|
||
### "Le certificat Let's Encrypt a expiré"
|
||
|
||
→ Traefik renouvelle automatiquement. Si pas le cas :
|
||
```bash
|
||
# Vérifier les logs Traefik
|
||
sudo docker logs traefik 2>&1 | grep -i "letsencrypt\|certificate"
|
||
|
||
# Forcer le renouvellement
|
||
cd ~/docker/traefik
|
||
docker compose down
|
||
docker compose up -d
|
||
```
|
||
|
||
### "Le script Python d'import échoue avec un 401 Unauthorized"
|
||
|
||
→ Le token Zitadel a expiré (1h) OU les droits du service account ont été révoqués.
|
||
|
||
```bash
|
||
# Vérifier que la clé JSON est valide
|
||
python3 -c "import json; data=json.load(open('zitadelfuriousimportkey.json')); print('UserId:', data.get('userId'), 'KeyId:', data.get('keyId'))"
|
||
|
||
# Vérifier dans Zitadel Console que le service account a toujours IAM_USER_MANAGER
|
||
```
|
||
|
||
### "Un user ne peut pas se logger après avoir été créé"
|
||
|
||
→ Vérifier :
|
||
1. `Email verified` cocher dans son profil Zitadel
|
||
2. Si "Only authorized users can authenticate" est activé sur le project → il doit avoir un rôle
|
||
3. MFA pas mal configuré → faire un reset MFA si bloqué
|
||
|
||
---
|
||
|
||
## 📊 Monitoring
|
||
|
||
### Métriques à surveiller
|
||
|
||
| Métrique | Outil | Seuil d'alerte |
|
||
|---|---|---|
|
||
| Disponibilité des sous-domaines | Uptime Kuma | Down > 5 min |
|
||
| Taux d'erreur HTTP (5xx) | Logs Traefik | > 1% sur 5 min |
|
||
| Espace disque | `df -h` | > 80% |
|
||
| RAM utilisée | `free -h` | > 90% |
|
||
| CPU load | `uptime` | > 4 (sur 4 vCPU) |
|
||
| Tentatives de login échouées | Logs Zitadel | > 100/heure (potentielle attaque) |
|
||
|
||
### Mettre en place le monitoring
|
||
|
||
Uptime Kuma est déjà déployé. Ajouter des moniteurs pour :
|
||
- Chaque sous-domaine (HTTP check)
|
||
- Le serveur lui-même (ping)
|
||
- L'API Furious (HTTP check)
|
||
|
||
---
|
||
|
||
## 📞 Escalation
|
||
|
||
### Quand appeler Philippe ?
|
||
|
||
- 🔴 Service critique down (Zitadel, Gitea, intranet) > 1h
|
||
- 🔴 Faille sécurité avérée
|
||
- 🔴 Perte de données
|
||
|
||
### Quand appeler le support Scaleway ?
|
||
|
||
- 🔴 Serveur inaccessible (panne hardware)
|
||
- 🔴 Problème réseau Scaleway
|
||
|
||
### Quand appeler le support Furious ?
|
||
|
||
- 🟡 API Furious down ou très lente
|
||
- 🟡 Permissions API qui ne fonctionnent pas
|
||
|
||
---
|
||
|
||
## 📝 Checklist hebdomadaire (5-10 min)
|
||
|
||
- [ ] Vérifier tous les conteneurs Up
|
||
- [ ] Vérifier l'espace disque < 80%
|
||
- [ ] Lire les alertes Uptime Kuma
|
||
- [ ] Vérifier les logs Traefik pour erreurs récurrentes
|
||
- [ ] Backup manuel des données critiques (si pas encore automatisé)
|
||
- [ ] Vérifier les certificats Let's Encrypt (expire dans > 7 jours)
|
||
|
||
## 📝 Checklist mensuelle (30 min)
|
||
|
||
- [ ] Faire un Docker prune des images inutilisées : `docker image prune -a`
|
||
- [ ] Vérifier les mises à jour disponibles : `apt list --upgradable`
|
||
- [ ] Auditer les users Zitadel (départs non synchronisés ?)
|
||
- [ ] Vérifier que les scripts Python fonctionnent toujours
|
||
- [ ] Lire les logs sécurité (tentatives de login échouées, etc.)
|