7. Sécuriser les échanges entre clients et serveur LDAP

La sécurisation des échanges entre les clients et le serveur LDAP repose sur deux mécanismes complémentaires, que cette partie met en place successivement.

Le premier est Kerberos. Son introduction modifie en profondeur le dialogue entre les clients et l'annuaire, passant du Simple Bind au SASL/GSSAPI. Au lieu d'échanger un identifiant et un mot de passe en clair, le client présente un ticket de service (TGS) préalablement signé par le KDC. Le serveur LDAP vérifie la signature du ticket auprès du KDC sans jamais manipuler de mot de passe. Le contenu des segments TCP (payload) est chiffré par Kerberos, ce qui rend le vol d'identité impossible.

Cependant, Kerberos ne dissimule pas la nature des échanges : une capture réseau révèle que c'est bien le service LDAP qui est interrogé. Un second mécanisme est donc nécessaire : TLS (Transport Layer Security). Ce protocole chiffre l'intégralité du flux au niveau du transport, indépendamment du protocole applicatif. Deux modes coexistent dans OpenLDAP : StartTLS, qui bascule vers TLS sur le port 389/TCP après une requête d'initialisation, et LDAPS, qui établit immédiatement un tunnel TLS sur le port 636/TCP, à la manière de HTTPS.

Tableau 4. Comparaison des niveaux de sécurité LDAP

Caractéristique Avant (Simple Bind) Avec Kerberos seul Avec Kerberos + TLS
Preuve d'identité Mot de passe Ticket de service (TGS) Ticket de service (TGS)
Contenu TCP En clair Chiffré par Kerberos Chiffré par TLS
Visibilité du protocole LDAP observable LDAP observable LDAP masqué
Certificat serveur Non Non Oui (X.509)
Résistance au rejeu Non Oui Oui

7.1. Assurer la résolution des noms d'hôtes

Pour Kerberos, l'identité d'un service est étroitement liée à son nom d'hôte pleinement qualifié (FQDN). Contrairement à mDNS (.local), qui est dynamique et sujet à l'usurpation, Kerberos exige une correspondance parfaite entre l'adresse IP, le nom d'hôte et le nom du service enregistré dans le KDC (le Service Principal Name ou SPN).

Si la résolution inverse (IP vers nom) ne correspond pas exactement au nom présent dans le ticket Kerberos, l'authentification échouera systématiquement.

Dans le cadre de travaux pratiques, on ne dispose pas d'un service DNS complet. Il faut donc procéder à une résolution locale des noms sur le serveur et sur le client.

Q144.

Quelles sont les étapes à suivre pour configurer le client et le serveur LDAP afin d'assurer une résolution locale des noms d'hôtes ?

Consultez les pages de manuel de la table de recherche statique des noms d'hôtes  : man hosts.

Créez un script qui ajoute les enregistrements du client et du serveur dans le fichier /etc/hosts, tout en évitant les doublons.

Copiez l'exemple de code ci-dessous dans le fichier update-hosts.sh.

[Attention] Attention

Éditez le script pour utiliser vos adresses IPv4 et IPv6.

#!/bin/bash

DOMAIN="lab.local"
HOSTS_FILE="/etc/hosts"
CLIENT_IPS=(
        "172.28.101.4"
        "2001:678:3fc:65:baad:caff:fefe:4"
)
CLIENT_NAME="ldap-clnt"
SERVER_IPS=(
        "172.28.101.3"
        "2001:678:3fc:65:baad:caff:fefe:3"
)
SERVER_NAME="ldap-srvr"

if [[ ${EUID} -ne 0 ]]; then
        echo "This script must be run as root." >&2
        exit 1
fi

# Escape the characters that are special in a sed basic regular expression.
escape_sed_bre() {
        sed 's/[][\\.^$*]/\\&/g'
}

update_host_entry() {
        local ip="$1"
        local name="$2"
        # Escape the IP before using it inside a sed search pattern.
        local escaped_ip
        escaped_ip=$(printf '%s\n' "${ip}" | escape_sed_bre)
        sed -i "/^${escaped_ip}[[:space:]]/d" "${HOSTS_FILE}"
        echo "${ip} ${name}.${DOMAIN} ${name}" >>"${HOSTS_FILE}"
}

for ip in "${CLIENT_IPS[@]}"; do
        update_host_entry "${ip}" "${CLIENT_NAME}"
done

for ip in "${SERVER_IPS[@]}"; do
        update_host_entry "${ip}" "${SERVER_NAME}"
done

exit 0

Lancez le script sur le client et sur le serveur.

sudo bash update-hosts.sh

Testez la résolution locale des noms du client et du serveur.

host ldap-clnt.lab.local
ldap-clnt.lab.local has address 172.28.101.4
ldap-clnt.lab.local has IPv6 address 2001:678:3fc:65:baad:caff:fefe:4
host ldap-srvr.lab.local
ldap-srvr.lab.local has address 172.28.101.3
ldap-srvr.lab.local has IPv6 address 2001:678:3fc:65:baad:caff:fefe:3

Testez aussi la résolution inverse.

for ip in 172.28.101.3 172.28.101.4 \
    2001:678:3fc:65:baad:caff:fefe:3 2001:678:3fc:65:baad:caff:fefe:4; do
        host $ip
done
3.101.28.172.in-addr.arpa domain name pointer ldap-srvr.lab.local.
3.101.28.172.in-addr.arpa domain name pointer ldap-srvr.
4.101.28.172.in-addr.arpa domain name pointer ldap-clnt.lab.local.
4.101.28.172.in-addr.arpa domain name pointer ldap-clnt.
3.0.0.0.e.f.e.f.f.f.a.c.d.a.a.b.5.6.0.0.c.f.3.0.8.7.6.0.1.0.0.2.ip6.arpa domain name pointer ldap-srvr.lab.local.
3.0.0.0.e.f.e.f.f.f.a.c.d.a.a.b.5.6.0.0.c.f.3.0.8.7.6.0.1.0.0.2.ip6.arpa domain name pointer ldap-srvr.
4.0.0.0.e.f.e.f.f.f.a.c.d.a.a.b.5.6.0.0.c.f.3.0.8.7.6.0.1.0.0.2.ip6.arpa domain name pointer ldap-clnt.lab.local.
4.0.0.0.e.f.e.f.f.f.a.c.d.a.a.b.5.6.0.0.c.f.3.0.8.7.6.0.1.0.0.2.ip6.arpa domain name pointer ldap-clnt.

7.2. Installer et configurer le serveur Kerberos

Contrairement au service LDAP, pour lequel on a séparé l'installation des paquets de la configuration avec le script de « bootstrap », le service Kerberos ne le permet pas.

Vous devrez donc réer un script de bootstrap dédié à Kerberos qui procédera à l'installation des paquets avec une configuration fournie en mode « pre-seeding » en utilisant les mêmes outils debconf que pour la configuration de l'accès transparent à l'annuaire LDAP côté client.

Q145.

Quels sont les paquets à installer pour configurer le serveur KDC ?

Recherchez la liste des paquets dont le nom débute par krb5.

Lancez la recherche avec le gestionnaire de paquets.

apt search --names-only ^krb5

On obtient ainsi une longue liste de paquets. Affichez les informations de chaque paquet pour décider s'il faut le retenir dans le contexte d'un serveur KDC.

Au minimum, on retient deux paquets :

  • krb5-kdc : Installe le Centre de Distribution des Clés (KDC), le moteur principal qui vérifie les identités et distribue les tickets d'accès.

  • krb5-admin-server : Fournit le démon d'administration (kadmind) nécessaire pour gérer la base de données Kerberos (création de comptes, génération de keytabs) via le réseau.

Q146.

Comment installer et configurer le Key Distribution Center (KDC) sur le serveur LDAP

Créez un script qui utilise les outils debconf pour préparer les paramètres de configuration du KDC et les injecter lors de l'installation du paquet et de ses dépendances.

