Post

Mise en place d'OpenLDAP avec Proxmox

Dans cet article, nous allons voir comment installer et configurer OpenLDAP sous Proxmox. Nous allons dans un premier temps mettre en place le serveur avant de nous pencher sur la configuration du client. Notre architecture est la suivante :

  • 1 instance Proxmox (PM1) contenant un conteneur exécutant le serveur OpenLDAP (serveur).
  • 1 instance Proxmox (PM2), cliente OpenLDAP.
  • 1 domaine lab.loc.

Commençons par l’installation et la configuration du serveur.

Installer le serveur

L’installation du serveur passe par la création du conteneur qui va héberger le serveur OpenLDAP sur PM1. À partir de la console de l’hyperviseur, nous pouvons donc télécharger une image Linux (Debian) pour conteneur. La commande suivante permet de créer un nouveau conteneur sur l’hyperviseur.

1
bash -c "$(curl -fsSL https://raw.githubusercontent.com/community-scripts/ProxmoxVE/main/ct/debian.sh)"

Installer et configurer l’annuaire

Maintenant que le serveur est en place, nous pouvons installer le service LDAP.

slapd

Installer

slapd est le processus réseau qui attend les requêtes des clients de l’annuaire pour lire ou écrire dans la base de données de cet annuaire. Une bonne pratique est de créer un utilisateur openldap, qui va faire tourner slapd et gérer le dossier /var/lib/ldap, qui répertorie les fichiers composant la base de données.

1
2
3
useradd openldap
mkdir /var/lib/ldap
chown openldap:openldap /var/lib/ldap

Une fois l’utilisateur ajouté, nous pouvons installer slapd.

1
apt-get -y install slapd

Configurer

Nous allons maintenant configurer slapd, en renseignant les informations dont le service a besoin pour s’exécuter.

1
dpkg-reconfigure slapd

Les menus ncurses apparaissent alors, et nous pouvons renseigner successivement :

  • No, pour configurer slapd.
  • lab.loc, pour fixer la racine de l’annuaire (= domaine DNS).
  • lab.loc, pour fixer l’attribut organization de la racine.
  • <mdp>, pour le mot de passe de l’administrateur de l’annuaire.
  • MDB, pour le moteur de base de données.
  • Non, pour limiter la purge.
  • Yes, pour sauvegarder la base de données actuelle.

Nous démarrons et activons ensuite slapd, de manière à ce qu’il s’exécute, même après redémarrage.

1
2
systemctl start slapd
systemctl enable slapd

Tester

Nous vérifions que le service écoute sur le port 389.

1
ss -laputn | grep slapd

S’il apparaît, nous vérifions ensuite que slapd est lancé avec les bons arguments :

1
cat /var/run/slapd/slapd.args
  • -h ldap:/// ldapi:///, pour accepter les connexions en clair et en local à la machine.
  • -g openldap -u openldap, qui définissent l’identité sous laquelle tourne le processus.
  • -F /etc/ldap/slapd.d, qui donne l’emplacement de la configuration de slapd.

Si tout est bon, nous pouvons requêter l’annuaire.

1
2
apt-get install -y ldap-utils
ldapsearch -x -H ldap://<hostname>.lab.loc -b 'dc=lab,dc=loc -W -D 'cn=admin,dc=lab,dc=loc'

<hostname> est le nom de l’hôte contenu dans /etc/hostname ou retourné par la commande hostname. Pour la suite, nous utiliserons serveur.

L’option -D permet de préciser le compte à utiliser pour se connecter à slapd.

L’option -W permet de faire demander le mot de passe interactivement.

Peupler l’annuaire

Maintenant que le service est installé, nous allons pouvoir définir la structure de notre annuaire et l’appliquer.

Définir de l’arborescence

Tout d’abord, il faut avoir une idée claire de l’arborescence à créer pour son annuaire. Nous partirons sur le modèle standard suivant.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
dc=lab,dc=loc
├── ou=people           ← utilisateurs
│   ├── uid=root
│   ├── uid=pnom
│   ├── uid=qnom
│   └── ...
├── ou=groups           ← groupes
│   ├── cn=admins
│   ├── cn=readonly
│   ├── cn=vmusers
│   ├── cn=vmadmins
│   └── ...
└── ou=system           ← compte de service
    └── cn=binduser

Créer l’arborescence

Ajouter des OU

Nous créons d’abord les OU à partir du fichier LDIF suivant.

1
2
3
4
5
6
7
8
9
10
11
dn: ou=people,dc=lab,dc=loc
objectClass: organizationalUnit
ou: people

