Serveur OpenLDAP

The Lightweight Directory Access Protocol, or LDAP, is a protocol for querying and modifying a X.500-based directory service running over TCP/IP. The current LDAP version is LDAPv3, as defined in RFC4510, and the LDAP implementation used in Ubuntu is OpenLDAP, currently at version 2.4.25 (Oneiric).

Ainsi, ce protocole accède aux répertoires LDAP. Voici quelques concepts et termes clé :

  • Un répertoire LDAP est une arborescence d'entrées de données de nature hiérarchique qui est appelée arborescence du répertoire d'information (DIT).

  • Une entrée se compose d'un ensemble d'attributs.

  • Un attribut possède un type (un nom/description) et une ou plusieurs valeurs.

  • Chaque attribut doit être défini dans au moins une classe d'objet.

  • Les attributs et classes d'objets sont définis dans les schémas (une classe d'objet est en fait considérée comme un type particulier d'attribut).

  • Chaque entrée possède un identifiant unique : son Nom distinctif (DN ou dn). Il s'agit de son Nom distinctif relatif (RDN), suivi par le DN (nom distinctif) de l'entrée parente.

  • Le DN de l'entrée n'est pas un attribut. Il n'est pas considéré comme faisant partie de l'entrée elle-même.

Les termes objet, conteneur et nœud ont une certaine connotations mais ils ont tous essentiellement la même signification que entrée, le terme techniquement correct.

Par exemple, ci-dessous, nous avons une entrée unique composée de 11 attributs. Son DN est « cn=John Doe,dc=exemple,dc=com » ; son RDN est « cn=John Doe » et son DN parent est « dc=exemple,dc=com ».

 dn: cn=John Doe,dc=example,dc=com
 cn: John Doe
 givenName: John
 sn: Doe
 telephoneNumber: +1 888 555 6789
 telephoneNumber: +1 888 555 1232
 mail: john@example.com
 manager: cn=Larry Smith,dc=example,dc=com
 objectClass: inetOrgPerson
 objectClass: organizationalPerson
 objectClass: person
 objectClass: top

L'entrée ci-dessus est au format LDIF (format d'échange de données LDAP). Toute information que vous fournirez dans votre DIT doit également être dans un tel format. Il est défini dans la RFC2849.

Although this guide will describe how to use it for central authentication, LDAP is good for anything that involves a large number of access requests to a mostly-read, attribute-based (name:value) backend. Examples include an address book, a list of email addresses, and a mail server's configuration.

Installation

Installez le démon du serveur OpenLDAP et les utilitaires de gestion traditionnels de LDAP. On les trouve respectivement dans les paquets slapd et ldap-utils.

The installation of slapd will create a working configuration. In particular, it will create a database instance that you can use to store your data. However, the suffix (or base DN) of this instance will be determined from the domain name of the localhost. If you want something different, edit /etc/hosts and replace the domain name with one that will give you the suffix you desire. For instance, if you want a suffix of dc=example,dc=com then your file would have a line similar to this:

127.0.1.1       nom_d'hote.example.com	nom-d'hote

Vous pouvez annuler la modification après l'installation du paquet.

Ce guide utilisera un suffixe de base de données tel que dc=exemple,dc=com.

Procédez à l'installation :

sudo apt-get install slapd ldap-utils

Since Ubuntu 8.10 slapd is designed to be configured within slapd itself by dedicating a separate DIT for that purpose. This allows one to dynamically configure slapd without the need to restart the service. This configuration database consists of a collection of text-based LDIF files located under /etc/ldap/slapd.d. This way of working is known by several names: the slapd-config method, the RTC method (Real Time Configuration), or the cn=config method. You can still use the traditional flat-file method (slapd.conf) but it's not recommended; the functionality will be eventually phased out.

Ubuntu utilise maintenant la méthode slapd-config pour la configuration de slapd et ce guide reflète cela.

During the install you were prompted to define administrative credentials. These are LDAP-based credentials for the rootDN of your database instance. By default, this user's DN is cn=admin,dc=example,dc=com. Also by default, there is no administrative account created for the slapd-config database and you will therefore need to authenticate externally to LDAP in order to access it. We will see how to do this later on.

De nos jours, certains schémas classiques (cosine, nis, inetorgperson) sont intégrés avec slapd. Il y a aussi un schéma « de base », un pré-requis pour que les schémas puissent fonctionner.

Inspection post-installation