Ce script Bash comprend plusieurs parties.

  1. Charger des variables et le secret maître

    La première partie du script initialise le contexte de travail en définissant le domaine (lab.local), le royaume Kerberos et le nom du serveur KDC (ldap-srvr.LAB.LOCAL), puis en récupérant de manière sécurisée le mot de passe maître utilisé pour initialiser la base de clés (~/.ldap_admin_pass).
  2. Pré‑configurer Debconf pour une installation non interactive

    Préparez l’installation des paquets Kerberos en renseignant à l’avance les réponses attendues par krb5-config via debconf-set-selections. Les paramètres attendus sont :
    • Le nom du royaume par défaut : default_realm

    • Le nom du serveur : kerberos_servers

    • Le nom du serveur d'administration : admin_server

    • L'ajout automatique de nouveaux serveurs : add_servers

  3. Installer des paquets Kerberos du serveur

    Installez les composants serveurs nécessaires à Kerberos en mode non interactif, à l’aide de apt et de la variable DEBIAN_FRONTEND=noninteractive.
  4. Appliquer de la configuration système /etc/krb5.conf

    Remplacez le fichier /etc/krb5.conf par une configuration qui définit au niveau système le realm par défaut, les serveurs KDC et d’administration, ainsi que les paramètres cryptographiques.
    Un bloc [libdefaults] doit désactiver les chiffrements faibles, forcer l’usage d’AES (128/256 bits) pour les tickets et les TGS, tandis que les sections [realms] et [domain_realm] associent le domaine lab.local au realm LAB.LOCAL en pointant vers le serveur ldap-srvr.lab.local, préparant ainsi l’intégration future avec le service LDAP.
  5. Initialiser la base cryptographique du KDC

    Utilisez l’outil kdb5_util pour créer la base de clés pour le realm.
    Utilisez l’option -s pour générer un fichier de stash contenant la clé maître pour permettre au KDC de redémarrer sans interaction. Utilisez aussi -P "${KDC_MASTER_PWD}" pour injecter le mot de passe maître de manière non interactive.
    Appliquez aussi une règle de contrôle d'accès minimale dans le fichier /etc/krb5kdc/kadm5.acl pour permettre le lancement du service sans erreur.
  6. Redémarrez et activez les services Kerberos

    Activez et redémarrez les services krb5-kdc et krb5-admin-server avec la commande systemctl.

Copiez l'exemple de code ci-dessous dans le fichier bootstrap-kdc.sh.

#!/usr/bin/env bash

set -euo pipefail

echo "=== 1. Loading variables and secrets ==="
readonly DOMAIN="lab.local"
# Automatically convert domain to uppercase for realm
readonly REALM="${DOMAIN^^}"
readonly KDC_SERVER="ldap-srvr.${DOMAIN}"
readonly ADMIN_PASS_FILE="${HOME}/.ldap_admin_pass"

# Verify presence of master password
if [[ ! -f ${ADMIN_PASS_FILE} ]]; then
        echo "Error: Password file ${ADMIN_PASS_FILE} not found."
        exit 1
fi

# Securely read password (without potential line breaks)
KDC_MASTER_PWD=$(head -n 1 "${ADMIN_PASS_FILE}")
readonly KDC_MASTER_PWD

echo "=== 2. Pre-configure Debconf for silent installation ==="
sudo debconf-set-selections <<EOF
krb5-config krb5-config/default_realm string ${REALM}
krb5-config krb5-config/kerberos_servers string ${KDC_SERVER}
krb5-config krb5-config/admin_server string ${KDC_SERVER}
krb5-config krb5-config/add_servers boolean true
EOF

echo "=== 3. Installing Kerberos packages ==="
sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
        krb5-kdc \
        krb5-admin-server

echo "=== 4. Deploying system configuration (/etc/krb5.conf) ==="
cat <<EOF | sudo tee /etc/krb5.conf >/dev/null
[libdefaults]
        default_realm = ${REALM}
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true
        rdns = true
        allow_weak_crypto = false
        default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
        default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
        permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96

[realms]
        ${REALM} = {
                kdc = ${KDC_SERVER}
                admin_server = ${KDC_SERVER}
                default_domain = ${DOMAIN}
        }

[domain_realm]
        .${DOMAIN} = ${REALM}
        ${DOMAIN} = ${REALM}
EOF

echo "=== 5. Initializing cryptographic database ==="
# The -s option creates a 'stash' file to allow the KDC to restart automatically
# The -P option allows passing the password non-interactively
sudo kdb5_util create -s -r "${REALM}" -P "${KDC_MASTER_PWD}"
# Create the basic ACL to ensure the service restarts without errors
echo "*/admin@${REALM} *" | sudo tee /etc/krb5kdc/kadm5.acl >/dev/null

echo "=== 6. Restarting services ==="
sudo systemctl enable krb5-kdc krb5-admin-server
sudo systemctl restart krb5-kdc krb5-admin-server

echo ""
echo "================================================================="
echo " Success: Kerberos KDC is installed and configured."
echo " Active realm: ${REALM}"
echo " Master server: ${KDC_SERVER}"
echo "================================================================="

Lancez le script sur le serveur LDAP.

bash bootstrap-kdc.sh

Vérifiez que les deux services sont actifs et sont initialisés correctement.

systemctl status krb5-kdc krb5-admin-server

Q147.

Comment créer le principal pour administrer le domaine Kerberos ?

Donnez une définition du rôle de principal dans l'architecture Kerberos.

Créez et testez le principal d'administration du KDC.

Dans l'environnement Kerberos, un principal est un identifiant cryptographique unique attribué à chaque entité du réseau (utilisateur, machine ou service). Il permet à cette entité de prouver son identité au centre de distribution de clés (KDC) et d'obtenir des tickets d'accès sécurisés.

L'administration à distance du KDC requiert la création d'un principal dédié disposant de privilèges étendus.

Copiez l'exemple de script Bash ci-dessous dans le fichier kadmin-princ-setup.sh.

#!/usr/bin/env bash

set -euo pipefail

echo "=== 1. Create KAdmin Password ==="
KADMIN_PASS=$(openssl rand -base64 28 | cut -c -24)
rm -f "${HOME}"/.kadmin_pass
echo -n "${KADMIN_PASS}" | tee "${HOME}"/.kadmin_pass >/dev/null
chmod 400 "${HOME}"/.kadmin_pass

echo "=== 2. Add KAdmin Principal ==="
sudo kadmin.local -q "addprinc -pw ${KADMIN_PASS} admin/admin"

echo "=== 3. List Principals ==="
sudo kadmin.local -q "listprincs"

Lancez le script de création du principal d'administration.

bash kadmin-princ-setup.sh
=== 1. Create KAdmin Password ===
=== 2. Add KAdmin Principal ===
Authenticating as principal root/admin@LAB.LOCAL with password.
No policy specified for admin/admin@LAB.LOCAL; defaulting to no policy
Principal "admin/admin@LAB.LOCAL" created.
=== 3. List Principals ===
Authenticating as principal root/admin@LAB.LOCAL with password.
K/M@LAB.LOCAL
admin/admin@LAB.LOCAL
kadmin/admin@LAB.LOCAL
kadmin/changepw@LAB.LOCAL
krbtgt/LAB.LOCAL@LAB.LOCAL

Maintenant que vous savez comment administrer la base Kerberos, vous pouvez passer à la création des principaux de l'hôte serveur, du service LDAP lui-même, puis des utilisateurs de cet annuaire.

Q148.

Quels principaux Kerberos faut-il créer pour intégrer l’annuaire ?

Vous devez créer les principaux des trois familles suivantes :

  • Hôte serveur

    host/ldap-srvr.lab.local@LAB.LOCAL : Il sert aux échanges de niveau hôte (ssh GSSAPI, etc.). Le principal de l'hôte client sera généré avec sa configuration.
  • Service LDAP

    ldap/ldap-srvr.lab.local@LAB.LOCAL : Ce principal est utilisé par slapd pour s’authentifier auprès des clients et pour valider les tickets présentés par les clients.
  • Utilisateurs

    Ces principaux permettent à chaque utilisateur de demander un ticket auprès du KDC avec kinit.

Générez le principal du serveur LDAP en une commande.

Créez les scripts de génération des principaux des deux autres familles en réutilisant les variables et les mots de passe déjà définis.

Commencez par le plus simple : la génération du principa du serveur LDAP.

sudo kadmin.local -q "addprinc -randkey host/ldap-srvr.lab.local@LAB.LOCAL"
Authenticating as principal root/admin@LAB.LOCAL with password.
No policy specified for host/ldap-srvr.lab.local@LAB.LOCAL; defaulting to no policy
Principal "host/ldap-srvr.lab.local@LAB.LOCAL" created.
[Note] Note

Le message « defaulting to no policy » s'affiche.

Lors de la création du principal, Kerberos affiche un message indiquant qu'aucune politique n'a été spécifiée. Dans Kerberos, une « politique » sert à imposer des règles relatives aux mots de passe, comme une expiration tous les 30 jours ou une complexité minimale.
Pour un compte de service ou de machine, l'absence de politique est la configuration standard et souhaitée. Cela garantit en effet que la clé cryptographique de la machine n'expirera pas subitement au milieu de l'année, ce qui provoquerait une panne générale de l'authentification sur le poste client.

Copiez l'exemple de code de génération du pricnipal du service LDAP dans le fichier create-ldap-service-princ.sh.

#!/usr/bin/env bash

set -euo pipefail

readonly DOMAIN="lab.local"
readonly REALM="${DOMAIN^^}"
readonly LDAP_HOST="ldap-srvr.${DOMAIN}"

# SPN respects standard format: service/fqdn@ROYAUME
readonly SPN="ldap/${LDAP_HOST}@${REALM}"
readonly KEYTAB_FILE="/etc/ldap/ldap.keytab"

echo "=== 1. Create the Service Principal Name (SPN) ==="
# The -randkey option generates a strong random key that will never be knonw or asked.
sudo kadmin.local -q "addprinc -randkey ${SPN}"

