La mise en place de SSL pour OpenLDAP permet de sécuriser les échanges, que ce soit en utilisant LDAPS ou START/TLS (dans ce dernier cas, la connexion démarre sur le port LDAP et passe ensuite en mode sécurisé).
En préalable, on aura généré une clé privée, récupéré un certificat, ainsi que celui de l'autorité de certification. (voir un article précédent sur le mémento OpenSSL ).
Les étapes pour la sécurisation sont :
Cette opération est optionnelle. On peut aussi utiliser le répertoire /etc/openldap/cacerts (sous RedHat / CentOS) ou tout autre répertoire tel que /etc/ssl/certs (pour les certificats) ou /etc/ssl/private (pour les clés privées). Création du répertoire dans lequel seront stockés les certificats et clés, et copie des fichiers dans ce répertoire :
mkdir /product/openldap/certs
Les certificats et clés doivent ensuite être copiés dans le répertoire. On doit normalement disposer de 3 fichiers :
On copie les trois fichiers dans le répertoire précédemment créé, et on met les droits restrictifs pour le ldap :
cp ldap_cert.pem /product/openldap/certs
cp ldap_key.pem /product/openldap/certs
cp ca-ldap-cert.pem /product/openldap/certs
cd /product/openldap/certs
chown ldap ldap*
chmod 400 ldap*
Attention : le fichier contenant la clé ne doit pas être protégé par mot de passe. Si c'est le cas, on peut utiliser la commande openssl suivante :
openssl rsa -in macleprive.key -out maclesanspass.key
Pour que le daemon slapd puisse écouter et servir ses requêtes sur le port ldaps (636), il faut activer l'option LDAPS dans la configuration de l'annuaire OpenLDAP.
Le paramétrage est différent selon le type de distribution (Redhat / Debian).
Pour une distribution type Red Hat, CentOS, il faut modifier le fichier /etc/sysconfig/ldap, et changer la valeur pour la variable SLAPD_LDAPS :
# Run slapd with -h "... ldaps:/// ..."
# yes/no, default: no
SLAPD_LDAPS=yes
Pour une distribution type Debian, Ubuntu, la modification est à faire dans le fichier /etc/default/slapd. Il faut modifier la ligne correspondant à la variable SLAPD_SERVICES. Changer par exemple :
SLAPD_SERVICES="ldap:/// ldapi:///"
en
SLAPD_SERVICES="ldap:/// ldaps:/// ldapi:///"
On peut alors démarrer le daemon et vérifier qu'il écoute sur le port ldaps :
# service slapd start
Démarrage de slapd : [ OK ]
# ps -ef | grep slap
ldap 1632 1 4 11:18 ? 00:00:00 /usr/sbin/slapd -h ldap:/// ldaps:/// ldapi:/// -u ldap
La prochaine étape consiste à modifier le paramétrage de l'annuaire, pour qu'il active le mode TLS.
Ceci peut s'effectuer par un fichier LDIF (recommandé), ou en modifiant le fichier /etc/openldap/slapd.d/cn=config.ldif manuellement. Dans l'option 1, on crée un fichier LDIF qui contient les lignes :
cat > tls-config.ldif << EOF
dn: cn=config
add: olcTLSCACertificateFile
olcTLSCACertificateFile: /product/openldap/certs/ca-ldap-cert.pem
dn: cn=config
add: olcTLSCertificateFile
olcTLSCertificateFile: /product/openldap/certs/ldap_cert.pem
dn: cn=config
add: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /product/openldap/certs/ldap_key.pem
dn: cn=config
add: olcTLSVerifyClient
olcTLSVerifyClient: never
EOF
Puis on modifie la configuration via un ldapmodify:
ldapmodify -QY EXTERNAL -H ldapi:/// -f tls-config.ldif
Pour l'option 2 (modification du fichier), il faut s'assurer que le service slapd soit arrêté.
service slapd stop
echo "olcTLSCACertificateFile: /product/openldap/certs/ca-ldap-cert.pem" >> /etc/openldap/slapd.d/cn=config.ldif
echo "olcTLSCertificateFile: /product/openldap/certs/ldap_cert.pem" >> /etc/openldap/slapd.d/cn=config.ldif
echo "olcTLSCertificateKeyFile: /product/openldap/certs/ldap_key.pem" >> /etc/openldap/slapd.d/cn=config.ldif
service slapd start
Attention : sous Debian, il semble que slapd utilise un mécanisme de checksum CRC32 pour valider que les fichiers LDIF de configuration n'ont pas été modifiés manuellement ! On peut alors avoir dans les logs de l'annuaire une ligne telle que
ldif_read_file: checksum error on "/etc/ldap/slapd.d/cn=config/olcDatabase={0}config.ldif"
Ceci n'empêche pas l'annuaire de démarrer, mais signifie qu'une modification manuelle a été effectuée, plutôt que l'utilisation de ldapmodify
On peut alors tester avec la commande :
ldapsearch -x -H ldap://192.168.56.121 -b "dc=example,dc=corp" "objectclass=organizationalunit" -Z -D "cn=manager,dc=example,dc=corp" -w Secr@t -s one
L'option -Z permet de passer en mode TLS. Dans ce cas, on utilise le port 389 entre le client et le serveur LDAP, ce que l'on peut vérifier dans les logs de l'annuaire OpenLDAP (slapd.log):
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 fd=21 ACCEPT from IP=192.168.56.1:48181 (IP=0.0.0.0:389)
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=0 EXT oid=1.3.6.1.4.1.1466.20037
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=0 STARTTLS
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=0 RESULT oid= err=0 text=
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 fd=21 TLS established tls_ssf=256 ssf=256
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=1 BIND dn="cn=manager,dc=example,dc=corp" method=128
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=1 BIND dn="cn=manager,dc=example,dc=corp" mech=SIMPLE ssf=0
Dec 18 11:51:13 ldapagd1 slapd[1806]: connection_input: conn=1020 deferring operation: binding
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=1 RESULT tag=97 err=0 text=
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=2 SRCH base="dc=example,dc=corp" scope=1 deref=0 filter="(objectClass=organizationalUnit)"
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=3 UNBIND
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 op=2 SEARCH RESULT tag=101 err=0 nentries=6 text=
Dec 18 11:51:13 ldapagd1 slapd[1806]: conn=1020 fd=21 closed
On peut combiner le TLS + SSL, en précisant le port et le protocolel ldaps, via la commande :
ldapsearch -x -H ldaps://192.168.56.121:636 -b "dc=example,dc=corp" "objectclass=organizationalunit" -Z -D "cn=manager,dc=example,dc=corp" -w Secr@t -s one
Dans les logs, on constate alors que le port est bien le 636 :
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 fd=21 ACCEPT from IP=192.168.56.1:54692 (IP=0.0.0.0:636)
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 fd=21 TLS established tls_ssf=256 ssf=256
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=0 EXT oid=1.3.6.1.4.1.1466.20037
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=0 STARTTLS
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=0 RESULT oid= err=1 text=TLS already started
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=1 BIND dn="cn=manager,dc=example,dc=corp" method=128
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=1 BIND dn="cn=manager,dc=example,dc=corp" mech=SIMPLE ssf=0
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=1 RESULT tag=97 err=0 text=
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=2 SRCH base="dc=example,dc=corp" scope=1 deref=0 filter="(objectClass=organizationalUnit)"
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=2 SEARCH RESULT tag=101 err=0 nentries=6 text=
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 op=3 UNBIND
Dec 18 11:53:19 ldapagd1 slapd[1806]: conn=1022 fd=21 closed
Certains clients LDAP veulent valider l'authenticité du certificat, ce qui peut poser problème lorsqu'on utilise un certificat auto-signé.
On peut se prémunir de ce type de problème en modifiant le fichier /etc/ldap/ldap.conf, et en ajoutant la variable TLS_REQCERT , et en déclarant le répertoire dans lequel on peut trouver les certificats des autorités de certification :
TLS_REQCERT allow
TLS_CACERTDIR /product/openldap/certs
Cette variable peut avoir plusieurs valeurs :
Dans le cas où le certificat doit être authentifié, il faut l'ajouter à la liste des certificats connus.
Afin d'éviter le côté "boîte noire" des commandes LDAP, on peut déjà tester l'échange des certificats via une commande ssl :
openssl s_client -connect 192.168.56.121:636
CONNECTED(00000003)
depth=0 C = XX, ST = FR, L = France, O = Hebinweb, OU = ldap, CN = ldap.hebinweb.com, emailAddress = admin@hebinweb.com
verify error:num=18:self signed certificate
verify return:1
depth=0 C = XX, ST = FR, L = France, O = Hebinweb, OU = ldap, CN = ldap.hebinweb.com, emailAddress = admin@hebinweb.com
verify return:1
---
Certificate chain
0 s:/C=XX/ST=FR/L=France/O=Hebinweb/OU=ldap/CN=ldap.hebinweb.com/emailAddress=admin@hebinweb.com
i:/C=XX/ST=FR/L=France/O=Hebinweb/OU=ldap/CN=ldap.hebinweb.com/emailAddress=admin@hebinweb.com
---
Server certificate
-----BEGIN CERTIFICATE-----
MIID7TCCAtWgAwIBAgIJAPsjys7PHwWQMA0GCSqGSIb3DQEBBQUAMIGMMQswCQYD
VQQGEwJYWDELMAkGA1UECAwCRlIxDzANBgNVBAcMBkZyYW5jZTERMA8GA1UECgwI
SGViaW53ZWIxDTALBgNVBAsMBGxkYXAxGjAYBgNVBAMMEWxkYXAuaGViaW53ZWIu
Y29tMSEwHwYJKoZIhvcNAQkBFhJhZG1pbkBoZWJpbndlYi5jb20wHhcNMTMxMjE4
MTAwNzQ4WhcNMTUxMjE4MTAwNzQ4WjCBjDELMAkGA1UEBhMCWFgxCzAJBgNVBAgM
...
Le client SSL récupère bien le certificat, qu'il identifie comme étant auto-signé (self signed certificate).