Le processus d'installation met en place 2 DIT. Un pour slapd-config et un pour vos propres données (dc=exemple, dc=com). Jetons-y un coup d’œil.

  • C'est ce à quoi la base de données slapd-config/DIT ressemble. Rappelons que cette base de données est basée sur LDIF et réside dans /etc/ldap/slapd.d :

    
        /etc/ldap/slapd.d/
        /etc/ldap/slapd.d/cn=config
        /etc/ldap/slapd.d/cn=config/cn=module{0}.ldif
        /etc/ldap/slapd.d/cn=config/cn=schema
        /etc/ldap/slapd.d/cn=config/cn=schema/cn={0}core.ldif
        /etc/ldap/slapd.d/cn=config/cn=schema/cn={1}cosine.ldif
        /etc/ldap/slapd.d/cn=config/cn=schema/cn={2}nis.ldif
        /etc/ldap/slapd.d/cn=config/cn=schema/cn={3}inetorgperson.ldif
        /etc/ldap/slapd.d/cn=config/cn=schema.ldif
        /etc/ldap/slapd.d/cn=config/olcBackend={0}hdb.ldif
        /etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif
        /etc/ldap/slapd.d/cn=config/olcDatabase={-1}frontend.ldif
        /etc/ldap/slapd.d/cn=config/olcDatabase={1}hdb.ldif
        /etc/ldap/slapd.d/cn=config.ldif
    
    

    Ne pas modifier la base de données slapd-config directement. Effectuez des modifications via le protocole LDAP (utilitaires).

  • Voici ce à quoi le DIT slapd-config ressemble avec le protocole LDAP :

    sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn
    
    dn: cn=config
    
    dn: cn=module{0},cn=config
    
    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: olcBackend={0}hdb,cn=config
    
    dn: olcDatabase={-1}frontend,cn=config
    
    dn: olcDatabase={0}config,cn=config
    
    dn: olcDatabase={1}hdb,cn=config
    
    

    Explication des entrées :

    • cn=config : paramètres globaux

    • cn=module{0},cn=config : un module chargé dynamiquement

    • cn=schema,cn=config: contains hard-coded system-level schema

    • cn={0}core,cn=schema,cn=config: the hard-coded core schema

    • cn={1}cosine,cn=schema,cn=config : le schéma cosine

    • cn={2}nis,cn=schema,cn=config : le schéma nis

    • cn={3}inetorgperson,cn=schema,cn=config : le schéma inetorgperson

    • olcBackend={0}hdb,cn=config: the 'hdb' backend storage type

    • olcDatabase={-1}frontend,cn=config: frontend database, default settings for other databases

    • olcDatabase={0}config,cn=config : base de données de configuration slapd (cn=config)

    • olcDatabase={1}hdb,cn=config : votre exemple de base de données (dc=exemle,dc=com)

  • C'est ce à quoi le DIT de dc=exemple,dc=com ressemble :

    ldapsearch -x -LLL -H ldap:/// -b dc=example,dc=com dn
    
    dn: dc=example,dc=com
    
    dn: cn=admin,dc=example,dc=com
    
    

    Explication des entrées :

    • dc=example,dc=com : base du DIT

    • cn=admin,dc=exemple,dc=com : administrateur (rootDN) pour ce DIT (mis en place lors de l'installation du paquet)

Modification/Remplissage de votre base de données

Introduisons un peu de contenu dans notre base de données. Nous allons ajouter ce qui suit :

  • un nœud appelé Gens (pour stocker les utilisateurs)

  • un nœud appelé Groupes (pour stocker les groupes)

  • a group called miners

  • un utilisateur appelé john

Créez le fichier LDIF suivant et appelez le add_content.ldif :

dn: ou=People,dc=example,dc=com
objectClass: organizationalUnit
ou: People

dn: ou=Groups,dc=example,dc=com
objectClass: organizationalUnit
ou: Groups

dn: cn=miners,ou=Groups,dc=example,dc=com
objectClass: posixGroup
cn: miners
gidNumber: 5000

dn: uid=john,ou=People,dc=example,dc=com
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: john
sn: Doe
givenName: John
cn: John Doe
displayName: John Doe
uidNumber: 10000
gidNumber: 5000
userPassword: johnldap
gecos: John Doe
loginShell: /bin/bash
homeDirectory: /home/john

It's important that uid and gid values in your directory do not collide with local values. Use high number ranges, such as starting at 5000. By setting the uid and gid values in ldap high, you also allow for easier control of what can be done with a local user vs a ldap one. More on that later.

Ajouter le contenu :

ldapadd -x -D cn=admin,dc=example,dc=com -W -f add_content.ldif

Enter LDAP Password: ********
adding new entry "ou=People,dc=example,dc=com"

adding new entry "ou=Groups,dc=example,dc=com"

adding new entry "cn=miners,ou=Groups,dc=example,dc=com"

adding new entry "uid=john,ou=People,dc=example,dc=com"

Nous pouvons vérifier que l'information a été correctement ajoutée avec l'utilitaire ldapsearch :

ldapsearch -x -LLL -b dc=example,dc=com 'uid=john' cn gidNumber

dn: uid=john,ou=People,dc=example,dc=com
cn: John Doe
gidNumber: 5000

Explication des changements :

  • La liaison« simple » -x: ; n'utilisera pas la méthode SASL par défaut

  • -LLL: désactive les informations externes d'impression

  • uid=john : un « filtre » pour trouver l'utilisateur john

  • cn gidNumber : demande l'affichage de certains attributs (la valeur par défaut fait s'afficher tous les attributs)

Modification de la base de données de configuration slapd