echo "=== 2. Extraction of the key in the Keytab file ==="
# The ktadd command extracts the key from the database and copies it to the local file.
sudo kadmin.local -q "ktadd -k ${KEYTAB_FILE} ${SPN}"

echo "=== 3. Securing the Keytab file ==="
# The slapd daemon runs under the 'openldap' user.
# It is crucial that it be the only owner and reader of this secret.
sudo chown openldap:openldap "${KEYTAB_FILE}"
sudo chmod 400 "${KEYTAB_FILE}"

echo ""
echo "================================================================="
echo " Success : The service ${SPN} has been created."
echo " The secret key has been exported and secured in : ${KEYTAB_FILE}"
echo "================================================================="

Lancez le script.

bash create-ldap-service-princ.sh
=== 1. Create the Service Principal Name (SPN) ===
Authenticating as principal root/admin@LAB.LOCAL with password.
No policy specified for ldap/ldap-srvr.lab.local@LAB.LOCAL; defaulting to no policy
Principal "ldap/ldap-srvr.lab.local@LAB.LOCAL" created.
=== 2. Extraction of the key in the Keytab file ===
Authenticating as principal root/admin@LAB.LOCAL with password.
Entry for principal ldap/ldap-srvr.lab.local@LAB.LOCAL with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/ldap/ldap.keytab.
Entry for principal ldap/ldap-srvr.lab.local@LAB.LOCAL with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/ldap/ldap.keytab.
=== 3. Securing the Keytab file ===

=================================================================
 Success : The service ldap/ldap-srvr.lab.local@LAB.LOCAL has been created.
 The secret key has been exported and secured in : /etc/ldap/ldap.keytab
=================================================================

L'exemple de code ci-dessous, génère les principaux des utilisateurs de l'annuaire LDAP : les membres de la famille Skywalker. Copiez le dans le fichier provision-users-kdc.sh.

#!/usr/bin/env bash

set -euo pipefail

readonly REALM="LAB.LOCAL"
# Usernames to provision in the KDC, matching those in LDAP
readonly USERS=("luke" "leia" "anakin" "padme")

echo "=== 1. Provision Kerberos principals from LDAP secrets ==="

for USER in "${USERS[@]}"; do
        PASS_FILE="${HOME}/.ldap_${USER}_pass"

        # Check if the password file exists before attempting to read it
        if [[ ! -f ${PASS_FILE} ]]; then
                echo " ⚠️ Avertissement : Le fichier ${PASS_FILE} est introuvable. Principal ${USER} ignoré."
                continue
        fi

        PASSWORD=$(head -n 1 "${PASS_FILE}")
        PRINCIPAL="${USER}@${REALM}"

        echo " 🔑 Creation of the principal : ${PRINCIPAL}"

        # Create the principal, or update its password if it already exists
        sudo kadmin.local -q "addprinc -pw ${PASSWORD} ${USER}" >/dev/null 2>&1 ||
                sudo kadmin.local -q "cpw -pw ${PASSWORD} ${USER}" >/dev/null 2>&1
done

echo ""
echo "=== 2. Check principals in the KDC database ==="
sudo kadmin.local -q "listprincs" | grep -E "luke|leia|anakin|padme"

echo ""
echo "================================================================="
echo " Success : The users have been added to the Kerberos database."
echo " Their passwords are strictly identical to those in the directory."
echo "================================================================="

Lancez le script.

bash provision-users-kdc.sh
=== 1. Provision Kerberos principals from LDAP secrets ===
 🔑 Creation of the principal : luke@LAB.LOCAL
 🔑 Creation of the principal : leia@LAB.LOCAL
 🔑 Creation of the principal : anakin@LAB.LOCAL
 🔑 Creation of the principal : padme@LAB.LOCAL

=== 2. Check principals in the KDC database ===
anakin@LAB.LOCAL
leia@LAB.LOCAL
luke@LAB.LOCAL
padme@LAB.LOCAL

=================================================================
 Success : The users have been added to the Kerberos database.
 Their passwords are strictly identical to those in the directory.
=================================================================

7.3. Installer et configurer le client Kerberos

Dans cette section, vous devez configurer le poste client (ldap-clnt.lab.local) pour accéder aux objets que l'on vient de créer sur le serveur KDC et activer le mécanisme de résolution d'identité.

Q149.

Quels sont les paquets à installer sur le client Kerberos ?

Recherchez, dans la liste des paquets Kerberos dont le nom contien krb5, ceux qui sont relatifs aux outils utilisateurs et à l'authentification (PAM).

apt search --names-only krb5

De cette longue liste, on retient deux paquets essentiels pour notre maquette :

  • krb5-user : commandes de diagnostic.

  • libpam-krb5 : module de pont entre le système d'exploitation et Kerberos.

Installez les paquets identifiés avec une configuration prédéfinie dans un script. Copiez l'exemple de code ci-dessous dans le fichier client-krb5-setup.sh.

#!/usr/bin/env bash

set -euo pipefail

readonly DOMAIN="lab.local"
readonly REALM="${DOMAIN^^}"
readonly KDC_SERVER="ldap-srvr.${DOMAIN}"

echo "=== 1. Pre seed Kerberos configuration ==="
sudo debconf-set-selections <<EOF
krb5-config krb5-config/default_realm string ${REALM}
krb5-config krb5-config/kerberos_servers string ${KDC_SERVER}
krb5-config krb5-config/admin_server string ${KDC_SERVER}
krb5-config krb5-config/add_servers boolean true
EOF

echo "=== 2. Install Kerberos client packages ==="
sudo DEBIAN_FRONTEND=noninteractive apt install -y --no-install-recommends \
        krb5-user \
        libpam-krb5

Lancez le script.

bash client-krb5-setup.sh

Q150.

Quel doit être le contenu du fichier /etc/krb5.conf d'un client Kerberos ?

Recherchez les informations sur les bonnes pratiques de gestion des fichiers de configuration Kerberos.

Le serveur KDC et les clients doivent être parfaitement d'accord sur le domaine par défaut, les emplacements des KDC (noms de domaine complets et ports) ainsi que sur les règles de chiffrement. Toute incompatibilité peut entraîner des échecs silencieux d'authentification.

Il est donc essentiel que le fichier /etc/krb5.conf soit identique sur le KDC et sur les clients pour garantir l'interopérabilité. Remplacez le contenu du fichier /etc/krb5.conf du client par celui du serveur LDAP.

cat << EOF | sudo tee /etc/krb5.conf >/dev/null
[libdefaults]
        default_realm = LAB.LOCAL
        kdc_timesync = 1
        ccache_type = 4
        forwardable = true
        proxiable = true
        rdns = true
        allow_weak_crypto = false
        default_tkt_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
        default_tgs_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96
        permitted_enctypes = aes256-cts-hmac-sha1-96 aes128-cts-hmac-sha1-96

[realms]
        LAB.LOCAL = {
                kdc = ldap-srvr.lab.local
                admin_server = ldap-srvr.lab.local
                default_domain = lab.local
        }

[domain_realm]
        .lab.local = LAB.LOCAL
        lab.local = LAB.LOCAL
EOF

Q151.

Comment générer le principal Kerberos du système client LDAP ?

Copiez le mot de passe d'administration Kerberos sur le poste client et créez un script qui utilise la commande kadmin en lieu et place de la commande kadmin.local utilisée pour générer les principaux côté serveur.

Copiez l'exemple de code ci-dessous dans le fichier create-client-princ.sh.

#!/usr/bin/env bash

set -euo pipefail

readonly DOMAIN="lab.local"
readonly CLIENT_NAME="ldap-clnt"
readonly REALM="${DOMAIN^^}"

readonly KADMIN_PASS_FILE="${HOME}/.kadmin_pass"
readonly KEYTAB_FILE="/etc/krb5.keytab"

echo "=== 1. Read Kerberos password from file ==="
if [[ ! -f ${KADMIN_PASS_FILE} ]]; then
        echo "Error: Kerberos admin password file not found: ${KADMIN_PASS_FILE}" >&2
        exit 1
fi

KADMIN_PASS=$(head -n 1 "${KADMIN_PASS_FILE}")

echo "=== 2. Create the client machine principal remotely ==="
sudo kadmin -p admin/admin -w "${KADMIN_PASS}" -q "addprinc -randkey host/${CLIENT_NAME}.${DOMAIN}@${REALM}"

echo "=== 3. Extract and automatically retrieve the key (Keytab) ==="
sudo kadmin -p admin/admin -w "${KADMIN_PASS}" -q "ktadd -k ${KEYTAB_FILE} host/${CLIENT_NAME}.${DOMAIN}@${REALM}"

echo "=== 4. Secure file access on the client ==="
sudo chown root:root "${KEYTAB_FILE}"
sudo chmod 600 "${KEYTAB_FILE}"

Notez que le mot de passe d'administration Kerberos est copié dans le fichier ~/.kadmin_pass et que le nom d'hôte est : ldap-clnt.lab.local.

Lancez le script.