dn: ou=groups,dc=lab,dc=loc
objectClass: organizationalUnit
ou: groups

dn: ou=system,dc=lab,dc=loc
objectClass: organizationalUnit
ou: system

Nous les ajoutons ensuite à l’annuaire, en utilisant ce fichier.

1
ldapadd -x -H ldap://serveur.lab.loc -D 'cn=admin,dc=lab,dc=loc' -f ou.ldif -W
Ajouter des utilisateurs

Ajoutons maintenant un compte, en suivant la même méthode.

1
2
3
4
5
6
7
dn: uid=pnom,ou=people,dc=lab,dc=loc
uid: pnom
sn: pnom
cn: pnom
objectClass: inetOrgPerson
objectClass: top
userPassword: {SSHA}XXXXXXXXXXXXXXXXXXXXXXXX

La configuration présentée ici est la configuration minimale. Des attributs supplémentaires comme objectClass: posixAccount ou objectClass: shadowAccount peuvent être ajoutés.

Il faut remplacer {SSHA}XXXXXXXXXXXXXXXXXXXXXXXX par la sortie de la commande slappasswd.

L’utilisateur est ensuite ajouté à l’annuaire par la commande suivante.

1
ldapadd -x -H ldap://serveur.lab.loc -D 'cn=admin,dc=lab,dc=loc' -f users.ldif -W

Il est possible de vérifier que l’ajout ait fonctionné.

1
ldapsearch -x -H ldap://serveur.lab.loc -b 'dc=lab,dc=loc'

Les entrées ajoutées devraient apparaître.

Ajouter des groupes

Nous pouvons maintenant ajouter des groupes, toujours en utilisant des fichiers LDIF.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
dn: cn=admins,ou=groups,dc=lab,dc=loc
objectClass: top
objectClass: groupOfNames
cn: vmadmins
member: uid=root,ou=people,dc=lab,dc=loc

dn: cn=vmusers,ou=groups,dc=lab,dc=loc
objectClass: top
objectClass: groupOfNames
cn: vmadmins
member: uid=pnom,ou=people,dc=lab,dc=loc

dn: cn=readonly,ou=groups,dc=lab,dc=loc
objectClass: top
objectClass: groupOfNames
cn: readonly
memberUid: uid=binduser,ou=system,dc=lab,dc=loc

dn: cn=vmadmins,ou=groups,dc=lab,dc=loc
objectClass: top
objectClass: groupOfNames
cn: vmadmins
member: uid=pnom,ou=people,dc=lab,dc=loc

La configuration présentée ici est la configuration minimale. Des attributs supplémentaires comme objectClass: posixGroup ou objectClass: shadowGroup peuvent être ajoutés.
Dans ce cas, l’attribution des utilisateurs aux groupes se fait par la correspondance entre les gidNumber renseignés dans les définitions du groupe et de l’utilisateur (groupe principal) et par la correspondance entre le memberUid de la définition du groupe et le uid de la définition de l’utilisateur (groupe secondaire).
Pour rappel, un groupe primaire est le groupe par défaut de l’utilisateur qui apparaît par exemple lors de la création de fichiers. Un groupe secondaire permet à l’utilisateur d’avoir des droits additionnels.

L’ajout d’un compte utilisateur (non technique) à un groupe peut se faire comme suit (groupe secondaire).

1
2
3
4
dn: cn=vmusers,ou=groups,dc=lab,dc=loc
changetype: modify
add: member
member: uid=qnom,ou=people,dc=lab,dc=loc
Ajouter des comptes techniques

Comme les comptes techniques ne sont pas amenés à se connecter en utilisant l’annuaire, leur configuration diffère.

1
2
3
4
5
6
dn: cn=binduser,ou=system,dc=lab,dc=loc
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: binduser
description: LDAP Bind Account
userPassword: {SSHA}XXXXXXXXXXXXXXXXXXXXXXXX

Le rôle du compte binduser est de permettre aux clients d’interroger l’annuaire pour vérifier et synchroniser les informations. Il est donc lecteur et n’a pas vocation à modifier l’annuaire.

Modifier ou supprimer des entrées

Il peut arriver qu’une entrée soit ajoutée par erreur à l’annuaire. Heureusement, il est possible de la modifier ou de la supprimer.

Supprimer

Commençons par le plus simple : supprimer une entrée.

Nous utilisons pour cela la commande ldapdelete et un compte ayant les droits pour supprimer un objet, identifié par son DN (OU, utilisateur, groupe etc.).

