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ément | Valeur |
|---|---|
| Script | /usr/local/bin/op_ad_sync.py sur le serveur OpenProject (VM 101, 10.194.24.48, compte setup) |
| Fréquence | toutes 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 source | rôle Ansible op_ad_sync du dépôt infra/infra |
| Alertes | canal Teams IT Alerts |
Ce que fait le script
- 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. - 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éé.
- 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.
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 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.
| Variable | Rôle |
|---|---|
LDAP_HOST, LDAP_PORT | Contrôleur de domaine, en LDAPS (port 636) |
LDAP_BIND_DN, LDAP_BIND_PASSWORD | Compte de lecture de l'AD |
LDAP_CA_FILE | Certificat de l'autorité du domaine, pour vérifier le LDAPS (facultatif) |
LDAP_GROUP_BASE, LDAP_USER_BASE | Où chercher les groupes et les comptes |
GROUP_FILTER | Groupes concernés (par défaut GG_*) |
OP_URL | https://project.formuleets.ca, le nom officiel d'OpenProject |
OP_API_KEY | Clé d'API d'un compte admin OpenProject |
ALERT_WEBHOOK_URL | Adresse du flux Teams (facultatif) |
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.
- Modifie
ansible/roles/op_ad_sync/files/op_ad_sync.pydans une branche, puis ouvre une merge request. Le pipeline vérifie le code Ansible. - Après la fusion, copie le dossier
ansibledu dépôt sur le serveur OpenProject, puis :ansible-playbook playbooks/op-ad-sync.yml -e ansible_connection=local -K-Kdemande le mot de passesudodu comptesetup. Le récapitulatif doit afficherfailed=0.
Problèmes connus
| Symptôme | Cause | Solution |
|---|---|---|
HTTP 400 : Invalid host_name configuration | OP_URL pointe vers l'IP ou localhost : OpenProject n'accepte que son nom officiel | OP_URL=https://project.formuleets.ca |
| Un membre n'apparaît pas dans son groupe | Il ne s'est jamais connecté à OpenProject, ou son login OpenProject diffère de son identifiant AD | Le faire se connecter une fois ; sinon, corriger son login dans OpenProject |
| Un membre perd un droit donné à la main | L'ajout n'était pas dans l'AD | L'ajouter au groupe dans l'AD |
Aucun groupe trouvé dans l'AD | AD injoignable ou base de recherche erronée | Vérifier LDAP_HOST et LDAP_GROUP_BASE |
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.