Quand on commence à avoir un certain nombre d’applications et donc, un certain nombre de bases utilisateur, cela devient vite compliqué à la fois pour l’administration, mais également pour les utilisateurs (plusieurs logins, mots de passe, etc..).
Il est donc temps de se poser la question de la centralisation de ses utilisateurs dans un seul référentiel. On pourrait très bien se service d’une base SQL, mais il existe un autre type de service bien plus adapté à ce genre d’usage : OpenLDAP, un annuaire LDAP (Lightweight Directory Access Protocol), dérivé des vénérables annuaires X500.
Table des matières
C – BaseDn, Filtres, Attributs
2 – Droits d’accès à la configuration du serveur
1 – Déplacement d’un utilisateur
1 – Renommage d’un utilisateur
1 – Suppression d’un utilisateur
C – Création utilisateur réplication
III – Réplication de la configuration
II – Configuration simple : une IP virtuelle
III – Et avec du loadbalancing ?
L’idée est de faire en sorte qu’un utilisateur puisse se connecter avec un login/mdp et qu’en fonction d’appartenance à des groupes, de présence d’attributs, etc.. il ait l’accès ou non aux applications, services, etc…
Je parlais un peu avant de la possibilité de faire cela avec un serveur SQL. Cependant, effectuer l’authentification en passant par le LDAP offre un avantage non négligeable : la rapidité. En effet, la particularité d’un ldap par rapport à un SGBD est l’optimisation pour la lecture. Une requête sera traité bien plus rapidement par LDAP que par MYSQL.
Dans un environnement avec de nombreuses authentifications concomitantes la différence peut se faire sentir en terme de charge. Et pour terminer avec les avantages du LDAP pour l’authentification, c’est que cela s’intégrera parfaitement dans un futur contexte AAA (Authentication, Authorization, Accounting).
Je ne vais pas faire un cours magistral sur le protocole LDAP (on trouve de nombreuses doc sur la toile), retenez simplement que c’est donc très pratique mais pas forcement simple à prendre en main.
Ce qu’il faut savoir :
Les informations sont stockées dans une structure en arborescence (différent en ce point par exemple d’un SGBD qui stocke les informations de manière relationnelle.
Avec OpenLDAP vous avez la liberté de définir complètement l’arborescence vous-même. On l’appelle « Directory Information Tree » (DIT).
Dans la grande majorité des articles sur OpenLDAP, on trouve la classique arborescence avec les OU People et Group.
Dans notre exemple, nous allons faire un peu plus complexe en prévision du futur.Nous allons commencer par un nœud racine dc=debugo,dc=fr contenant trois nœuds sous la racine:
ou=group,dc=debugo,dc=fr : elle contiendra elle même deux OU :
•.ou=sysgroup,ou=group,dc=debugo,dc=fr qui contiendra les groupes systèmes (groupe d’accès à des applications).
•.ou=workgroup,ou=group,dc=debugo,dc=fr qui contiendra les groupes de travail en fonction de mes clients (par ex un groupe par client pour le partage via le cloud ou FTP (articles à venir).
ou=people,dc=debugo,dc=fr : deux sous OU la aussi :
•.ou=debugo,ou=people,dc=debugo,dc=fr pour les comptes utilisateurs privés.
•.ou=client,ou=people,dc=debugo,dc=fr pour les comptes de mes clients.
ou=system,dc=debugo,dc=fr : OU qui contiendra les comptes systèmes permettant de lire les mots de passe des utilisateurs ldap.
Une chose à savoir, à partir de la version 2.3, la façon de configurer OpenLDAP a changé : on passe d’une configuration dans un fichier (slapd.conf) à une configuration elle même dans une base LDAP (dans l’arbre cn=config).L’avantage est conséquent : il est possible de modifier la configuration sans arrêter et redémarrer le service (ce qui dans le cas d’un gros annuaire peut être très long).
Pour se faire, nous mettrons nos différents paramétrages dans des fichiers ldif, que nous injecterons dans le serveur, sans le couper, et ce, dans le but de modifier sa configuration à chaud.
Bref, voila pour la présentation de cette série de tutoriels.
Classique, une mise à jour et on installe le paquet slapd et le paquet ldap-utils contenant les outils pour modifier le ldap
# apt-get update && apt-get upgrade
# apt-get install slapd ldap-utils
Cependant, la configuration par défaut du paquet n’est peut être pas celle que vous voulez (elle se base sur le FQDN de la machine), bref, pour être sur :
La, vous répondez comme cela :
Omit OpenLDAP server configuration? No
DNS domain name: debugo.fr
Organization name? Debugo
Administrator password: PASSWORD
Confirm password: PASSWORD
Database backend to use: MDB
Do you want the database to be removed when slapd is purged? YES
Allow LDAPv2 protocol? No
Ensuite, un petit tour dans le fichier /etc/ldap/ldap.conf pour le configurer comme il faut (utilisé par les outils ldap pour modifier le LDAP en ligne de commande) :
BASE dc=debugo,dc=fr
URI ldap://IP.MACHINE/
On test avec :
# ldapsearch -xLLL
ou bien
# ldapsearch -Y external -H ldapi:/// -b dc=debugo,dc=fr -LLL
Ce qui doit retourner quelque chose comme :
dn: dc=debugo,dc=fr
objectClass: top
objectClass: dcObject
objectClass: organization
o: debugo
dc: debugo
dn: cn=admin,dc=debugo,dc=fr
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: admin
description: LDAP administrator
Youpi ! On peut continuer.
Pour avoir d’autres informations sur le serveur, vous pouvez utiliser les commandes suivantes :
# slapd -V
# ldapsearch -Y external -H ldapi:/// -b cn=config "(objectClass=olcGlobal)" -LLL
-LLL : Permet de ne pas afficher certains informations superflues dans la sortie (testez avec et sans pour voir la différence …)
Comme je l’expliquais dans l’introduction de cette série de tutoriels, la configuration n’est plus dans un fichier unique, mais sous forme de DIT (cn=config). On peut en avoir un aperçu avec la commande
# tree /etc/ldap/slapd.d/
/etc/ldap/slapd.d/
|-- cn=config
| |-- cn=module{0}.ldif
| |-- cn=schema
| | |-- cn={0}core.ldif
| | |-- cn={1}cosine.ldif
| | |-- cn={2}nis.ldif
| | `-- cn={3}inetorgperson.ldif
| |-- cn=schema.ldif
| |-- olcBackend={0}mdb.ldif
| |-- olcDatabase={-1}frontend.ldif
| |-- olcDatabase={0}config.ldif
| `-- olcDatabase={1}mdb.ldif
`-- cn=config.ldif
Si la commande tree n’existe pas :
# apt-get install tree
A vrai dire, on peut encore configurer en passant par le fichier slapd.conf mais cela requiert un redémarrage du serveur à chaque modification. De plus, cette méthode n’est pas recommandée.
Si vous regardez le résultat de la commande :
# tree /etc/ldap/slapd.d/
Vous voyez plusieurs entrées sous la branche cn=schema. En l’occurrence, core, cosine, nis et inetorgperson.
Ce sont en quelque sorte les modèles qu’utiliseront vos futurs enregistrement (quel attribut, de quel type, etc..). Ceux déjà intégrés sont les plus couramment utilisés, mais il en existe d’autres, soit déjà disponibles dans /etc/ldap/schema :
# ls /etc/ldap/schema/*.ldif
Soit disponibles sur Internet.
Il est aussi tout à fait possible de créer vos propres schémas, afin que votre annuaire réponde précisément à vos besoins.
Pour modifier la configuration du serveur nous utiliserons principalement les commandes ldapadd, ldapmodify, ldapdelete (installées avec le paquet ldap-utils) Ces dernières prennent en option un fichier (option -f) de format ldif (Ldap Data Interchange Format).
Nous allons rapidement voir de quoi il s’agit.
Pour effectuer des requêtes, nous utiliserons la commande ldapsearch.
Celle ci peut interroger le serveur LDAP de plusieurs façons.
Sur le socket interne :
# ldapsearch -Q -Y external -H ldapi:/// -b cn=config
L’option -Q cache les infos SASL, inutile à l’affichage.
Ou sur un socket réseau :
# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -W -b cn=config
Sur le socket réseau, nous indiquons les options :
-x : authentification simple.
-H indique l’hôte (en l’occurrence, localhost).
-D est le compte qui va se connecter.
-W sert à demander le mot de passe.
-b ou basedn est l’endroit ou nous voulons faire notre recherche.
La commande fonctionne mais ne retourne rien. Le compte admin n’a pas accès à la configuration en passant par le socket réseau (nous allons y remédier après).
Au passage, pourquoi donc s’embêter alors qu’on ne pourrait qu’utiliser le socket interne ?
L’intérêt du socket réseau est qu’on peut lancer les commandes à distance (dans ce cas remplacer localhost par le nom de la machine distante).
Je reviens sur la commande :
# ldapsearch -Q -LLL -Y external -H ldapi:/// -b cn=config
Celle ci affiche donc l’intégralité de l’arbre cn=config (le baseDN de notre requête).
Au passage, on peut l’écrire sous la forme :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config"
Si l’on veut n’afficher que les attributs dn des résultats, on fera alors :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" dn
Si par exemple, je veux afficher d’autres attributs :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcModuleList)" dn olcModuleLoad
Dans la commande précédente, j’utilise un filtre. Pour les utiliser, il suffit de les indiquer après l’option -b et avant ce que l’on demande par ex :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "(&(objectClass=olcDatabaseConfig))" dn
Cette commande n’affichera que les attributs dn des objectClass olcDatabaseConfig. Le & est facultatif. J’aurais très bien pu mettre :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "(objectClass=olcDatabaseConfig)" dn
Si l’on ne veut pas que les attributs dn, mais toutes les infos :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "(&(objectClass=olcDatabaseConfig))"
Et si je voulais les attributs dn des objectClass étant des olcDatabaseConfig ou ceux étant des olcModuleList, je vais utiliser le | pour indiquer un OU (le ET étant spécifié par &)
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "(|(objectClass=olcDatabaseConfig)(objectClass=olcModuleList))" dn
Petite explication sur l’utilisation des filtres. Ceux ci utilisent un principe qui rappelle la notation polonaise inversée, l’opérateur étant ici devant.
Exemple :
Si je veux A et B :
( & (A) (B) )
Si je veux A ou B
( | (A) (B) )
Si je veux A et B ou A et C :
( | ( & (A) (B) ) ( & (A) (C) ) )
ou, en simplifiant :
( & (A) ( | (B) (C) ))
On peut aussi inverser avec le !.
Si l’on veut par ex ce qui est A et ce qui n’est pas B :
( & (A) (! B) )
Au niveau des filtres, nous pouvons utiliser les opérateurs suivants :
•.< : plus petit que
•.<= : plus petit ou égal
•.= : égal
•.> : plus grand
•.>= : plus grand ou égal
•.=* : présence de (retourne les entrées ou l’attribut est présent)
•.~= : approximation ( par ex, ~=Nocolas pourra retourner Nicolas)
On peut utiliser un joker, par ex, = *toto* sortira tout ce qui contient toto comme sous chaîne.
Il existe également la notion de filtres étendus, utilisé ainsi : attribut:dn:=valeur.
Par ex :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -w password -b "dc=debugo,dc=fr" ou=people dn
me donne :
dn: ou=people,dc=debugo,dc=fr
Et :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -w password -b "dc=debugo,dc=fr" ou:dn:=people dn
me donne :
dn: ou=people,dc=debugo,dc=fr
dn: ou=client,ou=people,dc=debugo,dc=fr
dn: ou=debugo,ou=people,dc=debugo,dc=fr
dn: uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr
dn: uid=ldap1,ou=debugo,ou=people,dc=debugo,dc=fr
dn: uid=ldap2,ou=debugo,ou=people,dc=debugo,dc=fr
Ils permettent donc de considérer les éléments du DN comme faisant partie de l’entrée elle même.
On peut également utiliser les filtres étendus pour modifier les opérateurs.
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -w password -b "dc=debugo,dc=fr" title:2.5.13.5:=Admin dn
ne me sortira que les entrées ou l’attribut title est égal à Admin (et non pas admin, ADMIN, etc…). Par défaut, l’opération n’est pas sensible à la casse.
Pour connaitre l’ensemble des matchingRules disponibles :
# ldapsearch -xLLL -D cn=admin,dc=debugo,dc=fr -w password -b "cn=subschema" -s base matchingRuleUse | grep "matchingRule" | cut -d ' ' -f3,5
Nous allons créer un répertoire /root/ldap/conf qui va centraliser tous nos fichiers de configuration :
# cd
# mkdir ldap
# cd ldap
# mkdir conf
# cd conf
Afin d’éviter d’avoir à toujours retaper le mot de passe admin (mot de passe que nous avons créé lors de la configuration du paquet) lors des commandes, nous allons l’enregistrer dans un fichier.
On va créer un fichier /root/pwdldap et mettre le mot de passe dedans :
# echo -n "mdpadmin" > /root/pwdldap
# chmod 600 /root/pwdldap
On test :
# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b dc=debugo,dc=fr
Par défaut, l’accès à la configuration n’est pas possible en passant par le socket réseau avec le compte admin :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b cn=config
nous donne :
No such object (32)
Créez le fichier LDIF /root/ldap/conf/acces-conf-admin.ldif, et insérez :
dn: olcDatabase={0}config,cn=config
changeType: modify
add: olcAccess
olcAccess: to * by dn.exact=cn=admin,dc=debugo,dc=fr manage by * break
Injectez :
# ldapmodify -Y external -H ldapi:/// -f acces-conf-admin.ldif
Et restestez :
# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b dc=debugo,dc=fr
Par défaut, OpenLdap ne cause pas beaucoup. On va changer cela.
On extrait la configuration actuelle dans un fichier :
# ldapsearch -Y external -H ldapi:/// -b cn=config "(objectClass=olcGlobal)" olcLogLevel -LLL > log.ldif
Avant de continuer, jetez un œil à ce fichier :
dn: cn=config
olcLogLevel: none
Explications :
La première ligne, DN est ce qu’on appelle le distinguished name, autrement dit, identifiant unique de l’entrée. La deuxième ligne contient l’attribut demandée lors de la requête (olcLogLevel), de valeur none. Vous comprendrez donc facilement que les logs sont, par défaut, désactivés.
On va modifier le fichier de la sorte :
dn: cn=config
changetype: modify
replace: olcLogLevel
olcLogLevel: 256
Pour information, les différents niveau de log sont :
-1 : enable all debugging
0 : no debugging
1 : trace function calls
2 : debug packet handling
4 : heavy trace debugging
8 : connection management
16 : print out packets sent and received
32 : search filter processing
64 : configuration file processing
128 : access control list processing
256 : stats log connections/operations/results
512 : stats log entries sent
1024 : print communication with shell backends
2048 : print entry parsing debugging
On injecte :
# ldapmodify -Y EXTERNAL -H ldapi:/// -f log.ldif
On regarde le résultat :
# ldapsearch -Y external -H ldapi:/// -b cn=config "(objectClass=olcGlobal)" olcLogLevel
Éditez le fichier /etc/rsyslog.conf et ajoutez à la fin :
LOCAL4.* -/var/log/slapd.log
Il faut redémarrer rsyslog :
service rsyslog restart
Lancez une requête et consulter le contenu du fichier /var/log/slapd.log:
ldapsearch -Y external -H ldapi:/// -b dc=debugo,dc=fr
tail /var/log/slapd.log
Normalement, on doit avoir un contenu assez significatif de ce qui a été exécuté par le serveur OpenLDAP.
Voila qui termine cette première partie de la série. Dans la suite, nous allons continuer la configuration de notre serveur en lui ajoutant des Overlays.
Les overlays sont des fonctionnalités supplémentaires qui se rajoutent. Ils en existent un certain nombre. La liste est non exhaustive, je n’ai mis que les plus « importants ».
•.accesslog : Enregistrement des accès. Attention, réduit drastiquement les performances.
•.auditlog : Enregistrement des modifications.
•.chain : Liaison de plusieurs serveurs LDAP au niveau des recherches.
•.collect : Implémentation de la RFC 3671. Les attributs collectifs partagent des valeurs communes entre l’ensemble des membres héritant d’une entrée commune.
•.constraint : Permet de forcer des contraintes sur des attributs.
•.memberof : Permet de connaître les groupes auxquels appartient un utilisateur
•.ppolicy : Password Policy. Permet la mise en place de contrôles sur les mots de passe (longueur, durée de validité, etc…).
•.refint :Referential Integrity. Permet de s’assurer de la cohérence de l’annuaire lors de suppression d’entrées.
•.syncprov :Syncrepl Provider. Permet la réplication syncrepl, incluant la fonctionnalité de recherche persistante. On l’installera plus tard.
•.translucent : Translucent Proxy. Cet overlay peut être utilisé avec un backend local pour créer un proxy transparent. Le contenu des entrées récupérées à partir d’un serveur LDAP distant peut être en partie réécrit/modifé/completé par la base locale.
•.unique : permet de s’assurer de l’unicité d’attributs.
•.valsort : Permet de forcer l’ordre pour les valeurs d’attributs lorsqu’ils sont retournées suite à une recherche.
En gras, ceux dont nous nous servirons.
Plus d’informations sur ce site : https://www.openldap.org/doc/admin24/overlays.html.
Pour chaque overlay, la configuration se fait en plusieurs fichiers. Généralement, un pour l’activation (qui ne sera utilisé qu’une fois). L’autre pour la configuration (nous pourrons alors le modifier plus tard). Ce fichier pour la configuration porte sur la base par défaut {1}mdb (qui contient notre arbre dc=debugo,dc=fr. Par la suite, avec d’autres arbres, nous pourrons alors configurer ces overlays sur ceux ci.
L’overlay memberof permet de savoir dans quels groupes se trouve un utilisateur en une seule requête au lieu de deux.
Exemple :
# ldapsearch -xLLL "(uid=toto)" memberof
retournera la liste des groupes auquel l’utilisateur toto appartient.
Créez un fichier memberof_act.ldif et insérez le contenu suivant :
dn: cn=module,cn=config
cn:module
objectclass: olcModuleList
objectclass: top
olcmoduleload: memberof.la
olcmodulepath: /usr/lib/ldap
Créez un fichier memberof_conf.ldif et insérez le contenu suivant :
dn: olcOverlay=memberof,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcMemberOf
objectClass: olcOverlayConfig
objectClass: olcConfig
objectClass: top
olcOverlay: memberof
olcMemberOfDangling: ignore
olcMemberOfRefInt: TRUE
olcMemberOfGroupOC: groupOfNames
olcMemberOfMemberAD: member
olcMemberOfMemberOfAD: memberOf
On injecte :
# ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_act.ldif
# ldapadd -Y EXTERNAL -H ldapi:/// -f memberof_conf.ldif
Pour vérifier :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcModuleList"
Ou bien encore :
# tree /etc/ldap/slapd.d/
On doit trouver trace dans la liste des modules.
On peut vérifier la configuration avec :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcmemberOf"
Cet overlay permet de supprimer un utilisateur d’un groupe quand on supprime l’utilisateur. Au passage, si un groupe se retrouve vide, l’admin sera automatiquement ajouté (un groupe vide créé une erreur dans OpenLdap)
Créez un fichier refint_act.ldif et insérez le contenu suivant :
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcmoduleload: refint.la
olcmodulepath: /usr/lib/ldap
Créez un fichier refint_conf.ldif et insérez le contenu suivant :
dn: olcOverlay=refint,olcDatabase={1}mdb,cn=config
objectClass: olcConfig
objectClass: olcOverlayConfig
objectClass: olcRefintConfig
objectClass: top
olcOverlay: refint
olcRefintAttribute: memberof member manager owner
olcRefintNothing: cn=admin,dc=debugo,dc=fr
On injecte :
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f refint_act.ldif
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f refint_conf.ldif
On vérifie :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcModuleList"
On peut vérifier la configuration avec :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcRefintConfig"
Cet overlay sert à auditer chaque modification au sein de l’annuaire. Dans notre cas, cela sera inscrit dans le fichier : /var/log/openldap/audit.ldif
Créez le fichier auditlog_act.ldif pour y insérer :
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcModuleLoad: auditlog.la
olcmodulepath: /usr/lib/ldap
Créez le fichier auditlog_conf.ldif pour y insérer :
dn: olcOverlay=auditlog,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcAuditLogConfig
olcOverlay: auditlog
olcAuditlogFile: /var/log/openldap/auditlog.ldif
Injectez :
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f auditlog_act.ldif
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f auditlog_conf.ldif
On vérifie :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcModuleList"
On peut vérifier la configuration avec :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcAuditLogConfig"
Ensuite, nous allons créer le fichier :
# mkdir /var/log/openldap
# chmod 755 /var/log/openldap
# chown openldap:openldap /var/log/openldap
# touch /var/log/openldap/auditlog.ldif
# chmod 755 /var/log/openldap/auditlog.ldif
# chown openldap:openldap /var/log/openldap/auditlog.ldif
Cet overlay permet de nous assurer l’unicité des attributs que l’on spécifie.
Créez un fichier unique_act.ldif pour y insérer :
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcModuleLoad: unique.la
olcmodulepath: /usr/lib/ldap
Créez un fichier unique_conf.ldif pour y insérer :
dn: olcOverlay=unique,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcUniqueConfig
olcOverlay: unique
olcUniqueUri: ldap:///ou=people,dc=debugo,dc=fr?uid?sub
olcUniqueUri: ldap:///ou=people,dc=debugo,dc=fr?mail?sub
olcUniqueUri: ldap:///ou=people,dc=debugo,dc=fr?uidNumber?sub
olcUniqueUri: ldap:///ou=groups,dc=debugo,dc=fr?cn?sub
Nous demandons ici à ce que les attributs ui, mail et uidNumber dans l’ou people soient uniques. Et que l’attribut cn dans l’ou groups soit lui aussi unique.
Injectez :
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f unique_act.ldif
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f unique_conf.ldif
On vérifie :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcModuleList"
On peut vérifier la configuration avec :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcUniqueConfig"
Cet overlay va nous permettre de spécifier une politique de mot de passe.
Un peu particulier, il faut ajouter son schéma dans l’annuaire :
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/ppolicy.ldif
On peut voir que c’est bon avec :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=schema,cn=config" cn
Ou bien encore :
# tree /etc/ldap/slapd.d/
Dans la branche cn=schema, on doit voir le schéma ppolicy qui s’est ajouté à ceux présent par défaut (core, cosine, nis et inetorgperson).
Créez un fichier ppolicy_act.ldif pour y insérer :
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcModuleLoad: ppolicy.la
olcmodulepath: /usr/lib/ldap
Créez un fichier ppolicy_conf.ldif pour y insérer :
dn: olcOverlay=ppolicy,olcDatabase={1}mdb,cn=config
objectClass: olcOverlayConfig
objectClass: olcPpolicyConfig
olcOverlay: ppolicy
olcPPolicyDefault: cn=ppolicy,dc=debugo,dc=fr
olcPPolicyHashCleartext: TRUE
olcPPolicyUseLockout: FALSE
olcPPolicyDefault : Indique le DN de configuration utilisé par défaut (nous le définirons apres).
olcPPolicyHashCleartext : Indique si les mots de passe doivent être cryptés.
olcPPolicyUseLockout : Si TRUE, le message d’erreur retourné en cas de connexion à un compte vérouillé indiquera qu’il s’agit d’un compte vérouillé. Si FALSE, ce sera un message d’échec stantard.
On injecte
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ppolicy_act.ldif
# ldapadd -Q -Y EXTERNAL -H ldapi:/// -f ppolicy_conf.ldif
On vérifie :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "cn=config" "Objectclass=olcPpolicyConfig" -LLL
On va maintenant créer la politique par défaut.
Créez un fichier ppolicy_def.ldif pour y insérer :
dn: cn=ppolicy,dc=debugo,dc=fr
objectClass: top
objectClass: device
objectClass: pwdPolicy
cn: ppolicy
pwdAllowUserChange: TRUE
pwdAttribute: userPassword
pwdCheckQuality: 1
pwdExpireWarning: 0
pwdFailureCountInterval: 30
pwdGraceAuthNLimit: 5
pwdInHistory: 5
pwdLockout: TRUE
pwdLockoutDuration: 60
pwdMaxAge: 0
pwdMaxFailure: 5
pwdMinAge: 0
pwdMinLength: 5
pwdMustChange: FALSE
pwdSafeModify: FALSE
La signification des attributs est :
pwdAllowUserChange : indique si l’utilisateur peut changer son mot de passe.
pwdCheckQuality : indique si OpenLDAP renvoie une erreur si le mot de passe n’est pas conforme
pwdExpireWarning : avertissement d’expiration.
pwdFailureCountInterval : Intervalle de temps entre deux tentatives infructueuses pour qu’elles soient considérées comme « à la suite ».
pwdGraceAuthNLimit : période de grâce suite à l’expiration du mot de passe.
pwdInHistory : nombre de mots de passe dans l’historique.
pwdLockout : indique si on bloque le compte au bout de X échecs.
pwdLockoutDuration : durée du blocage du compte (en secondes).
pwdMaxAge : age maximal du mot de passe (en secondes).
pwdMaxFailure : nombre d’échecs de saisie du mot de passe maximal (avant blocage).
pwdMinAge : age minimal du mot de passe (en secondes).
pwdMinLength : longueur minimale du mot de passe.
pwdMustChange : indique si l’utilisateur doit changer son mot de passe.
pwdSafeModify : indique si il faut envoyer l’ancien mot de passe avec le nouveau pour modification.
On injecte :
# ldapadd -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f ppolicy-def.ldif
On vérifie :
# ldapsearch -QLLLY EXTERNAL -H ldapi:/// -b "dc=debugo,dc=fr" "Objectclass=pwdPolicy"
On peut avoir plusieurs politique (une adapté pour des comptes clients, par exemple).
Par ex, fichier ppolicy-client.ldif :
dn: cn=ppolicy-client,dc=debugo,dc=fr
objectClass: top
objectClass: device
objectClass: pwdPolicy
cn: ppolicy-client
pwdAllowUserChange: TRUE
pwdAttribute: userPassword
pwdCheckQuality: 1
pwdExpireWarning: 0
pwdFailureCountInterval: 30
pwdGraceAuthNLimit: 5
pwdInHistory: 10
pwdLockout: TRUE
pwdLockoutDuration: 60
pwdMaxAge: 0
pwdMaxFailure: 3
pwdMinAge: 0
pwdMinLength: 8
pwdMustChange: FALSE
pwdSafeModify: TRUE
Qu’on injecte :
# ldapadd -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f ppolicy-client.ldif
Et qu’on affectera avec un fichier changeppolicy.ldif :
dn: uid=toto,ou=client,ou=people,dc=debugo,dc=fr
changetype: modify
replace: pwdPolicySubEntry
pwdPolicySubEntry: cn=ppolicy-client,dc=debugo,dc=fr
Qu’on injectera avec :
# ldapadd -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f changeppolicy.ldif
On pourra aussi spécifier cet attribut à la création de l’utilisateur.
Voila pour la seconde partie.
Dans la suite, nous peuplerons notre annuaire.
Nous avions créé un répertoire /root/ldap/conf pour y mettre la configuration. Créons un répertoire pour y mettre les fichiers ldif contenant les données.
# cd /root/ldap
# mkdir data
# cd data
Pour rappel, les OUs sont des conteneurs qui permettent de ranger les données dans l’annuaire, de les hiérarchiser. Il ne faut pas les confondre avec les Groupes.
Créez un fichier OU.ldif et remplissez le de la sorte :
dn: ou=people,dc=debugo,dc=fr
ou: people
objectClass: organizationalUnit
dn: ou=group,dc=debugo,dc=fr
ou: group
objectClass: organizationalUnit
dn: ou=system,dc=debugo,dc=fr
ou: system
objectClass: organizationalUnit
dn: ou=debugo,ou=people,dc=debugo,dc=fr
ou: debugo
objectClass: organizationalUnit
dn: ou=client,ou=people,dc=debugo,dc=fr
ou: client
objectClass: organizationalUnit
dn: ou=sysgroup,ou=group,dc=debugo,dc=fr
ou: sysgroup
objectClass: organizationalUnit
dn: ou=workgroup,ou=group,dc=debugo,dc=fr
ou: workgroup
objectClass: organizationalUnit
Les OUs que j’utilise me sont propres. Surement en aurez vous besoin d’autres, etc.. A vous de modifier.
On injecte :
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f OU.ldif
On va créer notre premier utilisateur.
Fichier User_niko.ldif :
dn: uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: niko
sn: niko
givenName: Nicolas
cn: Nicolas
displayName: Nicolas
userPassword: password
mail: mail@spam.com
title: Admin
initials: N
On injecte :
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f User_niko.ldif
Profitons pour faire une explication sur ces lignes :
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
Notre utilisateur héritera des attributs de ces trois classes. Mais qu’est ce donc ?
Voyons un peu les schémas :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=schema,cn=config"
Beaucoup d’infos, pour s’en sortir affichons les dn des schémas :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=schema,cn=config" dn
Ce qui nous affiche :
dn: cn=schema,cn=config
dn: cn={0}core,cn=schema,cn=config
dn: cn={1}cosine,cn=schema,cn=config
dn: cn={2}nis,cn=schema,cn=config
dn: cn={3}inetorgperson,cn=schema,cn=config
dn: cn={4}ppolicy,cn=schema,cn=config
Concentrons nous sur le schéma core :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=schema,cn=config" "cn={0}core"
La vous devez voir deux grands types de données : les olcObjectClasses et les olcAttributeTypes:
Les AttributeTypes sont les attributs que peuvent avoir les entrées de l’annuaire. Les ObjectClasses sont les regroupement de ces attributs.
Regardons les différents ObjectClasses qui composent notre schéma core :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=schema,cn=config" "cn={0}core" olcObjectClasses
En cherchant dedans, on va trouver nos objectclasses person et organizationalPerson :
olcObjectClasses: {4}( 2.5.6.6 NAME 'person' DESC 'RFC2256: a person' SUP top
STRUCTURAL MUST ( sn $ cn ) MAY ( userPassword $ telephoneNumber $ seeAlso $
description ) )
olcObjectClasses: {5}( 2.5.6.7 NAME 'organizationalPerson' DESC 'RFC2256: an o
rganizational person' SUP person STRUCTURAL MAY ( title $ x121Address $ regis
teredAddress $ destinationIndicator $ preferredDeliveryMethod $ telexNumber $
teletexTerminalIdentifier $ telephoneNumber $ internationaliSDNNumber $ fac
simileTelephoneNumber $ street $ postOfficeBox $ postalCode $ postalAddress $
physicalDeliveryOfficeName $ ou $ st $ l ) )
Ce qu’il faut comprendre :
L’ObjectClasses person hérite de top.
Must spécifie les AttributeTypes obligatoires : sn et cn.
May définie les AttributeTypes facultatives
Les AttributeTypes sont définis sur un modèle similaire, par exemple :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=schema,cn=config" "cn={0}core" olcAttributeTypes
J’en prend un au hasard :
olcAttributeTypes: {6}( 2.5.4.9 NAME ( 'street' 'streetAddress' ) DESC 'RFC225
6: street address of this object' EQUALITY caseIgnoreMatch SUBSTR caseIgnoreS
ubstringsMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15{128} )
On trouve le nom de l’attribut, une description et son type (SYNTAX suivi d’un OID, je reviendrais sur ce point dans le chapitre consacré à la création d’un schéma).
L’objet que l’on créé hérite des attributs des classes person, organizationalPerson et inetOrgPerson.
Voila donc pour les explications sur les ObjectClasses et les AttributeTypes:
Au passage, on va vérifier quelques points.
Regardons comment est stocké le mdp dans la base :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "dc=debugo,dc=fr" "uid=niko"
On voit une ligne :
userPassword:: e1NTSEF9TklxSkd5YVFBdVcwMkpOVmplcjArOGYwRmNNMjNBVXg=
Il s’agit d’un codage en base64. Pour le décoder :
# echo e1NTSEF9TklxSkd5YVFBdVcwMkpOVmplcjArOGYwRmNNMjNBVXg= | base64 -d
Et la on le résultat suivant :
{SSHA}NIqJGyaQAuW02JNVjer0+8f0FcM23AUx
Le mot de passe est bien crypté comme configuré avec l’overlay ppolicy.
Et pour tester la connexion avec ce compte :
# ldapsearch -xLLLH ldap://localhost -D uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr -W -b "dc=debugo,dc=fr" "uid=niko"
Et si vous tapez le bon mot de passe, cela vous affiche votre propre fiche.
A noter, il existe deux types de groupes : les posixgroup et les groupofnames.
Les posixgroup sont similaires au groupes Unix, et les groupofnames ressemblent plus à des groupes AD.
Pour faire simple, l’avantage des groupofnames est qu’avec un filtre sur un utilisateur, on peut connaitre ses groupes (avec l’overlay memberof). Chose impossible avec les posixgroups.
Par contre, il est impératif d’avoir au moins un utilisateur dans un groupe de type groupofnames. Vous pouvez être tenté de vous mettre par défaut, mais le jour ou vous aller modifier votre schéma, vous allez devoir supprimer les utilisateurs, et un groupe sans utilisateur garde l’uid du dernier membre à l’avoir quitté et si vous refaite un compte avec le même uid, impossible de vous remettre dedans sans supprimer le groupe. Bref, perso, je met l’admin par défaut, comme ça pas de risques. De plus notre overlay refint configuré au préalable est raccord avec cela.
On créé un fichier Group.ldif :
dn: cn=cloud,ou=sysgroup,ou=group,dc=debugo,dc=fr
cn: cloud
description: Cloud
objectClass: groupOfNames
member: cn=admin,dc=debugo,dc=fr
dn: cn=debugo,ou=workgroup,ou=group,dc=debugo,dc=fr
cn: debugo
description: Debugo
objectClass: groupOfNames
member: cn=admin,dc=debugo,dc=fr
J’ai mis dedans les groupes dont j’ai besoin, à vous de faire en fonction, etc…
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f Group.ldif
Au passage, on peut tester notre overlay memberof :
# ldapsearch -xLLLH ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "dc=debugo,dc=fr" "cn=admin" memberof
Doit nous retourner quelque chose qui ressemble à :
dn: cn=admin,dc=debugo,dc=fr
memberOf: cn=cloud,ou=sysgroup,ou=group,dc=debugo,dc=fr
memberOf: cn=wiki,ou=sysgroup,ou=group,dc=debugo,dc=fr
memberOf: cn=debugo,ou=workgroup,ou=group,dc=debugo,dc=fr
A la question, si je veux rajouter un utilisateur dans un groupe, comment faire ?
Je vous répond qu’avec OpenLdap, tout passe par des fichiers ldif, du coup, créez un fichier addusertogroup.ldif pour y mettre :
dn: cn=cloud,ou=sysgroup,ou=group,dc=debugo,dc=fr
changetype: modify
add: member
member: uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr
Puis on injecte :
# ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f addusertogroup.ldif
Et la, si on requête cela :
ldapsearch -xLLLH ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "dc=debugo,dc=fr" "uid=niko" memberof
On doit avoir ceci :
dn: uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr
memberOf: cn=cloud,ou=sysgroup,ou=group,dc=debugo,dc=fr
Nous verrons plus en détail les ajouts, modifications, suppressions dans la partie suivante.
Par défaut, l’accès à l’annuaire est assez ouvert :
# ldapsearch -xLLL
On voit ce que l’accès anonyme nous affiche…
On va devoir filtrer un peu.
Tout d’abord, nous allons créer deux compte systèmes. Un viewer (qui aura des droits de lecture uniquement, utilisé par les applications pour se connecter à l’annuaire et vérifier des droits, au lieu de passe par le bind anonyme) et un Writer (qui lui aura des droits d’écriture…)
Créez le fichier viewer.ldif :
dn: cn=viewer,ou=system,dc=debugo,dc=fr
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: viewer
description: LDAP viewer
userPassword: passview
Créez le fichier writer.ldif :
dn: cn=writer,ou=system,dc=debugo,dc=fr
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: writer
description: LDAP Writer
userPassword: passwrite
Injectez :
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f viewer.ldif
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f writer.ldif
Voyons les ACLs par défaut :
# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b "cn=config" "olcDatabase={1}mdb" olcaccess
Modifions les pour empêcher les connexions anonymes.
Créez un fichier acl.ldif :
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: to attrs=userPassword by self write by anonymous auth by dn="cn=writer,ou=system,dc=debugo,dc=fr" write by dn="cn=viewer,ou=system,dc=debugo,dc=fr" read by dn="cn=admin,dc=debugo,dc=fr" write by * none
olcAccess: to dn.base="dc=debugo,dc=fr" by users read
olcAccess: to * by self write by dn="cn=admin,dc=debugo,dc=fr" write by * read by anonymous none
J’expliquerais plus précisément le fonctionnement des ACLs dans un autre article. Nous modifions la deuxieme ACL qui par défaut donne accès en lecture à tout le monde. La, nous réduisons la lecture aux utilisateurs authentifiés.
On injecte :
ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f acl.ldif
On test de manière anonyme :
# ldapsearch -xLLL
Ça ne passe plus.
On teste avec notre compte viewer :
# ldapsearch -xLLL -H ldap://localhost -D cn=viewer,ou=system,dc=debugo,dc=fr -w passview -b "dc=debugo,dc=fr" "uid=niko"
Bingo !
Dans la prochaine partie, nous allons voir comment modifier les entrées de l’annuaire.
Quatrième partie de la série de tuto sur OpenLDAP consacrée à la modification des données.
Après avoir vu l’installation, les overlays et inséré nos premières données, voyons maintenant comment les modifier.
Avant tout, rappelons que nous pouvons en gros séparer les objets que nous manipulons en quatre familles (il y en a plus, mais je fais simple)
Les schémas (nous verrons cela en détail dans un autre article)
Les OU, qui sont des conteneurs.
Les entrées : groupes, utilisateur, etc…
Les attributs, rattachés aux entrées.
Nous allons utiliser énormément les commande ldapsearch et ldapmodify.
Du coup, afin d’aller plus vite nous allons créer des alias.
Éditez le fichier /root/.bashrc pour y ajouter :
alias lmodif='ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias lsearch='ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias ladd='ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias ldel='ldapdelete -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
Puis pour recharger le fichier :
# source ~/.bashrc
Dorénavant, il n’y aura plus tout à saisir…
Tout d’abord, listons ce qui est présent
# lsearch -b "dc=debugo,dc=fr" "objectClass=organizationalUnit"
Je vais profiter de cette partie sur les OU pour expliquer les trois commandes à notre disposition pour modifier les données de l’annuaire : ldapadd, ldapmodify et ldapdelete.
ldapadd est un alias de ldapmodify -a, le commutateur -a indiquant un ajout. Ce commutateur peut être remplacé par la ligne changetype: add dans le fichier ldif.
Ainsi, pour ajouter une OU par ex avec le fichier addou.ldif :
dn: ou=test,ou=people,dc=debugo,dc=fr
ou: test
objectClass: organizationalUnit
Injection :
# ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f addou.ldif
ou
# ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -a -f addou.ldif
Autre méthode avec le ficher addou.ldif :
dn: ou=test,ou=people,dc=debugo,dc=fr
changetype: add
ou: test
objectClass: organizationalUnit
Injection
# ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f addou.ldif
Ces trois façons de faire donnent le même résultat.
L’avantage de tout faire par ex avec ldapmodify est que l’on peut effectuer plusieurs opérations en un fichier, le tout étant de laisser une ligne avec – entre chaque opération.
Exemple avec le fichier test.ldif :
dn: ou=test,ou=people,dc=debugo,dc=fr
changetype: add
ou: test
objectClass: organizationalUnit
-
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
changetype: delete
Dans ce fichier, nous ajoutons une OU puis nous supprimons un utilisateur. Il n’y a pas de limite d’opérations que l’on peut effectuer en une fois.
Nous renommons l’OU test en newtest avec le fichier chgou.ldif :
dn: ou=test,ou=people,dc=debugo,dc=fr
changetype: modrdn
newrdn: ou=newtest
deleteoldrdn: 1
Injection :
# lmodif -f chgou.ldif
Nous déplaçons l’OU newtest de la branche ou=people,dc=debugo,dc=fr vers la branche ou=workgroup,ou=group,dc=debugo,dc=fr avec le fichier mvou.ldif :
dn: ou=newtest,ou=people,dc=debugo,dc=fr
changetype: modrdn
newrdn: ou=newtest
deleteoldrdn: 1
newsuperior: ou=workgroup,ou=group,dc=debugo,dc=fr
Injection :
# lmodif -f mvou.ldif
Il est nécessaire qu’elle soit vide.
Supprimons l’OU newtest avec le fichier deleteou.ldif :
dn: ou=newtest,ou=workgroup,ou=group,dc=debugo,dc=fr
changetype: delete
Injection :
# lmodif -f deleteou.ldif
Ou bien un fichier deleteou.ldif :
ou=newtest,ou=workgroup,ou=group,dc=debugo,dc=fr
Injection :
# ldel -f deleteou.ldif
Dans notre cas, les entrées sont de deux types, les users et les groupes.
Listons les groupes :
# lsearch -b "dc=debugo,dc=fr" "objectClass=groupOfNames"
Listons les users :
# lsearch -b "dc=debugo,dc=fr" "objectClass=InetOrgPerson"
Ajoutons un utilisateur toto avec le fichier adduser.ldif :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: toto
sn: toto
givenName: toto
cn: toto
displayName: toto
userPassword: password
Injection :
# ladd -f adduser.ldif
Ajoutons un groupe test avec le fichier addgrp.ldif :
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
cn: test
description: test
objectClass: groupOfNames
member: cn=admin,dc=debugo,dc=fr
Injection :
# ladd -f addgrp.ldif
Déplaçons toto de ou=debugo,ou=people,dc=debugo,dc=fr vers ou=client,ou=people,dc=debugo,dc=fr avec le fichier mvuser.ldif :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
changetype: modrdn
newrdn: uid=toto
deleteoldrdn: 1
newsuperior: ou=client,ou=people,dc=debugo,dc=fr
Injection :
# lmodif -f mvuser.ldif
Déplaçons le groupe test de ou=workgroup,ou=group,dc=debugo,dc=fr vers ou=sysgroup,ou=group,dc=debugo,dc=fr avec le fichier mvgrp.ldif :
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
changetype: modrdn
newrdn: cn=test
deleteoldrdn: 1
newsuperior: ou=sysgroup,ou=group,dc=debugo,dc=fr
Injection :
# lmodif -f mvgrp.ldif
Renommons toto en tata avec le fichier renameuser.ldif :
dn: uid=toto,ou=client,ou=people,dc=debugo,dc=fr
changetype: modrdn
newrdn: uid=tata
deleteoldrdn: 1
Injection
# lmodif -f renameuser.ldif
Ceci ne change que le nom de l’entrée dn: uid=tata,ou=client,ou=people,dc=debugo,dc=fr. Les autres attributs (cn, sn, etc..) s’ils doivent être renommés seront modifiés par une autre opération (voir plus bas).
Renommons le groupe test en newtest avec le fichier renamegrp.ldif :
dn: cn=test,ou=sysgroup,ou=group,dc=debugo,dc=fr
changetype: modrdn
newrdn: cn=newtest
deleteoldrdn: 1
Injection
# lmodif -f renamegrp.ldif
Supprimons l’utilisateur tata à l’aide d’un fichier deluser.ldif :
dn: uid=tata,ou=client,ou=people,dc=debugo,dc=fr
changetype: delete
Injection
# lmodif -f deluser.ldif
On aurait pu aussi directement faire :
# ldel uid=tata,ou=client,ou=people,dc=debugo,dc=fr
Supprimons le groupe newtest à l’aide d’un fichier delgrp.ldif :
dn: cn=newtest,ou=sysgroup,ou=group,dc=debugo,dc=fr
changetype: delete
Injection
# lmodif -f delgrp.ldif
Ou bien :
# ldel cn=newtest,ou=sysgroup,ou=group,dc=debugo,dc=fr
Nous allons réinsérer un utilisateur test et un groupe test avant tout :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
objectclass: top
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: toto
sn: toto
givenName: toto
cn: toto
displayName: toto
userPassword: password
Injection :
# ladd -f adduser.ldif
Puis :
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
cn: test
description: test
objectClass: groupOfNames
member: cn=admin,dc=debugo,dc=fr
Injection :
# ladd -f addgrp.ldif
Listons les attributs à notre disposition :
# lsearch -b "cn=schema,cn=config" olcAttributeTypes
Ou plus précises ment du schéma core :
# lsearch -b "cn={0}core,cn=schema,cn=config" olcAttributeTypes
Ajoutons un attribut description à notre utilisateur toto avec un fichier addattribute.ldif :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
changetype: modify
add: description
description: Sa tete est egale a zero plus zero !
Injection :
# lmodif -f addattribute.ldif
Et on peut vérifier l’ajout :
# lsearch -b "dc=debugo,dc=fr" uid=toto
Regardons ce que propose la classe groupOfNames (dans le schéma core)
# lsearch -b "cn={0}core,cn=schema,cn=config" olcObjectClasses
On va trouver :
olcObjectClasses: {7}( 2.5.6.9 NAME 'groupOfNames' DESC 'RFC2256: a group of n
ames (DNs)' SUP top STRUCTURAL MUST ( member $ cn ) MAY ( businessCategory $
seeAlso $ owner $ ou $ o $ description ) )
Pour un groupe, ce qui est le plus fréquent d’ajouter comme attribut, c’est un utilisateur (ajout d’un membre dans un groupe…)
Bref, ajoutons donc notre utilisateur test dans le groupe test avec un fichier addusertogroup.ldif :
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
changetype: modify
add: member
member: uid=toto,ou=client,ou=people,dc=debugo,dc=fr
Injection :
# lmodif -f addusertogroup.ldif
On peut vérifier :
# lsearch -b "dc=debugo,dc=fr" "(&(objectclass=inetOrgPerson)(memberof=cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr))" dn
Si on regarde la fiche de toto :
# lsearch -b "dc=debugo,dc=fr" "uid=toto"
On constater qu’on ne voit pas l’attribut memberof (overlay que nous avons pourtant configuré. En effet, il faut le demander spécifiquement :
# lsearch -b "dc=debugo,dc=fr" "uid=toto" memberof
Ou alors, nous pouvons le voir avec cette commande :
# lsearch -b "dc=debugo,dc=fr" "uid=toto" +
Un attribut qui peut etre modifié fréquement sur un utilisateur, c’est le mot de passe. Modifions donc le mot de passe de toto avec un fichier chgpwd.ldif :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
changetype: modify
replace: UserPassword
UserPassword: newpass
Injection :
# lmodif -f chgpwd.ldif
Ceci dit, pour modifier un mot de passe, nous avons la commande ldappassword consacré à cet usage :
# ldappasswd -H ldap://localhost -D "uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr" -W -S
-W pour la demande de l’ancien mot de passe.
-S pour la demande d’un nouveau mot de passe (sinon, le nouveau mot de passe est généré aléatoirement)
Cette commande peut également servir à changer le mot de passe d’un autre utilisateur, par exemple, le compte admin demande à changer le mot de passe de l’utilisateur niko :
# ldappasswd -D "cn=admin,dc=debugo,dc=fr" -w passsadmin -x "uid=niko,ou=debugo,ou=people,dc=debugo,dc=fr" -S
Modifions la description de notre groupe test avec un fichier chgattr.ldif :
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
changetype: modify
replace: description
description: Nouvelle description
Injection :
# lmodif -f chgattr.ldif
Supprimons l’attribut description de toto avec un fichier delattr.ldif :
dn: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
changetype: modify
delete: description
Injection :
# lmodif -f delattr.ldif
Pour un groupe, vous vous en doutez, un attribut qui peut etre amené à etre supprimé, c’est un membre. Supprimons donc toto du groupe test avec un ficher
dn: cn=test,ou=workgroup,ou=group,dc=debugo,dc=fr
changetype: modify
delete: member
member: uid=toto,ou=debugo,ou=people,dc=debugo,dc=fr
Injection
# lmodif -f deluserfromgroup.ldif
Vérification :
# lsearch -b "dc=debugo,dc=fr" "(&(objectclass=groupOfNames)(cn=test))" member
Voila qui termine ce long article. J’aurais pu faire plus court, certaines manipulation étant au final tres similaire, mais j’ai ainsi voulu couvrir de nombreuses applications que vous pouvez être amenés à rencontrer.
Dans le chapitre suivant, nous allons parler sauvegarde et restauration.
Cinquième partie de la série de tuto sur OpenLDAP consacrée à la sauvegarde et restauration des données.
Jusque la, nous avons vu l’installation, les overlays,inséré nos premières données, et appris comment les modifier.
Voyons maintenant comment effectuer des sauvegardes de tout cela.
Rappel, j’utilise des alias que je défini au début de cet article.
On va prendre connaissance de l’endroit ou sont stockées les données.
# lsearch -b "cn=config" "(&(objectClass=olcDatabaseConfig))" olcDbDirectory
Ce qui va donner :
dn: olcDatabase={-1}frontend,cn=config
dn: olcDatabase={0}config,cn=config
dn: olcDatabase={1}mdb,cn=config
olcDbDirectory: /var/lib/ldap
La ligne qui nous intéresse est /var/lib/ldap.
Cette commande peut être lancée avec le service LDAP en fonctionnement.
# slapcat -b cn=config > save_config.ldif
Comme pour la configuration, cette commande peut être lancée avec le service en fonctionnement.
# slapcat -b dc=debugo,dc=fr > save_data.ldif
On commence par arrêter le serveur si celui ci tourne :
# service slapd stop
On va supprimer l’existant :
# rm /etc/ldap/slapd.d/ -r
On va recréer :
# mkdir /etc/ldap/slapd.d/
On réinjecte :
# slapadd -F /etc/ldap/slapd.d -b cn=config -l save_config.ldif
On redonne les droits
# chown -R openldap:openldap /etc/ldap/slapd.d/
On peut relancer :
# service slapd start
On commence par arrêter le serveur si celui ci tourne :
# service slapd stop
On va supprimer l’existant (repertoire que nous avons noté au début) :
# rm /var/lib/ldap/ -r
On va recréer :
# mkdir /var/lib/ldap/
On réinjecte :
# slapadd -b dc=debugo,dc=fr -l save_data.ldif
On redonne les droits
# chown -R openldap:openldap /var/lib/ldap/
On ré-indexe :
# slapindex
On relance le serveur :
# service slapd start
Et voila ! Ces manipulations sont simple, mais ne les négligez pas, il reste assez facile de fusiller un annuaire LDAP avec quelques fausses manipulations…
Dans l’article suivant, nous allons voir la réplication.
Nous allons mettre en place une réplication Maitre-Maitre. L’idée est de faire en sorte que n’importe lequel de nos serveurs LDAP soit capable à la fois de lire les données, mais également de les modifier. De plus,nous allons mettre en place une réplication, à la fois sur l’arbre de données dc=debugo,dc=fr mais également sur l’arbre de configuration cn=config.
Sur un nouveau serveur, installez OpenLDAP, puis comme pour le serveur déjà en place:
# dpkg-reconfigure slapd
Mettez les informations que vous aviez renseignées.
Effectuez également la configuration de rsyslog.
Maintenant, sur le premier serveur, créez des sauvegardes de la configuration et des données (suivez ce tuto). Puis, depuis le premier serveur, nous allons envoyer les fichiers de sauvegarde sur le second serveur, ceci afin de gagner du temps. Pas de besoin de tout reconfigurer à l’identique.
maitre1# scp save_*.ldif root@maitre2:/root
Ensuite, réinjectez les sauvegardes en suivant la partie II de l’article Sauvegarde et restauration.
Ce qui suit est à faire sur chaque serveur !
Nous allons commencer par activer l’Overlay Syncprov à l’aide d’un fichier 01-syncprov_act.ldif :
dn: cn=module,cn=config
cn: module
objectclass: olcModuleList
objectclass: top
olcmoduleload: syncprov.la
olcmodulepath: /usr/lib/ldap
On injecte :
ldapx# ldapadd -Y EXTERNAL -H ldapi:/// -f 01-syncprov_act.ldif
On peut vérifier avec :
ldapx# ldapsearch -LLLY external -H ldapi:/// -b "cn=config" "objectClass=olcModuleList"
ldapx# ldapsearch -LLLY external -H ldapi:/// -b "cn=module{6},cn=config"
Sur chaque serveur, un fichier 02-serverid.ldif :
dn: cn=config
changetype: modify
add: olcServerID
olcServerID: x
Attention, sur le premier serveur olcServerID:1, sur le second olcServerID: 2, etc…
On injecte :
ldapx# ldapmodify -Y EXTERNAL -H ldapi:/// -f 02-serverid.ldif
Pour vérifier :
ldapx# ldapsearch -LLLY external -H ldapi:/// -b "cn=config" "objectClass=olcGlobal" olcServerID
Ensuite, nous allons créer un utilisateur pour la replication dans un fichier 03-replica_account.ldif :
dn: cn=replica,ou=system,dc=debugo,dc=fr
userPassword: password
cn: replica
objectclass: top
objectclass: person
sn: replica
On injecte :
ldapx# ldapadd -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -f 03-replica_account.ldif
Ces manipulations sont toujours à effectuer sur les deux serveurs.
Nous allons donner à l’utilisateur cn=replica,dc=debugo,dc=fr le droit de modifier la configuration via un fichier 04-droit_conf.ldif :
dn: olcDatabase={0}config,cn=config
changeType: modify
add: olcAccess
olcAccess: to * by dn.exact=cn=replica,ou=system,dc=debugo,dc=fr manage by * break
On injecte
ldapx# ldapmodify -Y EXTERNAL -H ldapi:/// -f 04-droit_conf.ldif
Créez un fichier 05-syncprov_conf_conf.ldif pour y mettre :
dn: olcOverlay=syncprov,olcDatabase={0}config,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
Injectez :
ldapx# ldapmodify -Y EXTERNAL -H ldapi:/// -f 05-syncprov_conf_conf.ldif
Créez un fichier 06-repl_conf_conf.ldif pour y mettre :
dn: olcDatabase={0}config,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=01 provider=ldap://IPSERVEUR1
binddn="cn=replica,ou=system,dc=debugo,dc=fr" bindmethod=simple
credentials=password searchbase="cn=config"
type=refreshAndPersist retry="5 5 300 5" timeout=1
olcSyncRepl: rid=02 provider=ldap://IPSERVEUR2
binddn="cn=replica,ou=system,dc=debugo,dc=fr" bindmethod=simple
credentials=password searchbase="cn=config"
type=refreshAndPersist retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE
Les lignes binddn, credentials, et type doivent commencer avec deux espaces.
et injectez :
ldapx# ldapmodify -Y EXTERNAL -H ldapi:/// -f 06-repl_conf_conf.ldif
Vérifiez avec :
# ldapsearch -QLLLY external -H ldapi:/// -b "cn=config" "olcDatabase={0}config" olcSyncRepl
Et voila !
Si vous modifiez la configuration sur un serveur (des ACLs par exemple), cela sera répliqué sur l’autre.
Dans les logs, on doit voir des traces de la synchro. Et pour être sur que tout est bien configuré :
# ldapsearch -z1 -LLLQY EXTERNAL -H ldapi:/// -s base -b cn=config contextCSN
doit vous donner le même contextCSN sur chaque serveur.
Ces manipulations ne sont à faire que sur un serveur étant donné que la réplication de la configuration est en place !
Nos acls avaient déjà été établies.
Vérifiez sur les deux serveurs :
ldapx# ldapsearch -QLLLY external -H ldapi:/// -b "cn=config" "olcDatabase={1}mdb" olcAccess
Doit vous donner :
dn: olcDatabase={1}mdb,cn=config
olcAccess:
{0}to attrs=userPassword
by self write by anonymous auth
by dn="cn=writer,ou=system,dc=debugo,dc=fr" write
by dn="cn=viewer,ou=system,dc=debugo,dc=fr" read
by dn="cn=admin,dc=debugo,dc=fr" write
by * none
olcAccess:
{1}to dn.base="dc=debugo,dc=fr"
by users read
olcAccess:
{2}to *
by self write
by dn="cn=admin,dc=debugo,dc=fr" write
by * read
by anonymous none
Nous allons les modifier avec un fichier 07-acl_replica.ldif pour donner le droit à l’utilisateur réplica de TOUT lire (y compris les passwords) :
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: to attrs=userPassword by self write by anonymous auth by dn="cn=writer,ou=system,dc=debugo,dc=fr" write by dn="cn=viewer,ou=system,dc=debugo,dc=fr" read by dn="cn=admin,dc=debugo,dc=fr" write by dn.exact="cn=replica,ou=system,dc=debugo,dc=fr" read by * none
olcAccess: to dn.subtree="dc=debugo,dc=fr" by users read by * none
olcAccess: to * by self write by dn="cn=admin,dc=debugo,dc=fr" write by * read by anonymous none
On injecte :
ldap1# ldapmodify -Y EXTERNAL -H ldapi:/// -f 07-acl_replica.ldif
Vous pouvez vérifier sur chaque serveur, c’est à jour :
ldapx# ldapsearch -QLLLY external -H ldapi:/// -b "cn=config" "olcDatabase={1}mdb" olcAccess
Au passage, on va modifier les limitations dans un fichier 08-limit.ldif :
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcLimits
olcLimits: dn.exact="cn=replica,ou=system,dc=debugo,dc=fr" time.soft=unlimited time.hard=unlimited size.soft=unlimited size.hard=unlimited
On injecte :
ldap1# ldapmodify -Y EXTERNAL -H ldapi:/// -f 08-limit.ldif
On va indexer entryCSN et entryUUID à l’aide d’un fichier 09-index.ldif :
dn:olcDatabase={1}mdb,cn=config
changetype: modify
add: olcDbIndex
olcDbIndex: entryCSN,entryUUID eq
On injecte :
ldap1# ldapmodify -Y EXTERNAL -H ldapi:/// -f 09-index.ldif
On va configurer l’overlay sur la base {1}mdb, qui correspond à notre dc=debugo,dc=fr, avec un fichier 10-syncprov_conf_data.ldif :
dn: olcOverlay=syncprov,olcDatabase={1}mdb,cn=config
changetype: add
objectClass: olcOverlayConfig
objectClass: olcSyncProvConfig
olcOverlay: syncprov
Injectez :
ldap1# ldapmodify -Y EXTERNAL -H ldapi:/// -f 10-syncprov_conf_data.ldif
Créez un fichier 11-repl_conf_data.ldif et insérez :
dn: olcDatabase={1}mdb,cn=config
changetype: modify
add: olcSyncRepl
olcSyncRepl: rid=01 provider=ldap://IPSERVEUR1
binddn="cn=replica,ou=system,dc=debugo,dc=fr"
bindmethod=simple credentials=password
searchbase="dc=debugo,dc=fr"
type=refreshAndPersist retry="5 5 300 5" timeout=1
olcSyncRepl: rid=02 provider=ldap://IPSERVEUR2
binddn="cn=replica,ou=system,dc=debugo,dc=fr"
bindmethod=simple credentials=password
searchbase="dc=debugo,dc=fr"
type=refreshAndPersist retry="5 5 300 5" timeout=1
-
add: olcMirrorMode
olcMirrorMode: TRUE
Injectez :
ldap1# ldapmodify -Y EXTERNAL -H ldapi:/// -f 11-repl_conf_data.ldif
Pour vérifier la synchro, sur un des serveurs, effectuez par exemple une modification d’attribut sur un utilisateur, puis sur les deux serveurs, lancez la commande :
ldapx# ldapsearch -z1 -LLLQY EXTERNAL -H ldapi:/// -s base -b dc=debugo,dc=fr contextCSN
Celle ci doit vous donner la meme réponse. Il faut qu’il y ait eu une modification (changement d’attribut par exemple) sans quoi l’attribut contextCSN n’existera pas.
Dernier point, concernant un petit effet de bord du à la synchro des configurations :
Vos serveurs se retrouvent avec le meme ServerID :
ldapx# ldapsearch -x -LLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -w passadmin -b cn=config "objectClass=olcGlobal"
Pour modifier cela, pas le choix, nous allons devoir éditer le fichier directement (si on refait un ldif qu’on injecte ça va se répliquer…). C’est le mal d’éditer les configs ldap à la main, mais ce coup ci, on a guère le choix…
Du coup, sur les deux serveurs, on arrête slapd :
ldapx# service slapd stop
Puis on va éditer le fichier /etc/ldap/slapd.d/cn\=config.ldif pour renseigner :
olcServerID: X
Ou X sera égal à 1 sur le premier serveur et égal à 2 sur le second.
Puis on relance les deux serveurs: :
ldapx# service slapd start
Et maintenant sur chaque serveur, la commande :
ldapx# ldapsearch -x -LLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -w passadmin -b cn=config "objectClass=olcGlobal"
donne bien son ID propre.
Voila qui clos la partie sur la réplication à proprement parlé.
Dans la partie suivante, nous allons rajouter Keepalived, qui nous permettra d’avoir une IP virtuelle unique pour interroger nos LDAPs.
Septième partie de la série de tuto sur OpenLDAP dans la continuité de la partie précédente sur la réplication, nous allons mettre en place le logiciel Keepalived afin que nos services LDAP soient accessibles via une IP unique.
Ceci ne sera pas un tutoriel complet sur Keepalived, mais juste une rapide présentation et mise en place. J’en parlerais plus longuement dans un futur article sur la haute disponibilité, etc…
Keepalived permet de faire deux choses distinctes :
•.Mise en place d’une IP virtuelle qui pourra changer de serveur en fonction de leur état (un peu à la manière de Hearbeat)
•.Mise en place de Loadbalancing (ceci dit, pas aussi complet qu’Haproxy, mais pour du LDAP, c’est largement suffisant.)
Comme je l’expliquais au préalable, nous allons rapidement l’installer et le configurer sans trop rentrer dans les détails, non pas que ça ne soit pas intéressant, mais ce n’est pas le sujet qui nous intéresse aujourd’hui. Pour le moment, on veut juste avoir nos serveurs Ldap accessible.
Sur nos deux serveurs, nous installons Keepalived :
ldapx# apt-get install keepalived
Sa configuration se trouvera dans /etc/keepalived qui, pour le moment est vide.
Nous allons commencer par la configuration la plus simple, la création d’une IP virtuelle qui se « baladera » entre nos deux serveurs LDAP en fonction de leur état.
Pour cela, créez sur les deux serveurs un fichier /etc/keepalived/keepalived.conf et remplissez le ainsi :
vrrp_script check_server_health {
script "/etc/keepalived/test_ldap.sh aaa.aaa.aaa.aaa" (mettre l'ip réel de votre serveur)
interval 2
fall 2
rise 2
}
vrrp_instance VI_LDAP {
state BACKUP
interface eth1
virtual_router_id 50
priority xxx (mettre 100 sur le serveur 1 et 10 par ex, sur le serveur 2)
advert_int 1
lvs_sync_daemon_interface eth1
authentication {
auth_type PASS
auth_pass MON_MOT_DE_PASSE_SECRET
}
track_script {
check_server_health
}
virtual_ipaddress {
XXX.XXX.XXX.XXX (mettre l'ip virtuelle de votre choix)
}
}
La valeur priority doit être adaptée. Elle doit être plus élevée sur votre serveur principal et plus faible sur le serveur secondaire.
Bien sur, vous remplacerez aaa.aaa.aaa.aaa par l’ip de votre serveur Ldap sur lequel vous êtes actuellement et xxx.xxx.xxx.xxx par l’ip virtuelle que vous aurez choisi.
Renseignez également la bonne interface dans les options interface et lvs_sync_daemon_interface en fonction de votre configuration (chez moi, eth1, pour le réseau inter-machines, l’eth0 étant pour les communications avec la gateway)
Il faut également créer le fichier qui va tester la santé de vos serveurs Ldap.
Créez donc un fichier (toujours sur les deux serveurs bien évidement) /etc/keepalived/test_ldap.sh et mettez ceci dedans :
#!/bin/bash
ldapsearch -x -H ldap://$1 -D cn=viewer,ou=system,dc=debugo,dc=fr -w motdepasse-b dc=debugo,dc=fr -l 3 > /dev/null 2>&1
ldapresponse=$?
if [ "$ldapresponse" -gt 0 ]; then
echo "down"
exit 1
else
echo "up"
fi
exit 0
Vous mettrez bien sur les valeurs adaptées à votre configuration. Keepalived attend une valeur à 0 si tout va bien et 1 si il y a une erreur.
Pensez à le rendre exécutable :
ldapx# chmod /etc/keepalived/test_ldap.sh +x
Ensuite, vous n’avez plus qu’à lancer sur les deux serveurs :
ldapx# service keepalived start
On peut vérifier l’état avec :
ldapx# service keepalived status
Sur le serveur principal, on fait un:
ldap1# ifconfig eth1
et …. rien !
En effet, keepalived passe par iproute2 et certaines données ne seront donc pas affichées avec la vieille commande ifconfig. Pour voir cette nouvelle IP, il faut donc faire :
ldap1# ip addr show dev eth1
Maintenant, testez… Si vous coupez le serveur 1, l’ip bascule sur le 2 et si le serveur 1 revient, l’IP revient dessus.
Dans notre configuration actuelle, tout le trafic arrivant sur notre ip virtuelle est relayé vers un seul serveur.
Que faire si nous voulons ajouter du loadbalancing et faire en sorte que nos deux serveurs soient ainsi sollicités ?
Rien de compliqué, ajoutez ce qui suit au fichier /etc/keepalived/keepalived.conf à la suite de ce que nous avons déjà mis :
[...]
virtual_server xxx.xxx.xxx.xxx 389 {
delay_loop 5
lb_algo wrr
lb_kind DR
persistence_timeout 0
protocol TCP
real_server aaa.aaa.aaa.aaa 389 {
weight 1
inhibit_on_failure
MISC_CHECK {
misc_path "/etc/keepalived/test.sh aaa.aaa.aaa.aaa"
}
connect_timeout 1
nb_get_retry 1
delay_before_retry 1
}
real_server bbb.bbb.bbb.bbb 389 {
weight 1
inhibit_on_failure
MISC_CHECK {
misc_path "/etc/keepalived/test.sh bbb.bbb.bbb.bbb"
}
connect_timeout 1
nb_get_retry 1
delay_before_retry 1
}
}
La, le complément du fichier sera le même sur les deux serveurs.
Modifiez simplement les adresses aaa.aaa.aaa.aaa et bbb.bbb.bbb.bbb par les adresses de vos serveurs Ldap et xxx.xxx.xxx.xxx par votre ip virtuelle.
On relance sur les deux serveurs :
ldapx# service keepalived restart
On va tester depuis une autre machine en installant ldap-utils :
test# apt-get ldap-utils
Puis, effectuez plusieurs fois :
test# ldapsearch -x -LLL -H ldap://ipvrituelle -D cn=admin,dc=debugo,dc=fr -w motdepasse-b cn=config "objectClass=olcGlobal" olcServerID
Tiens, curieux, une fois sur deux ça ne marche pas…
Mmm… Pourquoi donc…
Vous le savez, pour déboguer du réseau, tcpdump, c’est le bien. Du coup, on l’installe sur notre serveur qui ne répond pas (normalement, ce doit être le secondaire, vérifiez la réponse olcServerID) :
ldap2# apt-get install tcpdump
Et on va écouter un peu ce qui se passe :
ldap2# tcpdump -i eth1 port 389 -n
Puis relancer la commande sur la machine test. Entre les traces des paquets échangées entre les instances de Keepalived et le serveur Ldap, on doit voir des paquets émanant de votre machine de test et adressé à votre serveur sur l’IP Virtuelle….
Ha ! Il est la le problème !
Le serveur secondaire n’a pas cette IP (vu que pour le moment, elle est attribuée au serveur principal).
Donc, il nous suffit de rajouter un alias. Dans le fichier /etc/network/interfaces, ajoutez ceci :
auto lo:0
iface lo:0 inet static
address xxx.xxx.xxx.xxx
netmask 255.255.255.255
Pour l’activer de suite :
ldap2# if up lo:0
Cette manipulation est à faire également sur le serveur principal, au cas ou il perde l’IP virtuelle (ce ne devrait se produire que si Openldap tombe et du coup, n’étant plus loadbalancé par Keepalived, il ne devrait pas recevoir de requêtes, donc, manipulation en théorie inutile, mais je suis du genre prudent…)
On reste depuis notre machine de test :
test# ldapsearch -x -LLL -H ldap://ipvrituelle -D cn=admin,dc=debugo,dc=fr -w motdepasse-b cn=config "objectClass=olcGlobal" olcServerID
Et la, selon le serveur qui répond, la réponse olcServerID sera différente. Sur le reste par contre, ce sera transparent pour les clients.
Bingo !
Concernant Keepalived, on pourrait encore dire beaucoup de chose, mais comme promis, ce sera dans un article dédié à ces techniques (Haute Disponibilité, Load Balancing, etc…)