1
ldapdelete -x -D "cn=admin,dc=lab,dc=loc" -W "ou=users,dc=lab,dc=loc"

Avant de pouvoir supprimer un conteneur, il faut en supprimer tout le contenu.

Modifier

Pour modifier une entrée, on crée d’abord un nouveau fichier LDIF de la forme suivante.

1
2
3
4
dn: uid=pnom,ou=people,dc=lab,dc=loc
changetype: modify
replace: cn
cn: prom

Ensuite, on applique les changements avec la commande ldapmodify, un compte ayant les droits de modification de l’annuaire et le nouveau fichier créé.

1
ldapmodify -x -D "cn=admin,dc=lab,dc=loc" -W -f modify.ldif

Pour modifier le dn, c’est un peu différent. Il faut d’abord modifier le rdn avec la commande ldapmodrdn.

1
ldapmodrdn -x -D "cn=admin,dc=lab,dc=loc" -W "cn=admins,ou=groups,dc=lab,dc=loc" "cn=nouveau"

Puis modifier les autres champs qui dépendent de ce rdn, comme cn via un fichier LDIF.

1
2
3
4
dn: cn=admins-LDAP,ou=groups,dc=lab,dc=loc
changetype: modify
replace: cn
cn: nouveau

Et enfin appliquer les changements via la commande ldapmodify.

1
ldapmodify -x -D "cn=admin,dc=lab,dc=loc" -W -f rdn_modif.ldif

Sécuriser avec SSL

SSL permet d’ajouter la confidentialité à la connexion, par un chiffrement.

Générer un certificat SSL

Nous créons d’abord un répertoire spécifique, dans lequel nous rangerons notre certificat.

1
mkdir /etc/ldap/ssl && cd /etc/ldap/ssl

Puis nous générons le certificat.

1
openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 3650 -nodes

Les fichiers générés :

  • key.pem, est la clé privée.
  • cert.pem, est le certificat contenant la clé publique et fait office de CA, comme le certificat est auto-signé.

Pendant le création, nous renseignons surtout le champs Common Name, avec serveur.lab.loc.

Nous adaptons ensuite les propriétaires et droits des fichiers.

1
2
3
chown openldap:openldap /etc/ldap/ssl/cert.pem
chown openldap:openldap /etc/ldap/ssl/key.pem
chmod 400 /etc/ldap/ssl/key.pem

Reconfigurer slapd

Nous allons modifier les entrées de la racine cn=config pour y renseigner les chemins vers les fichiers générés. Nous utilisons pour cela un fichier LDIF.

1
2
3
4
5
6
7
8
9
10
dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/ssl/cert.pem
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/ssl/cert.pem
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/ssl/key.pem

Nous appliquons ensuite les changements par ldapi, comme aucun compte administrateur n’a été créé pour la racine cn=config.

1
ldapmodify -Y EXTERNAL -H ldapi:/// -f cert.ldif
  • -Y EXTERNAL remplace -x, pour permettre l’authentification via UID plutôt que par un compte de l’annuaire (simple bind).
  • -H ldapi:/// pointe vers la socket UNIX gérée par slapd.

Enfin, il nous reste à modifier le fichier de configuration /etc/default/slapd pour y ajouter ldaps:/// dans le ligne SLAPD_SERVICES="ldap:/// ldapi:/// ldaps:///".

Nous pouvons maintenant redémarrer slapd avant de tester la nouvelle configuration.

1
2
systemctl restart slapd
ss -laputn -A inet | grep slapd

Si le port 636 est en écoute, en plus du port 389, la configuration a bien été prise en compte.

Configurer le client

Notre client est donc un hyperviseur Proxmox et notre objectif est de synchroniser son authentification avec les données de l’annuaire.

Ajouter un Realm

Il faut d’abord ajouter un Realm au Datacenter Proxmox, sous Datacenter > Permissions > Realms > Add, en renseignant les informations nécessaires à la connexion au serveur LDAP, et en particulier les éléments suivants :

  • User classes : inetOrgPerson
  • Group classes : groupOfNames
  • User Filter : (objectClass=inetOrgPerson)
  • Group Filter : (objectClass=groupOfNames)

Ces paramètres correspondent à ceux choisis lors de la définition de notre arborescence et de ses objets. Nous prendrons pour notre realm, le nom LDAP.

realm1.png

realm2.png

Une fois le Realm ajouté, il est possible de synchroniser l’annuaire via le bouton Sync. De cette manière, les utilisateurs, groupes et appartenance des utilisateurs aux groupes sont ajoutés automatiquement.

sync.png