Le DIT de slapd-config peut également être interrogé et modifié. Voici quelques exemples.

  • Utilisez ldapmodify pour ajouter un « Index » (attribut DbIndex) à votre base de données {1}hdb,cn=config (dc=exemple,dc=com). Créez un fichier que vous appellerez uid_index.ldif contenant ce qui suit :

    dn: olcDatabase={1}hdb,cn=config
    add: olcDbIndex
    olcDbIndex: uid eq,pres,sub
    

    Puis, exécutez la commande suivante :

    sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f uid_index.ldif
    
    modification de l'entrée « olcDatabase={1}hdb,cn=config »
    
    

    Vous pouvez confirmer le changement de cette manière :

    sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=config '(olcDatabase={1}hdb)' olcDbIndex
    
    dn: olcDatabase={1}hdb,cn=config
    olcDbIndex: objectClass eq
    olcDbIndex: uid eq,pres,sub
    
    
  • Ajoutons un schéma. Il devra d'abord être converti au format LDIF. Vous pouvez trouver des schémas non convertis, en plus de ceux convertis dans le dossier /etc/ldap/schema.

    • Il n'est pas courant de supprimer un schéma de la base de données slapd-config. Entrainez vous à l'ajout de schémas sur un système de test.

    • Before adding any schema, you should check which schemas are already installed (shown is a default, out-of-the-box output):

      sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=schema,cn=config dn
      
      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
      
      

    Dans l'exemple suivant, nous ajouterons le schéma CORBA.

    1. Créez le fichier de configuration de conversion schema_convert.conf contenant les lignes suivantes :

      include /etc/ldap/schema/core.schema
      include /etc/ldap/schema/collective.schema
      include /etc/ldap/schema/corba.schema
      include /etc/ldap/schema/cosine.schema
      include /etc/ldap/schema/duaconf.schema
      include /etc/ldap/schema/dyngroup.schema
      include /etc/ldap/schema/inetorgperson.schema
      include /etc/ldap/schema/java.schema
      include /etc/ldap/schema/misc.schema
      include /etc/ldap/schema/nis.schema
      include /etc/ldap/schema/openldap.schema
      include /etc/ldap/schema/ppolicy.schema
      include /etc/ldap/schema/ldapns.schema
      include /etc/ldap/schema/pmi.schema
      
    2. Créez le répertoire de sortie ldif_output.

    3. Déterminez l'index du schéma :

      slapcat -f schema_convert.conf -F ldif_output -n 0 | grep corba,cn=schema
      
      cn={1}corba,cn=schema,cn=config
      
      

      When slapd ingests objects with the same parent DN it will create an index for that object. An index is contained within braces: {X}.

    4. Utilisez slapcat pour effectuer la conversion :

      slapcat -f schema_convert.conf -F ldif_output -n0 -H \ ldap:///cn={1}corba,cn=schema,cn=config -l cn=corba.ldif
      

      Le schéma converti est maintenant dans cn=corba.ldif

    5. Modifiez cn=corba.ldif pour atteindre les attributs suivants :

      dn: cn=corba,cn=schema,cn=config
      ...
      cn: corba
      

      Supprimez également les lignes suivantes à partir du bas :

      structuralObjectClass: olcSchemaConfig
      entryUUID: 52109a02-66ab-1030-8be2-bbf166230478
      creatorsName: cn=config
      createTimestamp: 20110829165435Z
      entryCSN: 20110829165435.935248Z#000000#000#000000
      modifiersName: cn=config
      modifyTimestamp: 20110829165435Z
      

      Vos valeurs d'attributs varieront.

    6. Enfin, utilisez ldapadd pour ajouter le nouveau schéma au DIT slapd-config :

      sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f cn\=corba.ldif
      
      ajout de nouvelle entrée « cn=corba,cn=schema,cn=config »
      
      
    7. Confirmez les schémas actuellement chargés :

      sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=schema,cn=config dn
      
      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}corba,cn=schema,cn=config
      
      

For external applications and clients to authenticate using LDAP they will each need to be specifically configured to do so. Refer to the appropriate client-side documentation for details.

Journal

Activity logging for slapd is indispensible when implementing an OpenLDAP-based solution yet it must be manually enabled after software installation. Otherwise, only rudimentary messages will appear in the logs. Logging, like any other slapd configuration, is enabled via the slapd-config database.

OpenLDAP comes with multiple logging subsystems (levels) with each one containing the lower one (additive). A good level to try is stats. The slapd-config man page has more to say on the different subsystems.

Créez le fichier logging.ldif avec le contenu suivant :

dn: cn=config
changetype: modify
add: olcLogLevel
olcLogLevel: stats

Appliquez le changement :

sudo ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f logging.ldif

This will produce a significant amount of logging and you will want to throttle back to a less verbose level once your system is in production. While in this verbose mode your host's syslog engine (rsyslog) may have a hard time keeping up and may drop messages:

rsyslogd-2177 : imuxsock a perdu 228 messages du pid 2547 à cause de la limitation de débit

Vous pouvez envisager un changement dans la configuration de rsyslog. Dans /etc/rsyslog.conf, entrez :

# Désactivez la limitation de débit
# (la limitation par défaut est de 200 messages en 5 secondes ; ci-dessous nous faisons que le 5 devienne 0)
$SystemLogRateLimitInterval 0

Et puis redémarrez le démon rsyslog :

sudo service rsyslog restart

Réplication

The LDAP service becomes increasingly important as more networked systems begin to depend on it. In such an environment, it is standard practice to build redundancy (high availability) into LDAP to prevent havoc should the LDAP server become unresponsive. This is done through LDAP replication.

Replication is achieved via the Syncrepl engine. This allows changes to be synchronized using a Consumer - Provider model. The specific kind of replication we will implement in this guide is a combination of the following modes: refreshAndPersist and delta-syncrepl. This has the Provider push changed entries to the Consumer as soon as they're made but, in addition, only actual changes will be sent, not entire entries.

Configuration du fournisseur

