Paillasse/docs/adr/0009-elasticsearch-interne-sans-securite.md
Adam Belkacemi 777dd1cbc8 ajoute la recherche plein texte dans les cours et labs (bloc C)
Elasticsearch interne (jamais exposé, sécurité x-pack désactivée,
cohérent avec le reste des services internes de ce serveur), tas JVM
fixé à 512 Mo plutôt que le calcul automatique (jusqu'à 50 % de la
RAM système, désastreux sur ce serveur à 31 Go réels). Appels HTTP
directs depuis Laravel, pas de bibliothèque cliente pour un besoin
aussi simple. Index reconstruit après chaque synchronisation du
catalogue, page de recherche commune aux profs et aux élèves.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-10-14 13:24:13 +02:00

70 lines
3.6 KiB
Markdown

# ADR 0009 — Elasticsearch interne, sécurité x-pack désactivée
- **Date** : 2026-10-14
- **Statut** : accepté
## Contexte
Bloc C du CLAUDE.md : « ElasticSearch : recherche plein texte dans les cours
et les labs (seulement si le besoin est réel). » Adam a confirmé le besoin
explicitement (« fonce »). Catalogue minuscule (quelques labs, un seul
`cours.md` aujourd'hui) : aucun besoin d'un cluster, d'un cache de
répertoires exotique ou d'une bibliothèque cliente PHP dédiée.
## Décisions
**Une instance Elasticsearch 8.19, locale, jamais exposée.** Installée
depuis le dépôt APT officiel Elastic (clé GPG vérifiée, même principe que
Ceph/ADR 0007). Consommée uniquement par le portail, en PHP, sur
`127.0.0.1:9200` — jamais par un navigateur.
**Sécurité x-pack désactivée (`xpack.security.enabled: false`).**
L'installation standard active TLS + authentification par défaut depuis la
8.x (mot de passe généré, certificats auto-signés) — pertinent pour un
cluster multi-nœuds exposé, disproportionné pour une instance mono-nœud qui
ne parle qu'à elle-même sur la boucle locale. Cohérent avec le reste de ce
serveur : l'API OpenStack interne (`10.10.0.1`) et le MariaDB/Redis dédiés
au portail (`127.0.0.1:3307`/`6380`) n'ont pas non plus de TLS entre
services — l'isolation vient du pare-feu (`policy drop` par défaut) et de
l'écoute en local, pas d'une authentification par service. Désactiver x-pack
évite aussi de devoir stocker et faire tourner un mot de passe Elasticsearch
supplémentaire pour rien.
**Tas JVM réduit à 512 Mo (`-Xms512m -Xmx512m`), pas le calcul automatique
d'Elasticsearch.** Par défaut, Elasticsearch vise jusqu'à 50 % de la RAM
système — sur ce serveur à 31 Go réels (voir ADR 0007), cela aurait pu
réserver ~15 Go à un service qui indexe quelques dizaines de documents.
Mesuré après coup : ~900 Mo de RSS au total pour le processus, RAM
disponible du serveur restée stable (~6 Go) pendant tout le chantier.
**Appels HTTP directs (`Illuminate\Support\Facades\Http`), pas le client
PHP officiel `elastic/elasticsearch`.** Le besoin se limite à indexer des
documents et faire une recherche plein texte avec surlignage — deux appels
REST simples. Ajouter une bibliothèque cliente complète (et ses
dépendances) pour ça aurait été une techno sans besoin réel (CLAUDE.md,
section 8).
**Analyseur `french` d'Elasticsearch sur les champs `titre`/`contenu`.**
Livré avec Elasticsearch, pas un plugin à installer : améliore réellement la
pertinence sur du contenu pédagogique en français (élision, racines des
mots) sans coût d'exploitation supplémentaire.
**Reconstruction complète de l'index à chaque synchronisation**
(`labs:synchroniser`, `cours:synchroniser`), pas une mise à jour
incrémentale. Volume du catalogue trop faible pour que ça coûte quoi que ce
soit ; plus simple et plus sûr (jamais de document orphelin si un lab est
retiré).
## Conséquences
- Recherche vérifiée en réel avec un compte élève jetable : les deux vrais
documents existants (labs catalogués + `08-deux-lan-routeur/cours.md`,
contenu réel) retrouvés par recherche plein texte, extrait surligné
affiché, compte supprimé ensuite.
- `App\Services\Recherche\IndexRecherche::disponible()` renvoie `false` si
`ELASTICSEARCH_HOTE` n'est pas renseigné : la page de recherche affiche
alors un message d'indisponibilité au lieu d'une erreur — même principe
que `StockageTravauxEleves::disponible()` pour le S3.
- En dette : pas de pagination des résultats (taille de catalogue bien en
dessous du besoin), pas de recherche à facettes (niveau, compétence) —
à ajouter si le catalogue grossit réellement.