Il reste toutefois possible de le faire manuellement.

Déclarer des utilisateurs manuellement

Il est possible d’ajouter des utilisateurs LDAP manuellement dans Proxmox soit par l’interface graphique, soit en ligne de commandes.

1
pveum user add root@LDAP

Et pour le supprimer.

1
pveum user del root@LDAP

Déclarer des groupes manuellement

Il est également possible d’ajouter des groupes manuellement.

1
pveum groupadd admins

Et pour le supprimer.

1
pveum groupdel admins

L’interface graphique est plus permissive ici, puisqu’elle permet par exemple les majuscules dans les noms des groupes.

groupe.png

Ajouter un utilisateur à un groupe manuellement

Il ne reste maintenant plus qu’à ajouter l’utilisateur au groupe, dont les droits sont déjà définis.

1
pveum usermod root@LDAP -group admins

Sur l’interface graphique, au moment de créer l’utilisateur, il est possible de lui assigner un groupe directement. Il est également possible d’éditer cette valeur.

utilisateur.png

Attribuer des droits

L’attribution automatique des droits n’est en revanche pas possible par synchronisation, elle doit être faite manuellement.

Par utilisateur

Il est possible d’assigner les droits par utilisateur en fonction de ce qu’il seront autorisés à faire sur l’hyperviseur.

1
pveum aclmod / -user root@LDAP -role Administrator

permission.png

Par groupe

Il est aussi possible d’attribuer des droits Proxmox aux groupes LDAP synchronisés, dont les utilisateurs membres vont hériter.

1
pveum aclmod / -group admins@LDAP -role Administrator
  • / définit le périmètre sur lequel ces droits s’appliquent. Il peut être restreint (par exemple, /vms)

Et pour supprimer le rôle associé au groupe donné.

1
pveum acldel / -group admins@ldap -role Administrator

permission_groupe.png

Bonne pratique : restriction des droits du binduser

Le compte binduser, qui n’est utile que pour synchroniser l’annuaire et le Proxmox peut avoir des droits restreints en lecture seule sur l’annuaire.

Pour restreindre ses droits, il faut d’abord déterminer si la configuration d’OpenLDAP est statique ou dynamique.

Pour cela, regardons si le fichier /etc/ldap/slapd.conf existe. Si oui, il s’agit d’une configuration statique.

Pour s’assurer que la configuration est dynamique, regardons le retour de la commande suivante.

1
ldapsearch -Q -LLL -Y EXTERNAL -H ldapi:/// -b cn=config dn

Si la ligne dn: cn=config est retournée, alors il s’agit d’une configuration dynamique.

Configuration statique

Dans la section access du /etc/ldap/slapd.conf, ajoutons ou remplaçons les lignes suivantes.

1
2
3
access to dn.subtree="dc=lab,dc=loc"
    by dn.exact="cn=binduser,ou=system,dc=lab,dc=loc" read
    by * none

Configuration dynamique

Nous créons un nouveau fichier LDIF pour modifier les ACL en place par défaut.

1
2
3
4
5
6
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: to dn.subtree="dc=lab,dc=loc"
  by dn.exact="cn=binduser,ou=system,dc=lab,dc=loc" read
  by * none

Puis nous l’appliquons.

1
ldapmodify -Y EXTERNAL -H ldapi:/// -f binduser-acl.ldif

Si l’erreur suivante apparaît, nous devrons redéfinir l’ensemble de l’ACL.

1
ldapmodify: wrong attributeType at line 4, entry "olcDatabase={1}mdb,cn=config"

Pour commencer, récupérons la sous-partie des ACL qui nous intéresse.

1
ldapsearch -Q -Y EXTERNAL -H ldapi:/// -b cn=config '(olcAccess=*)' olcAccess`, section `# {1}mdb, config

Et inscrivons-la, en plus de notre entrée, dans un fichier LDIF.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: {0}to attrs=userPassword
  by self write
  by anonymous auth
  by * none
olcAccess: {1}to attrs=shadowLastChange
  by self write
  by * read
olcAccess: {2}to dn.subtree="dc=lab,dc=loc"
  by dn.exact="cn=binduser,ou=system,dc=lab,dc=loc" read
  by * none
olcAccess: {3}to *
  by * read

Puis appliquons-la avec la méthode habituelle.

1
ldapmodify -Y EXTERNAL -H ldapi:/// -f binduser-acl.ldif

Nous pouvons ensuite vérifier que la modification ait bien été prise en compte.

1
slapcat -n 0 | grep olcAccess

Références

This post is licensed under CC BY 4.0 by the author.