bash create-client-princ.sh
=== 1. Read Kerberos password from file ===
=== 2. Create the client machine principal remotely ===
Authenticating as principal admin/admin with password.
No policy specified for host/ldap-clnt.lab.local@LAB.LOCAL; defaulting to no policy
Principal "host/ldap-clnt.lab.local@LAB.LOCAL" created.
=== 3. Extract and automatically retrieve the key (Keytab) ===
Authenticating as principal admin/admin with password.
Entry for principal host/ldap-clnt.lab.local@LAB.LOCAL with kvno 2, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
Entry for principal host/ldap-clnt.lab.local@LAB.LOCAL with kvno 2, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/krb5.keytab.
=== 4. Secure file access on the client ===

7.4. Intégrer Kerberos au service d'annuaire LDAP

Maintenant que le serveur et le client sont configurés pour utiliser Kerberos, le service LDAP doit utiliser cette fonction pour sécuriser les échanges entre serveur et client. L'intégration se fait en trois étapes :

  1. Indiquez au serveur LDAP comment utiliser le fichier Keytab que vous avez généré, puis assurez-vous qu'il écoute les requêtes GSSAPI.

  2. Apprenez au serveur LDAP à traduire une identité Kerberos en une identité LDAP.

  3. Intérgrez l'utilisation de Kerberos par le service nslcd sur le système client.

Q152.

