Aller au contenu principal

Synchro des groupes AD vers OpenProject

Les droits dans OpenProject passent par des groupes (GG_Lead, GG_Software…, voir Administration). Ces groupes sont recopiés depuis l'Active Directory toutes les 15 minutes par un script. Pour donner ou retirer un droit, on change le groupe dans l'AD, jamais dans OpenProject.

ÉlémentValeur
Script/usr/local/bin/op_ad_sync.py sur le serveur OpenProject (VM 101, 10.194.24.48, compte setup)
Fréquencetoutes les 15 minutes (/etc/cron.d/op-ad-sync)
Journal/var/log/op-ad-sync.log, archivé chaque semaine (8 semaines gardées)
Configuration et secrets/etc/op-ad-sync.env, lisible par root seulement
Code sourcerôle Ansible op_ad_sync du dépôt infra/infra
Alertescanal Teams IT Alerts

Ce que fait le script​

  1. Il lit dans l'AD tous les groupes GG_* et leurs membres actifs, groupes imbriqués compris. Les comptes désactivés sont ignorés.
  2. Pour chaque groupe, il aligne exactement le groupe du même nom dans OpenProject : il ajoute les membres manquants et retire ceux qui ne sont plus dans l'AD. Un groupe qui n'existe pas encore dans OpenProject est créé.
  3. Les comptes sont rapprochés par l'identifiant : le nom d'ouverture de session de l'AD (sAMAccountName) doit être identique au login OpenProject.

Le script ne supprime jamais de groupe, et ne touche qu'aux groupes OpenProject qui portent le nom d'un groupe de l'AD. Si l'AD ne renvoie aucun groupe (AD injoignable, mauvaise configuration), il s'arrête au lieu de vider les groupes.

L'AD est la référence

Un membre ajouté à la main dans un groupe OpenProject est retiré au passage suivant s'il n'est pas dans le groupe de l'AD. Pour un changement durable, modifie le groupe dans Utilisateurs et ordinateurs Active Directory.

Un nouveau membre doit se connecter une fois

Un compte AD qui ne s'est jamais connecté à OpenProject n'y existe pas encore : il ne peut pas être ajouté à ses groupes. Il les reçoit au premier passage du script qui suit sa première connexion.

Les alertes Teams​

Le script poste dans le canal IT Alerts (équipe IT Alerts) :

  • 🔴 au premier échec, avec la raison ;
  • 🟢 au premier passage réussi après une panne.

Il n'y a qu'un message par panne, pas un toutes les 15 minutes. Le script mémorise la panne dans /var/lib/op-ad-sync/en-echec. Aucun message n'est envoyé en mode simulation.

Les alertes passent par un flux de travail Teams (modèle « Envoyer des alertes webhook à un canal »). Son adresse est dans ALERT_WEBHOOK_URL, dans le fichier de configuration. Sans cette variable, le script fonctionne sans alertes.

Pour vérifier que les alertes arrivent, sur le serveur OpenProject :

sudo python3 -c "import sys; sys.path.insert(0, '/usr/local/bin'); import op_ad_sync as m; m.load_env_file('/etc/op-ad-sync.env'); m.notify('🧪 Test des alertes IT', 'Message de test, à ignorer.')"

Vérifier ou forcer une synchro​

Sur le serveur OpenProject :

# Simulation : affiche les ajouts et retraits prévus, sans rien modifier
sudo /usr/local/bin/op_ad_sync.py --env /etc/op-ad-sync.env --dry-run -v

# Synchro immédiate, sans attendre le prochain quart d'heure
sudo /usr/local/bin/op_ad_sync.py --env /etc/op-ad-sync.env

# Derniers passages
grep -E "trouvé|utilisateur|AJOUT|RETRAIT|CRÉATION|ERROR" /var/log/op-ad-sync.log | tail -20

En mode détaillé (-v), le journal liste aussi les membres de l'AD qui ne se sont pas encore connectés à OpenProject.

La configuration​

Le fichier /etc/op-ad-sync.env contient des lignes CLÉ=valeur. Il n'est pas dans le dépôt, à cause des secrets.

VariableRôle
LDAP_HOST, LDAP_PORTContrôleur de domaine, en LDAPS (port 636)
LDAP_BIND_DN, LDAP_BIND_PASSWORDCompte de lecture de l'AD
LDAP_CA_FILECertificat de l'autorité du domaine, pour vérifier le LDAPS (facultatif)
LDAP_GROUP_BASE, LDAP_USER_BASEOù chercher les groupes et les comptes
GROUP_FILTERGroupes concernés (par défaut GG_*)
OP_URLhttps://project.formuleets.ca, le nom officiel d'OpenProject
OP_API_KEYClé d'API d'un compte admin OpenProject
ALERT_WEBHOOK_URLAdresse du flux Teams (facultatif)
À compléter

L'emplacement dans Vaultwarden du mot de passe du compte de lecture LDAP, de la clé d'API OpenProject et de l'adresse du flux Teams.

Modifier le script​

Le script n'est plus modifié directement sur le serveur : on le change dans le dépôt, puis on le déploie avec Ansible.

  1. Modifie ansible/roles/op_ad_sync/files/op_ad_sync.py dans une branche, puis ouvre une merge request. Le pipeline vérifie le code Ansible.
  2. Après la fusion, copie le dossier ansible du dépôt sur le serveur OpenProject, puis :
    ansible-playbook playbooks/op-ad-sync.yml -e ansible_connection=local -K
    -K demande le mot de passe sudo du compte setup. Le récapitulatif doit afficher failed=0.

Problèmes connus​

SymptômeCauseSolution
HTTP 400 : Invalid host_name configurationOP_URL pointe vers l'IP ou localhost : OpenProject n'accepte que son nom officielOP_URL=https://project.formuleets.ca
Un membre n'apparaît pas dans son groupeIl ne s'est jamais connecté à OpenProject, ou son login OpenProject diffère de son identifiant ADLe faire se connecter une fois ; sinon, corriger son login dans OpenProject
Un membre perd un droit donné à la mainL'ajout n'était pas dans l'ADL'ajouter au groupe dans l'AD
Aucun groupe trouvé dans l'ADAD injoignable ou base de recherche erronéeVérifier LDAP_HOST et LDAP_GROUP_BASE
Panne du 2 au 10 novembre 2026

Après le passage d'OpenProject derrière Caddy, le script appelait encore OpenProject par son IP et échouait à chaque passage, sans que personne le voie. Les groupes n'ont pas été mis à jour pendant 8 jours. C'est ce qui a motivé les alertes Teams.