Commencez par configurer le Fournisseur.

  1. Créez un fichier LDIF avec le contenu suivant et nommez-le provider_sync.ldif :

    # Add indexes to the frontend db.
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: entryCSN eq
    -
    add: olcDbIndex
    olcDbIndex: entryUUID eq
    
    #Load the syncprov and accesslog modules.
    dn: cn=module{0},cn=config
    changetype: modify
    add: olcModuleLoad
    olcModuleLoad: syncprov
    -
    add: olcModuleLoad
    olcModuleLoad: accesslog
    
    # Accesslog database definitions
    dn: olcDatabase={2}hdb,cn=config
    objectClass: olcDatabaseConfig
    objectClass: olcHdbConfig
    olcDatabase: {2}hdb
    olcDbDirectory: /var/lib/ldap/accesslog
    olcSuffix: cn=accesslog
    olcRootDN: cn=admin,dc=example,dc=com
    olcDbIndex: default eq
    olcDbIndex: entryCSN,objectClass,reqEnd,reqResult,reqStart
    
    # Accesslog db syncprov.
    dn: olcOverlay=syncprov,olcDatabase={2}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpNoPresent: TRUE
    olcSpReloadHint: TRUE
    
    # syncrepl Provider for primary db
    dn: olcOverlay=syncprov,olcDatabase={1}hdb,cn=config
    changetype: add
    objectClass: olcOverlayConfig
    objectClass: olcSyncProvConfig
    olcOverlay: syncprov
    olcSpNoPresent: TRUE
    
    # accesslog overlay definitions for primary db
    dn: olcOverlay=accesslog,olcDatabase={1}hdb,cn=config
    objectClass: olcOverlayConfig
    objectClass: olcAccessLogConfig
    olcOverlay: accesslog
    olcAccessLogDB: cn=accesslog
    olcAccessLogOps: writes
    olcAccessLogSuccess: TRUE
    # scan the accesslog DB every day, and purge entries older than 7 days
    olcAccessLogPurge: 07+00:00 01+00:00
    

    Changer le rootDN dans le fichier LDIF pour qu'il corresponde à celui que vous avez pour votre répertoire.

  2. Le profil apparmor pour slapd devra être ajusté en ce qui concerne l'emplacement du journal d’accès de la base de données. Modifiez /etc/apparmor.d/local/usr.sbin.slapd en ajoutant ce qui suit :

    /var/lib/ldap/accesslog/ r,
    /var/lib/ldap/accesslog/** rwk,
    

    Créez un répertoire, mettez en place un fichier de configuration de base de données, et rechargez le profil apparmor :

    sudo -u openldap mkdir /var/lib/ldap/accesslog
    sudo -u openldap cp /var/lib/ldap/DB_CONFIG /var/lib/ldap/accesslog
    sudo service apparmor reload
    
  3. Ajoutez le nouveau contenu et, en raison du changement dans apparmor, redémarrez le démon :

    sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f provider_sync.ldif
    sudo service slapd restart
    

Le fournisseur est maintenant configuré.

Configuration de l'utilisateur

Et maintenant configurez le Consumer (Consommateur).

  1. Installez le logiciel en passant par Installation. Assurez-vous que la base de données slapd-config est identique à celle du fournisseur. En particulier, assurez-vous que les schémas et le suffixe de base de données sont les mêmes.

  2. Créez un fichier LDIF avec le contenu suivant et nommez-le consumer_sync.ldif :

    dn: cn=module{0},cn=config
    changetype: modify
    add: olcModuleLoad
    olcModuleLoad: syncprov
    
    dn: olcDatabase={1}hdb,cn=config
    changetype: modify
    add: olcDbIndex
    olcDbIndex: entryUUID eq
    -
    add: olcSyncRepl
    olcSyncRepl: rid=0 provider=ldap://ldap01.exemple.com bindmethod=simple binddn="cn=admin,dc=exemple,dc=com" 
     credentials=secret searchbase="dc=exemple,dc=com" logbase="cn=accesslog" 
     logfilter="(&(objectClass=auditWriteObject)(reqResult=0))" schemachecking=on 
     type=refreshAndPersist retry="60 +" syncdata=accesslog
    -
    add: olcUpdateRef
    olcUpdateRef: ldap://ldap01.exemple.com
    

    Vérifiez que les attributs suivants ont les bonnes valeurs :

    • fournisseur (nom d’hôte du serveur fournisseur -- ldap01.exemple.com dans cet exemple -- ou l'adresse IP)

    • binddn (le DN administrateur que vous utilisez)

    • credentials (le mot de passe administrateur DN que vous utilisez)

    • searchbase (le suffixe de base de données que vous utilisez)

    • olcUpdateRef (nom d’hôte du serveur fournisseur ou adresse IP)

    • rid (réplique d'identifiant unique à 3 chiffres qui définie la réplique. Chaque utilisateur devrait avoir au moins une réplique d'identifiant)

  3. Ajoutez le nouveau contenu :

    sudo ldapadd -Q -Y EXTERNAL -H ldapi:/// -f consumer_sync.ldif
    

Vous avez terminé. Les deux bases de données (suffixe : dc=exemple,dc=com) devraient maintenant se synchroniser.

Tests

Une fois que la réplication démarre, vous pouvez la suivre en exécutant

ldapsearch -z1 -LLLQY EXTERNAL -H ldapi:/// -s base -b dc=exemple,dc=com contextCSN

dn: dc=example,dc=com
contextCSN: 20120201193408.178454Z#000000#000#000000

sur le fournisseur et l'utilisateur. Une fois que la sortie (20120201193408.178454Z#000000#000#000000 dans l'exemple ci-dessus) correspond aux deux machines, vous avez la réplication. Chaque fois qu'une modification est effectuée pour le fournisseur, cette valeur changera, ainsi que celle des utilisateurs.

If your connection is slow and/or your ldap database large, it might take a while for the consumer's contextCSN match the provider's. But, you will know it is progressing since the consumer's contextCSN will be steadly increasing.

If the consumer's contextCSN is missing or does not match the provider, you should stop and figure out the issue before continuing. Try checking the slapd (syslog) and the auth log files in the provider to see if the consumer's authentication requests were successful or its requests to retrieve data (they look like a lot of ldapsearch statements) return no errors.

To test if it worked simply query, on the Consumer, the DNs in the database:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b dc=example,dc=com dn

You should see the user 'john' and the group 'miners' as well as the nodes 'People' and 'Groups'.

Contrôle d'accès

The management of what type of access (read, write, etc) users should be granted to resources is known as access control. The configuration directives involved are called access control lists or ACL.

When we installed the slapd package various ACL were set up automatically. We will look at a few important consequences of those defaults and, in so doing, we'll get an idea of how ACLs work and how they're configured.

To get the effective ACL for an LDAP query we need to look at the ACL entries of the database being queried as well as those of the special frontend database instance. The ACLs belonging to the latter act as defaults in case those of the former do not match. The frontend database is the second to be consulted and the ACL to be applied is the first to match ("first match wins") among these 2 ACL sources. The following commands will give, respectively, the ACLs of the hdb database ("dc=example,dc=com") and those of the frontend database:

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=config '(olcDatabase={1}hdb)' olcAccess

dn: olcDatabase={1}hdb,cn=config
olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous
              auth by dn="cn=admin,dc=example,dc=com" write by * none
olcAccess: {1}to dn.base="" by * read
olcAccess: {2}to * by self write by dn="cn=admin,dc=example,dc=com" write by *
  read

The rootDN always has full rights to it's database. Including it in an ACL does provide an explicit configuration but it also causes slapd to incur a performance penalty.

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=config '(olcDatabase={-1}frontend)' olcAccess

dn: olcDatabase={-1}frontend,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,
              cn=external,cn=auth manage by * break
olcAccess: {1}to dn.exact="" by * read
olcAccess: {2}to dn.base="cn=Subschema" by * read

La toute première ACL est cruciale :

olcAccess: {0}to attrs=userPassword,shadowLastChange by self write by anonymous
              auth by dn="cn=admin,dc=example,dc=com" write by * none

Ceci peut être représenté différemment pour une digestion plus facile :

to attrs=userPassword
	by self write
	by anonymous auth
	by dn="cn=admin,dc=example,dc=com" write
	by * none

to attrs=shadowLastChange
	by self write
	by anonymous auth
	by dn="cn=admin,dc=example,dc=com" write
	by * none

Cette ACL composée (il y en a deux) implique ce qui suit :

  • Anonymous 'auth' access is provided to the userPassword attribute for the initial connection to occur. Perhaps counter-intuitively, 'by anonymous auth' is needed even when anonymous access to the DIT is unwanted. Once the remote end is connected, howerver, authentication can occur (see next point).

  • Authentication can happen because all users have 'read' (due to 'by self write') access to the userPassword attribute.

  • L'attribut Mot_de_passe_utilisateur est par ailleurs inaccessible aux autres utilisateurs, à l'exception de rootDN, qui a l’accès complet à celui-ci.

  • Pour permettre aux utilisateurs de changer leurs mots de passe en utilisant la commande passwd ou d'autres utilitaires, l'attribut shadowLastChange doit être accessible une fois qu'un utilisateur s'est authentifié.

This DIT can be searched anonymously because of 'by * read' in this ACL:

to *
	by self write
	by dn="cn=admin,dc=example,dc=com" write
	by * read

Si ce n'est pas désiré, il vous faut modifier les ACLs. Pour forcer l'authentification lors d'une demande de liaison, vous pouvez alternativement (ou en combinaison avec l'ACL modifiée) utiliser la directive « olcRequire: authc ».

Comme mentionné précédemment, il n'existe pas de compte administrateur créé pour la base de données slapd-config. Il y a cependant une identité SASL accordée pour un accès complet à celle-ci. Il représente le super-utilisateur de l'hôte local (root/sudo). Le voici :

dn.exact=gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth 

La commande suivante affichera les ACL (listes de contrôle d’accès) de la base de données slapd-config :

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=config '(olcDatabase={0}config)' olcAccess

dn: olcDatabase={0}config,cn=config
olcAccess: {0}to * by dn.exact=gidNumber=0+uidNumber=0,cn=peercred,
              cn=external,cn=auth manage by * break

Since this is a SASL identity we need to use a SASL mechanism when invoking the LDAP utility in question and we have seen it plenty of times in this guide. It is the EXTERNAL mechanism. See the previous command for an example. Note that:

  1. You must use sudo to become the root identity in order for the ACL to match.

  2. Le mécanisme EXTERNE fonctionne via IPC (sockets de domaine UNIX). Cela signifie que vous devez utiliser le format URI ldapi.

Voici une façon rapide d'obtenir toutes les ACL :

sudo ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b \ cn=config '(olcAccess=*)' olcAccess olcSuffix

Il y a beaucoup à dire sur le sujet du contrôle d'accès. Voir la page de manuel sur les accès.slapd.

TLS

Pour s'authentifier sur un serveur OpenLDAP, il est préférable d'utiliser une session chiffrée. Cela peut être accompli en utilisant le protocole TLS (Transport Layer Security).

Ici, nous serons notre propre autorité de certification (CA), puis nous allons créer et signer notre certificat de serveur LDAP en tant que CA. Puisque slapd est compilé avec la bibliothèque gnutls, nous utiliserons l'utilitaire certtool pour effectuer ces tâches.

  1. Installez les paquets gnutls-bin et ssl-cert :

    sudo apt-get install gnutls-bin ssl-cert
    
  2. Créer une clé privée pour l'autorité de certification :

    sudo sh -c "certtool --generate-privkey > /etc/ssl/private/cakey.pem"
    
  3. Créez le modèle ou le fichier /etc/ssl/ca.info pour définir le CA :

    cn = Entreprise Exemple
    ca
    cert_signing_key
    
  4. Créer le certificat d'autorité de certification auto-signé :

    sudo certtool --generate-self-signed \ --load-privkey /etc/ssl/private/cakey.pem \ --template /etc/ssl/ca.info \ --outfile /etc/ssl/certs/cacert.pem
    
  5. Créer une clef privée pour le serveur :

    sudo certtool --generate-privkey \ --bits 1024 \ --outfile /etc/ssl/private/ldap01_slapd_key.pem
    

    Replace ldap01 in the filename with your server's hostname. Naming the certificate and key for the host and service that will be using them will help keep things clear.

  6. Créez le fichier d'informations /etc/ssl/ldap01.info contenant :

    organization = Compagnie Exemple
    cn = ldap01.example.com
    tls_www_server
    encryption_key
    signing_key
    expiration_days = 3650
    

    Le certificat ci-dessus est valable pendant 10 ans. Ajustez en conséquence.

  7. Créer le certificat du serveur :

    sudo certtool --generate-certificate \ --load-privkey /etc/ssl/private/ldap01_slapd_key.pem \ --load-ca-certificate /etc/ssl/certs/cacert.pem \ --load-ca-privkey /etc/ssl/private/cakey.pem \ --template /etc/ssl/ldap01.info \ --outfile /etc/ssl/certs/ldap01_slapd_cert.pem
    

Créez le fichier certinfo.ldif avec le contenu suivant (ajustez en conséquence, notre exemple suppose que nous avons créé les certificats en utilisant https://www.cacert.org) :

dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
-
add: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ssl/certs/ldap01_slapd_cert.pem
-
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ssl/private/ldap01_slapd_key.pem

Utilisez la commande ldapmodify pour informer slapd de notre emploi de TLS via la base de données slapd-config :

sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f /etc/ssl/certinfo.ldif

Contrairement à la croyance populaire, vous n'avez pas besoin de ldaps :// dans /etc/default/slapd pour utiliser le chiffrement. Vous devriez avoir seulement :

SLAPD_SERVICES="ldap:/// ldapi:///"

LDAP over TLS/SSL (ldaps://) is deprecated in favour of StartTLS. The latter refers to an existing LDAP session (listening on TCP port 389) becoming protected by TLS/SSL whereas LDAPS, like HTTPS, is a distinct encrypted-from-the-start protocol that operates over TCP port 636.

Resserrez la propriété et les autorisations :

sudo adduser openldap ssl-cert
sudo chgrp ssl-cert /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod g+r /etc/ssl/private/ldap01_slapd_key.pem
sudo chmod o-r /etc/ssl/private/ldap01_slapd_key.pem

Redémarrez OpenLDAP :

sudo service slapd restart

Consultez les fichiers de journalisation de votre hôte (/var/log/syslog) pour voir si le serveur a démarré correctement.

Réplication et TLS

If you have set up replication between servers, it is common practice to encrypt (StartTLS) the replication traffic to prevent evesdropping. This is distinct from using encryption with authentication as we did above. In this section we will build on that TLS-authentication work.

The assumption here is that you have set up replication between Provider and Consumer according to Réplication and have configured TLS for authentication on the Provider by following TLS.

As previously stated, the objective (for us) with replication is high availablity for the LDAP service. Since we have TLS for authentication on the Provider we will require the same on the Consumer. In addition to this, however, we want to encrypt replication traffic. What remains to be done is to create a key and certificate for the Consumer and then configure accordingly. We will generate the key/certificate on the Provider, to avoid having to create another CA certificate, and then transfer the necessary material over to the Consumer.

  1. Sur le fournisseur,

    Créez un répertoire (qui sera utilisé pour le transfert éventuel), puis la clé privée de l'utilisateur :

    mkdir ldap02-ssl
    cd ldap02-ssl
    sudo certtool --generate-privkey \ --bits 1024 \ --outfile ldap02_slapd_key.pem
    

    Créez un fichier info, ldap02.info, pour le serveur utilisateur, en ajustant ses valeurs en conséquence :

    organization = Compagnie Exemple
    cn = ldap02.example.com
    tls_www_server
    encryption_key
    signing_key
    expiration_days = 3650
    

    Créer le certificat du consommateur :

    sudo certtool --generate-certificate \ --load-privkey ldap02_slapd_key.pem \ --load-ca-certificate /etc/ssl/certs/cacert.pem \ --load-ca-privkey /etc/ssl/private/cakey.pem \ --template ldap02.info \ --outfile ldap02_slapd_cert.pem
    

    Obtenir une copie du certificat CA :

    cp /etc/ssl/certs/cacert.pem .
    

    Nous avons terminé. Maintenant transférez le répertoire ldap02-ssl à l'utilisateur. Ici, nous utilisons scp (ajustez en conséquence) :

    cd ..
    scp -r ldap02-ssl utilisateur@consumer :
    
  2. Sur l'utilisateur,

    Configurer l'authentification TLS :

    sudo apt-get install ssl-cert
    sudo adduser openldap ssl-cert
    sudo cp ldap02_slapd_cert.pem cacert.pem /etc/ssl/certs
    sudo cp ldap02_slapd_key.pem /etc/ssl/private
    sudo chgrp ssl-cert /etc/ssl/private/ldap02_slapd_key.pem
    sudo chmod g+r /etc/ssl/private/ldap02_slapd_key.pem
    sudo chmod o-r /etc/ssl/private/ldap02_slapd_key.pem
    

    Créez le fichier /etc/ssl/certinfo.ldif avec le contenu suivant (ajustez en conséquence) :

    dn: cn=config
    add: olcTLSCACertificateFile
    olcTLSCACertificateFile: /etc/ssl/certs/cacert.pem
    -
    add: olcTLSCertificateFile
    olcTLSCertificateFile: /etc/ssl/certs/ldap02_slapd_cert.pem
    -
    add: olcTLSCertificateKeyFile
    olcTLSCertificateKeyFile: /etc/ssl/private/ldap02_slapd_key.pem
    

    Configurer la base de données slapd-config :

    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f certinfo.ldif
    

    Configurez /etc/default/slapd comme sur le fournisseur (SLAPD_SERVICES).

  3. Sur l'utilisateur,

    Configure TLS for Consumer-side replication. Modify the existing olcSyncrepl attribute by tacking on some TLS options. In so doing, we will see, for the first time, how to change an attribute's value(s).

    Créez le fichier utilisateur_sync_tls.ldif avec le contenu suivant :

    dn: olcDatabase={1}hdb,cn=config
    replace: olcSyncRepl
    olcSyncRepl: rid=0 provider=ldap://ldap01.example.com bindmethod=simple
     binddn="cn=admin,dc=example,dc=com" credentials=secret searchbase="dc=example,dc=com"
     logbase="cn=accesslog" logfilter="(&(objectClass=auditWriteObject)(reqResult=0))"
     schemachecking=on type=refreshAndPersist retry="60 +" syncdata=accesslog
     starttls=critical tls_reqcert=demand
    

    The extra options specify, respectively, that the consumer must use StartTLS and that the CA certificate is required to verify the Provider's identity. Also note the LDIF syntax for changing the values of an attribute ('replace').

    Mettre en œuvre ces changements :

    sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f consumer_sync_tls.ldif
    

    Et redémarrez slapd :

    sudo service slapd restart
    
  4. Sur le fournisseur,

    Check to see that a TLS session has been established. In /var/log/syslog, providing you have 'conns'-level logging set up, you should see messages similar to:

    slapd[3620]: conn=1047 fd=20 ACCEPT from IP=10.153.107.229:57922 (IP=0.0.0.0:389)
    slapd[3620]: conn=1047 op=0 EXT oid=1.3.6.1.4.1.1466.20037
    slapd[3620]: conn=1047 op=0 STARTTLS
    slapd[3620]: conn=1047 op=0 RESULT oid= err=0 text=
    slapd[3620]: conn=1047 fd=20 TLS established tls_ssf=128 ssf=128
    slapd[3620]: conn=1047 op=1 BIND dn="cn=admin,dc=example,dc=com" method=128
    slapd[3620]: conn=1047 op=1 BIND dn="cn=admin,dc=example,dc=com" mech=SIMPLE ssf=0
    slapd[3620]: conn=1047 op=1 RESULT tag=97 err=0 text
    

Authentification LDAP

Une fois que vous avez un serveur LDAP fonctionnel, vous devrez installer des bibliothèques sur le client qui saura comment et quand les contacter. Sur Ubuntu, ceci a été traditionnellement fait par l'installation du paquet libnss-ldap. Ce paquet apportera d'autres outils qui vous assisteront dans l'étape de configuration. Maintenant, installez ce paquet :

sudo apt-get install libnss-ldap

Vous serez invité à entrer les détails de votre serveur LDAP. Si vous faites une erreur, vous pouvez essayer à nouveau en utilisant :

sudo dpkg-reconfigure ldap-auth-config

Le résultat de la configuration est visible dans /etc/ldap.conf. Si votre serveur requiert des options non couvertes par l'assistant, modifiez ce fichier en conséquence.

Maintenant, configurez le profil LDAP pour NSS :

sudo auth-client-config -t nss -p lac_ldap

Configurez le système pour qu'il utilise LDAP pour l'authentification :

sudo pam-auth-update

Dans le menu, choisissez LDAP et les autres mécanismes d'authentification dont vous avez besoin.

Vous devriez maintenant être capable de vous connecter en utilisant les informations d'identification basées sur LDAP.

Les clients LDAP devront se référer à plusieurs serveurs si la réplication est en cours d'utilisation. Dans /etc/ldap.conf, vous devriez avoir quelque chose comme :

uri ldap://ldap01.example.com ldap://ldap02.example.com

The request will time out and the Consumer (ldap02) will attempt to be reached if the Provider (ldap01) becomes unresponsive.

Si vous envisagez d'utiliser LDAP pour stocker les utilisateurs Samba, vous devrez configurer le serveur Samba pour qu'il s'authentifie en utilisant LDAP. Voir Samba et LDAP pour plus de détails.

Une alternative au paquet libnss-ldap est libnss-ldapd. Cependant, ceci apportera le paquet nscd qui est probablement indésirable. Il vous suffit de le retirer par la suite.

Gestion des groupes et utilisateurs

The ldap-utils package comes with enough utilities to manage the directory but the long string of options needed can make them a burden to use. The ldapscripts package contains wrapper scripts to these utilities that some people find easier to use.

Installez le paquet :

sudo apt-get install ldapscripts

Puis éditez le fichier /etc/ldapscripts/ldapscripts.conf pour arriver à quelque chose de semblable à ce qui suit :

SERVER=localhost
BINDDN='cn=admin,dc=example,dc=com'
BINDPWDFILE="/etc/ldapscripts/ldapscripts.passwd"
SUFFIX='dc=example,dc=com'
GSUFFIX='ou=Groups'
USUFFIX='ou=People'
MSUFFIX='ou=Computers'
GIDSTART=10000
UIDSTART=10000
MIDSTART=10000

Maintenant, créez le fichier ldapscripts.passwd pour permettre l'accès de rootDN au répertoire :

sudo sh -c "echo -n 'secret' > /etc/ldapscripts/ldapscripts.passwd"
sudo chmod 400 /etc/ldapscripts/ldapscripts.passwd

Remplacez « secret » par le mot de passe actuel de l'utilisateur rootdn de votre base de données.

Les scripts sont maintenant prêts à vous aider à gérer votre répertoire. Voici quelques exemples de la façon de les utiliser :

  • Créez un nouvel utilisateur :

    sudo ldapadduser laurence exemple
    

    Ceci créera un utilisateur ayant pour UID laurence et pour groupe primaire (GID) exemple.

  • Modifiez un mot de passe utilisateur :

    sudo ldapsetpasswd laurence
    Modifier le mot de passe de l'utilisateur uid=laurence,ou=People,dc=example,dc=com
    Nouveau mot de passe : 
    Nouveau mot de passe (vérification) : 
    
  • Supprimer un utilisateur :

    sudo ldapdeleteuser laurence
    
  • Ajouter un groupe :

    sudo ldapaddgroup qa
    
  • Supprimer un groupe :

    sudo ldapdeletegroup qa
    
  • Ajouter un utilisateur à un groupe :

    sudo ldapaddusertogroup laurence qa
    

    Vous devez avoir maintenant un attribut memberUid ayant pour valeur laurence pour le groupe qa.

  • Supprimer un utilisateur d'un groupe :

    sudo ldapdeleteuserfromgroup laurence qa
    

    L'attribut memberUid ne doit plus apparaître dans le groupe qa group.

  • Le script ldapmodifyuser vous permet d'ajouter, supprimer ou modifier les attributs des utilisateurs. Il utilise la même syntaxe que ldapmodify. Par exemple :

    sudo ldapmodifyuser laurence
    # About to modify the following entry :
    dn: uid=laurence,ou=People,dc=example,dc=com
    objectClass: account
    objectClass: posixAccount
    cn: george
    uid: george
    uidNumber: 1001
    gidNumber: 1001
    homeDirectory: /home/laurence
    loginShell: /bin/bash
    gecos: george
    description: User account
    userPassword:: e1NTSEF9eXFsTFcyWlhwWkF1eGUybVdFWHZKRzJVMjFTSG9vcHk=
    
    # Enter your modifications here, end with CTRL-D.
    dn: uid=laurence,ou=People,dc=example,dc=com
    replace: gecos
    gecos: Laurence Bibot
    

    Le gecos de l'utilisateur doit être maintenant « Laurence Bibot ».

  • L'une des fonctionnalités intéressantes de ldapscripts est son système de modèles qui permettent de personnaliser les attributs d'utilisateur, de groupe et des objets machine. Par exemple, pour activer le modèle utilisateur, modifiez /etc/ldapscripts/ldapscripts.conf en changeant :

    UTEMPLATE="/etc/ldapscripts/ldapadduser.template"
    

    Des modèles types se trouvent dans le répertoire /etc/ldapscripts. Copiez ou renommer le fichier ldapadduser.template.sample en /etc/ldapscripts/ldapadduser.template :

    sudo cp /usr/share/doc/ldapscripts/examples/ldapadduser.template.sample \ /etc/ldapscripts/ldapadduser.template
    

    Modifiez le nouveau modèle pour ajouter les attributs désirés. Ce qui suit va créer de nouveaux utilisateurs avec un objectClass de inetOrgPerson :

    dn: uid=<user>,<usuffix>,<suffix>
    objectClass: inetOrgPerson
    objectClass: posixAccount
    cn: <user>
    sn: <ask>
    uid: <user>
    uidNumber: <uid>
    gidNumber: <gid>
    homeDirectory: <home>
    loginShell: <shell>
    gecos: <user>
    description: User account
    title: Employee
    

    Remarquez l'option <ask> utilisée pour l'attribut sn. Cela fera que ldapadduser vous demandera sa valeur.

Il existe des utilitaires dans le paquet qui n'ont pas été abordés ici. En voici la liste complète :

Archivage et restauration

ldap tourne maintenant tout juste comme nous le voulons, il est temps de s'assurer que nous pouvons enregistrer l'ensemble de notre travail et le restaurer si nécessaire.

What we need is a way to backup the ldap database(s), specifically the backend (cn=config) and frontend (dc=example,dc=com). If we are going to backup those databases into, say, /export/backup, we could use slapcat as shown in the following script, called /usr/local/bin/ldapbackup:

#!/bin/bash

BACKUP_PATH=/export/backup
SLAPCAT=/usr/sbin/slapcat

nice ${SLAPCAT} -n 0 > ${BACKUP_PATH}/config.ldif
nice ${SLAPCAT} -n 1 > ${BACKUP_PATH}/example.com.ldif
nice ${SLAPCAT} -n 2 > ${BACKUP_PATH}/access.ldif
chmod 640 ${BACKUP_PATH}/*.ldif

These files are uncompressed text files containing everything in your ldap databases including the tree layout, usernames, and every password. So, you might want to consider making /export/backup an encrypted partition and even having the script encrypt those files as it creates them. Ideally you should do both, but that depends on your security requirements.

Then, it is just a matter of having a cron script to run this program as often as we feel comfortable with. For many, once a day suffices. For others, more often is required. Here is an example of a cron script called /etc/cron.d/ldapbackup that is run every night at 22:45h:

MAILTO=backup-emails@domain.com
45 22 * * *  root    /usr/local/bin/ldapbackup

Les fichiers étant créés, ils doivent être copiés sur un serveur de sauvegarde.

En supposant que nous ayons fait une réinstallation fraîche de ldap, le processus de restauration pourrait être quelque chose comme ceci :

sudo service slapd stop
sudo mkdir /var/lib/ldap/accesslog
sudo slapadd -F /etc/ldap/slapd.d -n 0 -l /export/backup/config.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 1 -l /export/backup/domain.com.ldif
sudo slapadd -F /etc/ldap/slapd.d -n 2 -l /export/backup/access.ldif
sudo chown -R openldap:openldap /etc/ldap/slapd.d/
sudo chown -R openldap:openldap /var/lib/ldap/
sudo service slapd start

Ressources