Comment configurer slapd pour qu'il utilise l'identité cryptographique /etc/ldap/ldap.keytab et qu'il accepte les connexions Kerberos (GSSAPI) ?

  1. Recherchez le mode de déclaration d'emplacement du Keytab.

    Par défaut, les bibliothèques Kerberos du système d'exploitation cherchent toujours les clés dans le fichier global /etc/krb5.keytab. Or, pour des raisons de sécurité, vous avez isolé la clé d'OpenLDAP dans /etc/ldap/ldap.keytab (accessible uniquement par l'utilisateur openldap).

  2. Recherchez la syntaxe LDIF des instructions de configuration dans la base cn=config du nom d'hôte SASL et du royaume.

Créez un script qui rassemble les deux traitements.

Utilisez la variable d'environnement KRB5_KTNAME dans le fichier /etc/default/slapd pour forcer le processus slapd à lire le bon Keytab.

Copiez l'exemple de code ci-dessous dans le fichier configure-slapd-gssapi.sh.

i#!/usr/bin/env bash

set -euo pipefail

readonly DOMAIN="lab.local"
readonly REALM="${DOMAIN^^}"
readonly LDAP_HOST="ldap-srvr.${DOMAIN}"
readonly KEYTAB_FILE="/etc/ldap/ldap.keytab"

echo "=== 1. Set KRB5_KTNAME in /etc/default/slapd ==="

if ! grep -q "^KRB5_KTNAME" /etc/default/slapd; then
        # Add the KRB5_KTNAME variable to /etc/default/slapd
        sudo sed -i "s|^#\?KRB5_KTNAME.*|KRB5_KTNAME=${KEYTAB_FILE}|" /etc/default/slapd
        echo "export KRB5_KTNAME=${KEYTAB_FILE}" | sudo tee -a /etc/default/slapd >/dev/null
        echo " KRB5_KTNAME added to /etc/default/slapd."
else
        echo " The KRB5_KTNAME variable is already configured."
fi

echo "=== 2. Install the GSSAPI SASL module and restart slapd ==="
sudo apt -y install libsasl2-modules-gssapi-mit

# Restart slapd service to apply changes
sudo systemctl restart slapd

echo "=== 3. Insert the SASL configuration into the directory ==="

# Creation of a temporary LDIF file
TMP_LDIF=$(mktemp)

cat <<EOF >"${TMP_LDIF}"
dn: cn=config
changetype: modify
replace: olcSaslHost
olcSaslHost: ${LDAP_HOST}
-
replace: olcSaslRealm
olcSaslRealm: ${REALM}
EOF

# Apply LDIF file via the local connection (root)
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f "${TMP_LDIF}"

# Cleanup
rm -f "${TMP_LDIF}"

echo ""
echo "================================================================="
echo " Success: The slapd daemon is configured to use GSSAPI."
echo "================================================================="
>

Lancez le script.

bash configure-slapd-gssapi.sh
=== 1. Set KRB5_KTNAME in /etc/default/slapd ===
 The KRB5_KTNAME variable is already configured.
=== 2. Install the GSSAPI SASL module and restart slapd ===
libsasl2-modules-gssapi-mit est déjà la version la plus récente (2.1.28+dfsg1-11).
Sommaire :
  Mise à niveau de : 0. Installation de : 0, Supprimé : 0. Non mis à jour : 0
=== 3. Insert the SASL configuration into the directory ===
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"


=================================================================
 Success: The slapd daemon is configured to use GSSAPI.
=================================================================

Q153.

Comment établir la correspondance entre les principaux et le DIT ?

Recherchez la syntaxe du fichier LDIF qui insère les expressions rationnelles de la clé olcAuthzRegexp dans la base de configuration cn=config.

Créez un script qui applique les nouvelles règles de correspondance.

Copiez l'exemple de code ci-dessous dans le fichier configure-identity-mapping.sh.

#!/usr/bin/env bash

set -euo pipefail

readonly DOMAIN="lab.local"
readonly REALM="${DOMAIN^^}"
readonly BASE_DN="dc=lab,dc=local"
readonly USERS_OU="ou=people,${BASE_DN}"
readonly HOSTS_OU="ou=hosts,${BASE_DN}"

echo "=== 1. Set the translation rules (Authz-Regexp) ==="

TMP_LDIF=$(mktemp)

# Regex explanation:
# - replace : Ensures idempotency (overwrites existing rules safely instead of failing)
# - cn=[^,]+ : Makes the realm matching case-insensitive (lab.local or LAB.LOCAL)
# - Rule {0} (Humans) : uid=([^/,]+) captures the username, explicitly excluding '/' to avoid overlap.
# - Rule {1} (Machines): uid=host/([^,]+) specifically captures machine identities.
cat <<EOF >"${TMP_LDIF}"
dn: cn=config
changetype: modify
replace: olcAuthzRegexp
olcAuthzRegexp: {0}uid=([^/,]+),cn=[^,]+,cn=gssapi,cn=auth uid=\$1,${USERS_OU}
olcAuthzRegexp: {1}uid=host/([^,]+),cn=[^,]+,cn=gssapi,cn=auth cn=\$1,${HOSTS_OU}
EOF

echo "=== 2. Insert the rules into cn=config ==="
sudo ldapmodify -Y EXTERNAL -H ldapi:/// -f "${TMP_LDIF}"

rm -f "${TMP_LDIF}"

echo ""
echo "================================================================="
echo " Success: The identity mapping (Identity Mapping) is configured."
echo " Kerberos 'user@${REALM}'          -> LDAP 'uid=user,${USERS_OU}'"
echo " Kerberos 'host/machine@${REALM}'  -> LDAP 'cn=machine,${HOSTS_OU}'"
echo "================================================================="

Lancez le script.

bash configure-identity-mapping.sh
=== 1. Set the translation rules (Authz-Regexp) ===
=== 2. Insert the rules into cn=config ===
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"


=================================================================
 Success: The identity mapping (Identity Mapping) is configured.
 Kerberos 'user@LAB.LOCAL'          -> LDAP 'uid=user,ou=people,dc=lab,dc=local'
 Kerberos 'host/machine@LAB.LOCAL'  -> LDAP 'cn=machine,ou=hosts,dc=lab,dc=local'
================================================================

Q154.

Comment tester la correspondance entre principal et DIT ?

Recherchez comment utiliser les commandes kinit et klist avec une identité d'utilisateur de l'annuaire. Cherchez ensuite comment appeler la commande ldapwhoami pour valider cette identité.

Voici un exemple de séquence de test en trois étapes :

  1. Demandez un ticket Kerberos pour Leia.

    kinit leia
    Password for leia@LAB.LOCAL:

    Utilisez le mot de passe généré lors de la création des comptes utilisateurs de l'annuaire.

  2. Vérifiez que le ticket est dans le cache.

    klist
    Ticket cache: FILE:/tmp/krb5cc_1000
    Default principal: leia@LAB.LOCAL
    
    Valid starting       Expires              Service principal
    18/05/2026 11:03:34  18/05/2026 21:03:34  krbtgt/LAB.LOCAL@LAB.LOCAL
        renew until 19/05/2026 11:03:25
  3. Interrogez LDAP avec le mécanisme GSSAPI.

    ldapwhoami -Y GSSAPI
    SASL/GSSAPI authentication started
    SASL username: leia@LAB.LOCAL
    SASL SSF: 256
    SASL data security layer installed.
    dn:uid=leia,ou=people,dc=lab,dc=local

Le résultat de la commande ldapwhoami prouve non seulement que l'authentification Kerberos est acceptée via un canal sécurisé (SASL SSF: 256), mais aussi que le moteur LDAP a parfaitement traduit le principal Kerberos entrant (leia@LAB.LOCAL) vers son identité annuaire exacte (dn:uid=leia,ou=people,dc=lab,dc=local) grâce aux règles de correspondance.

Q155.

Comment intégrer l'utilisation de Kerberos dans l'accès transparent à l'annuaire depuis le système client ?

Créez le principal associé au compte de service nslcd-proxy déjà créé lors des étapes précédentes.

Recherchez les paramètres à utiliser pour reconfigurer le service nslcd afin qu'il fasse appel à la gestion de tickets Kerberos à partir de son identité propre.

Rassemblez les instructions dans un script.

Copiez l'exemple de code ci-dessous dans le fichier configure-nslcd-proxy.sh.

#!/usr/bin/env bash

# Enable strict mode
set -euo pipefail

readonly REALM="LAB.LOCAL"
readonly PROXY_PRINC="nslcd-proxy@${REALM}"
readonly KEYTAB_DIR="/etc/nslcd"
readonly KEYTAB_FILE="${KEYTAB_DIR}/nslcd.keytab"
readonly NSLCD_CONFIG="/etc/nslcd.conf"
readonly NLSCD_DEFAULTS="/etc/default/nslcd"

echo "=== 1. Installing dependencies (kstart and SASL/GSSAPI) ==="
sudo apt update
sudo DEBIAN_FRONTEND=noninteractive apt install -y kstart libsasl2-modules-gssapi-mit

echo "=== 2. Creating service account and extracting key ==="
# Retrieve the Kerberos admin secret
KADMIN_PASS=$(head -n 1 ~/.kadmin_pass)

# Create the key directory
sudo mkdir -p "${KEYTAB_DIR}"

# Create principal (|| true prevents script failure if principal already exists)
sudo kadmin -p admin/admin -w "${KADMIN_PASS}" -q "addprinc -randkey ${PROXY_PRINC}" >/dev/null 2>&1 || true

# Extract keytab directly to its final location
sudo kadmin -p admin/admin -w "${KADMIN_PASS}" -q "ktadd -k ${KEYTAB_FILE} ${PROXY_PRINC}"

echo "=== 3. Cryptographic isolation (least privilege) ==="
# Directory and file are owned exclusively by nslcd
sudo chown -R nslcd:nslcd "${KEYTAB_DIR}"
# 700: Only nslcd can access the directory
sudo chmod 700 "${KEYTAB_DIR}"
# 400: Only nslcd can read the key
sudo chmod 400 "${KEYTAB_FILE}"

echo "=== 4. Configuring k5start / nslcd integration ==="
# Inject configuration so Debian manages the ticket automatically
if ! grep -q "^K5START_START=" "${NLSCD_DEFAULTS}"; then
        sudo tee -a "${NLSCD_DEFAULTS}" >/dev/null <<EOF

# --- Kerberos automatic configuration ---
K5START_START="yes"
K5START_KEYTAB="${KEYTAB_FILE}"
K5START_PRINCIPAL="${PROXY_PRINC}"
EOF
        echo " k5start configuration added to ${NLSCD_DEFAULTS}."
else
        echo " k5start configuration already present."
fi

echo "=== 5. Reconfiguring authentication in nslcd.conf ==="
# Remove old clear-text authentication directives
sudo sed -i '/^binddn/d' "${NSLCD_CONFIG}"
sudo sed -i '/^bindpw/d' "${NSLCD_CONFIG}"

# Enable GSSAPI mechanism
if ! sudo grep -q "^sasl_mech GSSAPI" "${NSLCD_CONFIG}"; then
        echo "sasl_mech GSSAPI" | sudo tee -a "${NSLCD_CONFIG}" >/dev/null
fi

# Set the ticket cache path generated by k5start
if ! sudo grep -q "^krb5_ccname" "${NSLCD_CONFIG}"; then
        echo "krb5_ccname /tmp/krb5cc_nslcd" | sudo tee -a "${NSLCD_CONFIG}" >/dev/null
fi

echo "=== 6. Applying configuration ==="
sudo systemctl restart nslcd

Lancez le script.

bash configure-nslcd-proxy.sh
=== 1. Installing dependencies (kstart and SASL/GSSAPI) ===
Réception de : 1 file:/etc/apt/mirrors/debian.list Mirrorlist [30 B]
Réception de : 2 file:/etc/apt/mirrors/debian-security.list Mirrorlist [39 B]
Atteint : 3 https://deb.debian.org/debian testing InRelease
Atteint : 4 https://deb.debian.org/debian testing-updates InRelease
Atteint : 5 https://deb.debian.org/debian testing-backports InRelease
Atteint : 6 https://deb.debian.org/debian-security testing-security InRelease
Tous les paquets sont à jour.
kstart est déjà la version la plus récente (4.3-1).
libsasl2-modules-gssapi-mit est déjà la version la plus récente (2.1.28+dfsg1-11).
Sommaire :
  Mise à niveau de : 0. Installation de : 0, Supprimé : 0. Non mis à jour : 0
=== 2. Creating service account and extracting key ===
Authenticating as principal admin/admin with password.
Entry for principal nslcd-proxy@LAB.LOCAL with kvno 5, encryption type aes256-cts-hmac-sha1-96 added to keytab WRFILE:/etc/nslcd/nslcd.keytab.
Entry for principal nslcd-proxy@LAB.LOCAL with kvno 5, encryption type aes128-cts-hmac-sha1-96 added to keytab WRFILE:/etc/nslcd/nslcd.keytab.
=== 3. Cryptographic isolation (least privilege) ===
=== 4. Configuring k5start / nslcd integration ===
 k5start configuration already present.
=== 5. Reconfiguring authentication in nslcd.conf ===
=== 6. Applying configuration ===

Vérifiez l'état du service nslcd avant de passer à la suite.

systemctl status nslcd.service

Q156.

Comment tester et valider la transparence des accès sécurisés à l'annuaire LDAP ?

Reprenez les mêmes tests que ceux effectués avant la mise en place de Kerberos.

Le plus simple consiste à utiliser la bascule d'identité locale avec la commande su -.

Copiez le mot de passe du compte leia par exemple.

cat .ldap_leia_pass

Prenez l'identité de ce compte.

su - leia
Password:
su: warning: cannot change directory to /ahome/leia: Aucun fichier ou dossier de ce nom
leia@ldap-clnt:/home/etu$

Vérifiez dans le journal du service que la requête sur ce compte a bien été émise.

journalctl -n 8 -u nslcd.service
ldap-clnt systemd[1]: Starting nslcd.service - LDAP connection daemon...
ldap-clnt nslcd[8083]: Starting Keep alive Kerberos ticket: k5start.
ldap-clnt nslcd[8096]: version 0.9.13 starting
ldap-clnt nslcd[8096]: accepting connections
ldap-clnt nslcd[8083]: Starting LDAP connection daemon: nslcd.
ldap-clnt systemd[1]: Started nslcd.service - LDAP connection daemon.
ldap-clnt nslcd[8096]: [b0dc51] <passwd="luke"> (re)loading /etc/nsswitch.conf
ldap-clnt nslcd[8096]: [7b8ddc] <passwd="leia"> (re)loading /etc/nsswitch.conf

L'intégration de l'accès à l'annuaire est à nouveau fonctionnelle. Arrêtons nous un instant pour relancer une capture de trafic réseau et observer le résultat.

Lancez une capture de trafic côté serveur.

tshark -i enp0s1 -Y "ldap" -V >ldap-krb5.trace

Procédez à nouveau à un changement d'identité côté client pour alimenter la capture.

su - leia

Arrêtez la capture avec Ctrl+c, ouvrez le fichier ldap-krb5.trace et recherchez les informations sur l'authentification.

grep -A8 -i bindrequest ldap-krb5.trace
    LDAPMessage bindRequest(1) "<ROOT>" sasl
        messageID: 1
        protocolOp: bindRequest (0)
            bindRequest
                version: 3
                name: <MISSING>
                authentication: sasl (3)
                    sasl
                        mechanism: GSSAPI
                        credentials […]: 6082...
                        GSS-API Generic Security Service Application Program Interface
                    OID: 1.2.840.113554.1.2.2 (KRB5 - Kerberos 5)

C'est déjà nettement mieux ! Avec Kerberos, il n'est plus question d'échanger des identités et des mots de passe, mais des tickets. De plus, le contenu des segments TCP (payload) est chiffré.

Le vol d'identité n'est donc plus possible. Toutefois, la sécurisation des transactions entre le client et le serveur n'est pas totalement satisfaisante, car la capture montre que le service LDAP est utilisé.

Vous devez donc mettre en place un mécanisme de sécurisation supplémentaire : TLS.

7.5. Sécuriser les échanges avec TLS

Partant d’un service LDAP fonctionnel, on sécurise maintenant les échanges entre le serveur et ses clients à l’aide du protocole Transport Layer Security (TLS). Cette section met en place une autorité de certification locale, génère les certificats X.509 du serveur et configure la couche dynamique cn=config du démon slapd.

En situation réelle de production, on ferait appel à une autorité de certification tierce publique comme Let’s Encrypt, ou à une PKI interne d’entreprise. Dans le contexte d’une maquette d’enseignement, une CA auto-signée est suffisante.

Avant de passer à la gestion de certificats et de clés, il faut préciser comment le service LDAP utilise TLS.

Q157.

Quelle est la différence entre ldaps:// et StartTLS pour sécuriser l'accès à un annuaire LDAP ?

Recherchez les avantages et inconvénients des deux approches. Vous allez découvrir qu'il n'est pas facile de trancher entre les deux choix.

Il existe une contradiction apparente entre les standards RFC qui définissent la théorie et la réalité opérationnelle de la production.

  • ldaps:// (port 636/tcp)

    Établit immédiatement le tunnel TLS avant tout dialogue LDAP (comme HTTPS). C'est aujourd'hui la norme recommandée en production car elle facilite le routage via des répartiteurs de charge (Load Balancers) et empêche les attaques par repli (downgrade attacks).
  • StartTLS (port 389/tcp)

    Ouvre la connexion en clair, puis bascule en TLS après une requête spécifique. La documentation officielle d'OpenLDAP présente StartTLS comme « la norme » en partant du principe que le seul le port numéro 389 fait référence. Cependant, les pare-feux et les répartiteurs de charge doivent avoir une connaissance fine du protocole de couche application pour traiter correctement les flux ; ce qui va à l'encontre de la simplicité offerte un seul numéro de port.

Dans le cadre de ces travaux pratiques, il est essentiel de maintenir les deux numéros de port ouverts afin d'assurer des possibilités d'analyse réseau ultérieures.

Q158.

Comment répartir les certificats et les clés privées associées sur le serveur et le client LDAP ?

Proposez un tableau respectant la règle selon laquelle chaque extrémité de la session TLS détient sa propre clé privée, tandis que les certificats publics (et celui de l'autorité) sont partagés.

Tableau 5. Répartition des certificats et des clés privées pour le service LDAP (TLS)

Répertoire Client (ldap-clnt) Serveur (ldap-srvr)
/etc/ssl/certs/

ldap-ca.crt

ldap-clnt.crt

ldap-srvr.crt

ldap-ca.crt

ldap-clnt.crt

ldap-srvr.crt

/etc/ssl/private/

ldap-clnt.key

ldap-srvr.key


Q159.

Comment générer les certificats et la clé privée du serveur et du client LDAP ?

Recherchez les propriétés de l'option -x509 de la commande openssl qui permet de générer directement un certificat de type CA. Ce certificat signera ensuite les demandes (CSR) du serveur et du client.

[Note] Note

Dans le cadre de TLS moderne, l'intégration de l'extension SAN (Subject Alternative Name) dans les certificats est nécessaire. Cette recommandation fait suite à une observation du comportement des clients LDAP récents, qui ont tendance à rejeter les certificats ne contenant que le CN (Common Name).

Codez un script qui rassemble tous les traitements et stocke les clés et les certificats dans un répertoire dédié. Si le code du script qui suit est enregistré sur le serveur dans le fichier generate-ldap-certs.sh, on lance le traitement en tant qu'utilisateur normal.

Copiez l'exemple de code ci-dessous dans le fichier generate-ldap-certs.sh.

#!/usr/bin/env bash

set -euo pipefail

LDAP_CA="ldap-ca"
LDAP_SERVER="ldap-srvr"
LDAP_CLIENT="ldap-clnt"
DOMAIN="lab.local"
CERT_DIR="${HOME}/certs"
CA_REQ_CONF="ca_req.conf"

mkdir -p "${CERT_DIR}"
chmod 700 "${CERT_DIR}"
cd "${CERT_DIR}"

gen_key() {
        local name="$1"
        local algo="$2"
        case "${algo}" in
        ed25519) openssl genpkey -algorithm ed25519 -out "${name}.key" ;;
        rsa) openssl genpkey -algorithm rsa -pkeyopt rsa_keygen_bits:4096 -out "${name}.key" ;;
        *)
                echo "Unsupported algorithm: ${algo}" >&2
                exit 1
                ;;
        esac
}

