seize-infra-doc/OPERATIONS.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

14 KiB
Raw Permalink Blame History

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

# 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

# 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)

# 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 section Backup automatisé.


🔄 Mises à jour

Mise à jour d'un service Docker

cd ~/docker/<service>
docker compose pull
docker compose up -d

Vérifier qu'une mise à jour ne casse rien

# 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)

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é

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) :

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"> :

<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 :

const ACCESS_MATRIX = {
  "portainer": ["direction", "manager"],
  "status":    ["direction"],
  // ...
  "<outil>":   ["direction", "manager"],  // ← Ajouter ta nouvelle ligne
};

7. Restart de l'intranet

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

# 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 :
    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)

# 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

# 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.

# 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 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 :

# 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.

# 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.)