issue_cert() {
        local ca_name="$1"
        local cert_name="$2"
        local usage="$3"
        local algo="$4"
        local ext

        gen_key "${cert_name}" "${algo}"
        openssl req -new -key "${cert_name}.key" -out "${cert_name}.csr" -subj "/CN=${cert_name}.${DOMAIN}"

        if [[ ${usage} == "server" ]]; then
                ext="extendedKeyUsage=serverAuth\nsubjectAltName=DNS:${cert_name}.${DOMAIN},DNS:${cert_name}"
        else
                ext="extendedKeyUsage=clientAuth"
        fi

        openssl x509 -req -in "${cert_name}.csr" -CA "${ca_name}.crt" -CAkey "${ca_name}.key" -CAcreateserial \
                -out "${cert_name}.crt" -days 730 -extensions v3 -extfile <(printf '%b\n' "[v3]" \
                        "basicConstraints=CA:FALSE" "keyUsage=critical,digitalSignature" \
                        "subjectKeyIdentifier=hash" "authorityKeyIdentifier=keyid,issuer" "${ext}")
}

gen_key "${LDAP_CA}" ed25519
cat >"${CA_REQ_CONF}" <<'EOF'
[req]
distinguished_name=req
[v3_ca]
basicConstraints=critical,CA:TRUE
keyUsage=critical,keyCertSign,cRLSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always,issuer
EOF
openssl req -x509 -new -nodes -key "${LDAP_CA}.key" -days 3650 -subj "/CN=LDAP-CA" -out "${LDAP_CA}.crt" \
        -extensions v3_ca -config "${CA_REQ_CONF}"

issue_cert "${LDAP_CA}" "${LDAP_SERVER}" server ed25519
issue_cert "${LDAP_CA}" "${LDAP_CLIENT}" client ed25519

rm -f -- ./*.csr ./*.srl "${CA_REQ_CONF}"

echo "Certificates and keys generated in ${CERT_DIR}"
echo "Transfer to the client: ${LDAP_CA}.crt"
echo "  LDAP: ${LDAP_SERVER}.crt  ${LDAP_CLIENT}.key  ${LDAP_CLIENT}.crt"

exit 0

Lancez le script et affichez la liste des fichiers du dossier ~/certs/.

bash generate-ldap-certs.sh
Certificate request self-signature ok
subject=CN=ldap-srvr.lab.local
Certificate request self-signature ok
subject=CN=ldap-clnt.lab.local
Certificates and keys generated in /home/etu/certs
Transfer ldap-ca.crt, ldap-clnt.key, ldap-clnt.crt, and ldap-srvr.crt to the client.
ls -1 certs/
ldap-ca.crt
ldap-ca.key
ldap-ca.srl
ldap-clnt.crt
ldap-clnt.key
ldap-srvr.crt
ldap-srvr.key

Q160.

Comment déposer ou transférer les certificats et les clés dans les répertoires définis ?

Connaissant les répertoires cibles, copiez directement les fichiers sur le serveur. Dans le cas du client, vous devez d'abord les transférer avant de les copier.

  • Copiez les fichiers directement du dossier local sur le serveur. Quand le démon slapd démarre, il perd ses privilèges root et devient l'utilisateur système openldap. C'est cet utilisateur qui doit posséder la clé privée.

    Lancez le script copy-install-tls-certs.sh sur le serveur :

    cat << EOF >copy-install-tls-certs.sh
    #!/usr/bin/env bash
    
    set -euo pipefail
    
    DEST_DIR="/etc/ldap/certs"
    SRC_DIR="${HOME}/certs"
    
    # 1. Create the dedicated directory if it does not exist
    sudo mkdir -p "${DEST_DIR}"
    
    # 2. Copy files from the source (your certificate generation directory)
    # Copy the CA, the server certificate, and the private key
    for cert in ldap-ca.crt ldap-srvr.crt ldap-srvr.key; do
            sudo cp "${SRC_DIR}/${cert}" "${DEST_DIR}/"
    done
    
    # 3. Grant full ownership to the openldap user
    # This solves the "Permission denied" issue when leaving the root-owned directory
    sudo chown -R openldap:openldap "${DEST_DIR}"
    
    # 4. Apply strict permissions:
    # - 400: Only openldap can read the private key
    # - 444: Read-only for public certificates
    sudo chmod 400 "${DEST_DIR}/ldap-srvr.key"
    for cert in ldap-ca.crt ldap-srvr.crt; do
            sudo chmod 444 "${DEST_DIR}/${cert}"
    done
    
    echo "Certificates deployed and secured in ${DEST_DIR}"
    EOF
    
    bash copy-install-tls-certs.sh
  • Commencez par transférer le dossier ~/certs sur le client via scp dans um répertoire temporaire identique. Appliquez ensuite une politique similaire, mais adaptée au démon de résolution nslcd.

    Lancez le script copy-install-tls-certs.sh sur le client :

    cat << EOF >copy-install-tls-certs.sh
    #!/usr/bin/env bash
    
    set -euo pipefail
    
    # 1. Copy the certs folder from the server to the client.
    scp -r ldap-srvr:~/certs ~
    
    # 2. Copy the public certificates.
    sudo cp ~/certs/ldap-ca.crt /etc/ssl/certs/
    sudo cp ~/certs/ldap-clnt.crt /etc/ssl/certs/
    sudo cp ~/certs/ldap-srvr.crt /etc/ssl/certs/
    
    # 3. Apply standard system read permissions to the certificates.
    sudo chown root:root /etc/ssl/certs/ldap-ca.crt /etc/ssl/certs/ldap-clnt.crt /etc/ssl/certs/ldap-srvr.crt
    sudo chmod 644 /etc/ssl/certs/ldap-ca.crt /etc/ssl/certs/ldap-clnt.crt /etc/ssl/certs/ldap-srvr.crt
    
    # 4. Copy and secure the client's private key.
    sudo cp ~/certs/ldap-clnt.key /etc/ssl/private/
    
    # 5. Transfer full ownership to the owner of the nslcd daemon.
    sudo chown nslcd:nslcd /etc/ssl/private/ldap-clnt.key
    sudo chmod 400 /etc/ssl/private/ldap-clnt.key
    
    # 6. Clean up the standard user's temporary directory.
    rm -rf ~/certs
    
    # 7. Update the system's trusted certificate store to include the new CA certificate.
    sudo cp /etc/ssl/certs/ldap-ca.crt /usr/local/share/ca-certificates/ldap-ca.crt
    sudo update-ca-certificates
    EOF
    
    bash copy-install-tls-certs.sh

    Les commandes du point 7 ajoutent le certificat de l'autorité LDAP au magasin de CA du système en copiant ldap-ca.crt dans /usr/local/share/ca-certificates/ puis en régénérant le bundle /etc/ssl/certs/ca-certificates.crt avec update-ca-certificates, afin que tous les clients TLS du système puissent vérifier et faire confiance au certificat du serveur LDAP.

Q161.

Comment fonctionnent les seuils du mécanisme Security Strength Factor ?

Recherchez dans la documentation OpenLDAP, la présentation de l'indicateur de la force de protection SSF.

Voici une présentation résumée qui met en relation les valeurs de l'indicateur SSF avec les paramètres à régler dans la base de configuration cn=config.

Le Security Strength Factor (SSF) est une valeur entière qu'OpenLDAP associe à chaque connexion entrante pour quantifier son niveau de protection cryptographique. Un SSF de 0 désigne une connexion en clair, sans authentification forte ni chiffrement. Un SSF de 128 correspond approximativement à une session TLS avec AES-128, et une valeur de 256 à AES-256 ou à une connexion locale dont la sécurité est garantie par le système d'exploitation.

La directive olcSecurity fixe le seuil minimum que doit atteindre le SSF d'une connexion pour qu'elle soit acceptée. Si le SSF effectif est inférieur à ce seuil, le serveur retourne l'erreur LDAP 13 (Confidentiality required).

Le socket Unix local (ldapi:///) n'établit pas de session TLS. Son SSF brut est 0. La directive olcLocalSSF permet de lui attribuer une valeur conventionnelle, qui reflète la protection implicite apportée par le système d'exploitation (contrôle des droits Unix, isolation des processus). Cette valeur est prise en compte au démarrage de slapd et ne peut pas être modifiée à chaud.

Q162.

Quels sont les attributs de la base de configuration de l'annuaire LDAP à utiliser pour activer le chiffrement TLS ?

Quelles sont les valeurs associées à cahcun des attributs retenus ?

Recherchez les attributs relatifs à l'indicateur SSF et à la désignation des certificats.

Les attributs suivants doivent être définis à la racine de la configuration globale et s'appliquent à toutes les connexions, quelle que soit la base interrogée.

Tableau 6. Attributs TLS de la configuration OpenLDAP

Attribut Valeur Rôle
olcLocalSSF 256 SSF implicite attribué aux connexions via ldapi:/// (socket Unix local).Pris en compte uniquement au démarrage de slapd.
olcSecurity ssf=128 Seuil SSF minimum requis pour toute connexion. Les connexions avec une valeur SSF inférieure à 128 provoquent l'erreur 13 (Confidentiality required).
olcTLSCACertificateFile /etc/ldap/certs/ldap-ca.crt Certificat de l'autorité de certification.
olcTLSCertificateFile /etc/ldap/certs/ldap-srvr.crt Certificat X.509 du serveur LDAP, présenté aux clients lors du handshake TLS.
olcTLSCertificateKeyFile /etc/ldap/certs/ldap-srvr.key Clé privée associée au certificat serveur.

Q163.

Comment activer l'utilisation des certificats sur le serveur LDAP ?

Recherchez la syntaxe de configuration des attributs d'affectation des certificats, puis créez et appliquez le fichier LDIF.

Voici un exemple de fichier configure-tls-certs.ldif.

dn: cn=config
changetype: modify
replace: olcTLSCACertificateFile
olcTLSCACertificateFile: /etc/ldap/certs/ldap-ca.crt
-
replace: olcTLSCertificateFile
olcTLSCertificateFile: /etc/ldap/certs/ldap-srvr.crt
-
replace: olcTLSCertificateKeyFile
olcTLSCertificateKeyFile: /etc/ldap/certs/ldap-srvr.key

Lancez la modification de configuration :

sudo ldapmodify -Y EXTERNAL \
    -H ldapi:/// \
    -f configure-tls-certs.ldif
SASL/EXTERNAL authentication started
SASL username: gidNumber=0+uidNumber=0,cn=peercred,cn=external,cn=auth
SASL SSF: 0
modifying entry "cn=config"

Q164.

Comment régler les seuils SSF dans la configuration du serveur LDAP ?

Recherchez la syntaxe LDIF d'application des seuils SSF, puis appliuqez les valeurs définies dans le tableau ci-dessus.

Voici un exemple de fichier enable-TLS-SSF.ldif.

dn: cn=config
changetype: modify
replace: olcLocalSSF
olcLocalSSF: 256
-
add: olcSecurity
olcSecurity: ssf=128

Lancez la modification de configuration :

sudo ldapmodify -Y EXTERNAL \
    -H ldapi:/// \
    -f configure-tls-certs.ldif
[Attention] Attention

L'attribut olcLocalSSF est particulier. Sa valeur n'est pas prise en charge dynamiquement. Il faut redémarrer le service après modification.

sudo systemctl restart slapd.service

Q165.

Quelles sont les modifications à apporter au fichier /etc/ldap/ldap.conf pour désigner l'autorité de certification locale ?

Installez le paquet libldap-common et consultez la page de manuel du fichier de configuration ldap.conf pour trouvez les entrées relatives à l'utilisation de TLS.

Vérifiez que le paquet libldap-common est installé.

sudo apt install -y libldap-common

Consultez la page de manuel et sélectionnez les deux paramètres nécessaires dans le contexte des travaux pratiques.

man ldap.conf

Ce fichier définit le comportement par défaut des outils en ligne de commande comme ldapsearch. Il assure la vérification stricte du certificat serveur TLS via TLS_CACERT et TLS_REQCERT, ce qui impose que toute connexion chiffrée utilise un certificat signé par la CA locale avant d’être acceptée.

Complétez la configuration avec ces deux paramètres.

sudo touch /etc/ldap/ldap.conf
cat << EOF | sudo tee -a /etc/ldap/ldap.conf
URI ldap://ldap-srvr.lab.local
BASE dc=lab,dc=local

TLS_CACERT /etc/ldap/certs/ldap-ca.crt
TLS_REQCERT demand
EOF

Q166.

Comment tester l'utilisation de TLS avec StartTLS lors de l'envoi d'une requête LDAP ?

Recherchez dans la liste des options de la commande ldapsearch celle qui impose l'utilisation de TLS.

Commencez par lancer une requête avec les mêmes options que dans les parties précédentes.

ldapsearch -H ldap://ldap-srvr.lab.local \
    -b "dc=lab,dc=local" \
    -D "cn=admin,dc=lab,dc=local" \
    -y .ldap_admin_pass \
    uid=anakin
ldap_bind: Confidentiality required (13)
additional info: confidentiality required

La requête sans utilisation de TLS échoue. La valeur SSF de cette requête est insuffisante.

Lancez la même requête en ajoutant l'option -ZZ pour déclencher le recours à StartTLS.

ldapsearch -ZZ -LLL -H ldap://ldap-srvr.lab.local \
    -b "dc=lab,dc=local" \
    -D "cn=admin,dc=lab,dc=local" \
    -y .ldap_admin_pass \
    uid=anakin
dn: uid=anakin,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: anakin
cn: Anakin Skywalker
givenName: Anakin
sn: Skywalker
mail: anakin@lab.local
userPassword:: e0FSR09OMn0kYXJnb24yaWQkdj0xOSRtPTcxNjgsdD01LHA9MSRZc2xGeXU5Wjl
 hS2lvSENWMjgvT0NBJEFnUWRBRnhrODlIMW1mdW1zaFpuMThYSFgvTVlmZ0ZHa05pTW9NR1pPaTA=
shadowLastChange: 20597
loginShell: /bin/bash
uidNumber: 10001
gidNumber: 10001
homeDirectory: /ahome/anakin
gecos: Anakin Skywalker

Cette fois-ci, la requête est acceptée par le serveur et vous obtenez une réponse.

Vous pouvez aussi afficher les détails de la transaction StartTLS avec la syntaxe de requête suivante :

LDAPTLS_REQCERT=allow \
ldapsearch -d 1 -ZZ -LLL -H ldap://ldap-srvr.lab.local \
    -b "dc=lab,dc=local" \
    -D "cn=admin,dc=lab,dc=local" \
    -y .ldap_admin_pass \
    uid=anakin \
    2>&1 | grep -i tls
TLS trace: SSL_connect:before SSL initialization
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS write client hello
TLS trace: SSL_connect:SSLv3/TLS read server hello
TLS trace: SSL_connect:TLSv1.3 read encrypted extensions
TLS certificate verification: depth: 1, err: 0, subject: /CN=LDAP-CA, issuer: /CN=LDAP-CA
TLS certificate verification: depth: 0, err: 0, subject: /CN=ldap-srvr.lab.local, issuer: /CN=LDAP-CA
TLS trace: SSL_connect:SSLv3/TLS read server certificate
TLS trace: SSL_connect:TLSv1.3 read server certificate verify
TLS trace: SSL_connect:SSLv3/TLS read finished
TLS trace: SSL_connect:SSLv3/TLS write change cipher spec
TLS trace: SSL_connect:SSLv3/TLS write finished
TLS trace: SSL_connect:SSL negotiation finished successfully
TLS trace: SSL_connect:SSL negotiation finished successfully
TLS trace: SSL_connect:SSLv3/TLS read server session ticket
TLS trace: SSL_connect:SSL negotiation finished successfully
TLS trace: SSL_connect:SSL negotiation finished successfully
TLS trace: SSL_connect:SSLv3/TLS read server session ticket
TLS trace: SSL3 alert write:warning:close notify

Q167.

Comment activer le service ldaps:// ?

Recherchez la modification à effectuer dans le fichier /etc/default/slapd.

Complétez la liste de la variable SLAPD_SERVICES avec l'URI ldaps:///.

sudo sed -i '/^SLAPD_SERVICES=/{
  /ldaps:\/\//! s/"$/ ldaps:\/\/\/"/
}' /etc/default/slapd

Redémarrez le service pour que la modification soit prise en compte.

sudo systemctl restart slapd.service

Vérifiez que le service est bien en écoute sur le port 636.

sudo ss -tlnp 'sport = :636'
State      Recv-Q      Send-Q      Local Address:Port     Peer Address:Port  Process
LISTEN     0           2048              0.0.0.0:636           0.0.0.0:*      users:(("slapd",pid=16653,fd=10))
LISTEN     0           2048                 [::]:636              [::]:*      users:(("slapd",pid=16653,fd=11))

Q168.

Comment tester l'utilisation de TLS avec l'URL ldaps:// ?

Reprenez l'exemple de requête ldapsearch en adaptant les options.

Voici un exemple de requête directe sur le port numéro 636 du service LDAP.

ldapsearch -LLL -H ldaps://ldap-srvr.lab.local \
    -D "cn=admin,dc=lab,dc=local" \
    -y .ldap_admin_pass \
    uid=anakin
dn: uid=anakin,ou=users,dc=lab,dc=local
objectClass: inetOrgPerson
objectClass: posixAccount
objectClass: shadowAccount
uid: anakin
cn: Anakin Skywalker
givenName: Anakin
sn: Skywalker
mail: anakin@lab.local
userPassword:: e0FSR09OMn0kYXJnb24yaWQkdj0xOSRtPTcxNjgsdD01LHA9MSRZc2xGeXU5Wjl
 hS2lvSENWMjgvT0NBJEFnUWRBRnhrODlIMW1mdW1zaFpuMThYSFgvTVlmZ0ZHa05pTW9NR1pPaTA=
shadowLastChange: 20597
loginShell: /bin/bash
uidNumber: 10001
gidNumber: 10001
homeDirectory: /ahome/anakin
gecos: Anakin Skywalker

Cette question termine les manipulations côté serveur. Vous pouvez donc logiquement passer à la configuration et aux tests côté client LDAP.

Q169.

Quelles sont les modifications à apporter au fichier /etc/ldap/ldap.conf pour utiliser l'autorité de certification locale ?

Reprenez la démarche suivie sur le serveur côté client.

Vérifiez que le paquet libldap-common est bien installé.

sudo apt install -y libldap-common

Les paramètres de ce fichier garantissent une vérification stricte du certificat du serveur TLS via les paramètres TLS_CACERT et TLS_REQCERT, ce qui implique que toute connexion chiffrée doit utiliser un certificat signé par la CA locale pour être acceptée.

sudo touch /etc/ldap/ldap.conf
cat << EOF | sudo tee -a /etc/ldap/ldap.conf
URI ldap://ldap-srvr.lab.local
BASE dc=lab,dc=local

TLS_CACERT /etc/ssl/certs/ldap-ca.crt
TLS_REQCERT demand
EOF

Q170.

Comment tester les différentes utilisations de TLS lors de l'envoi d'une requête LDAP ?

Reprenez les mêmes tests que ceux effectués côté serveur.

  • Requête sans demande de chiffrement :

    ldapsearch -LLL -H ldap://ldap-srvr \
        -D "cn=admin,dc=lab,dc=local" \
        -y .ldap_admin_pass \
        -b "dc=lab,dc=local" \
        uid=padme
    ldap_bind: Confidentiality required (13)
        additional info: confidentiality required
  • Requête avec ouverture StartTLS :

    ldapsearch -LLL -ZZ -H ldap://ldap-srvr \
        -D "cn=admin,dc=lab,dc=local" \
        -y .ldap_admin_pass \
        -b "dc=lab,dc=local" \
        uid=padme
    dn: uid=padme,ou=users,dc=lab,dc=local
    objectClass: inetOrgPerson
    objectClass: posixAccount
    objectClass: shadowAccount
    uid: padme
    cn: Padme Amidala
    givenName: Padme
    sn: Amidala
    mail: padme@lab.local
    userPassword:: e0FSR09OMn0kYXJnb24yaWQkdj0xOSRtPTcxNjgsdD01LHA9MSRDMzJtb0xLbEE
     1ZVFNZVVwWlNybXF3JFg0M1FMOVdrWGxGdW1Eak9pOGtmc3BxY1Nsc2Q1Q1QwZXRKUExiTUE3bVU=
    shadowLastChange: 20597
    loginShell: /bin/bash
    uidNumber: 10000
    gidNumber: 10000
    homeDirectory: /ahome/padme
    gecos: Padme Amidala
  • Requête directe ldaps:// :

    ldapsearch -LLL -H ldaps://ldap-srvr \
        -D "cn=admin,dc=lab,dc=local" \
        -y .ldap_admin_pass \
        -b "dc=lab,dc=local" \
        uid=padme
    dn: uid=padme,ou=users,dc=lab,dc=local
    objectClass: inetOrgPerson
    objectClass: posixAccount
    objectClass: shadowAccount
    uid: padme
    cn: Padme Amidala
    givenName: Padme
    sn: Amidala
    mail: padme@lab.local
    userPassword:: e0FSR09OMn0kYXJnb24yaWQkdj0xOSRtPTcxNjgsdD01LHA9MSRDMzJtb0xLbEE
     1ZVFNZVVwWlNybXF3JFg0M1FMOVdrWGxGdW1Eak9pOGtmc3BxY1Nsc2Q1Q1QwZXRKUExiTUE3bVU=
    shadowLastChange: 20597
    loginShell: /bin/bash
    uidNumber: 10000
    gidNumber: 10000
    homeDirectory: /ahome/padme
    gecos: Padme Amidala

La sécurisation des échange entre clients et serveur LDAP est maintenant complètement validée. Voici un tableau récapitulatif des modaltés de connexion.

Tableau 7. Comportement des connexions selon l'indicateur SSF

Type de connexion Protocole / Transport SSF effectif Seuil requis Résultat
Administration root locale serveur ldapi:/// + SASL EXTERNAL 256 (via olcLocalSSF) 128 Autorisé — SSF local (256) ≥ seuil (128)
Client réseau avec StartTLS ldap:// + -ZZ 128 à 256 selon le cipher AES 128 Autorisé — SSF TLS ≥ seuil (128)
Client réseau avec LDAPS ldaps:// 128 à 256 selon le cipher AES 128 Autorisé — SSF TLS ≥ seuil (128)
Client réseau sans TLS ldap:// sans -ZZ 0 128 Refusé — erreur 13 (Confidentiality required)