ElasticSearch

ElasticSearch est un moteur de recherche et d’analyse RESTful distribué, d’après son site web (elastic.co). Très utilisé et même proposé sous forme de service par AWS, ce produit permet de gérer des recherches sur de grandes quantités de données.

C’est bien.

Mais cela devient moins amusant quand on le configure mal, les informaticiens pouvant être peu consciencieux ou débordés. Le résultat est alors sans appel : des moteurs de recherche internet (comme Shodan) indexent (trop) facilement les contenus mal protégés, et l’énorme quantité des données gérées par ElasticSearch deviennent purement et simplement disponibles et accessibles à la moindre requête anonyme.

D’après Shodan1, en 2018, 900 To de données ElasticSearch sont disponibles sans protection, et plus de 5 Po de données pour de clusters Hadoop.

Fuites de données

Exactis

Il s’agit du premier cas que j’ai repéré (ça qui ne signifie pas qu’il s’agisse du premier). La volumétrie fait peur : 2 To de données de 340 millions d’utilisateurs2. Pas de cartes bancaires, mais tout un tas de données de profilage, relevant de la vie privée, mais pouvant aussi servir à répondre aux questions de sécurité pour récupérer (frauduleusement) un accès à un quelconque service de messagerie, de réseautage social, etc.

Durée de vie

Ne pas faire attention et laisser les paramètres par défaut peut rapidement conduire à de gros ennuis : une étude de 2020 indique qu’une base non sécurisée est repérée par les méchants en huit heures3. Ils sont à l’affût !

Tellement courant

Les fuites de données dues à une mauvaise mise en oeuvre d’ElasticSearch sont si courantes que la CNIL a publié un guide de bonnes pratiques.

Moteur de recherche et d’analyse Elasticsearch : 4 bonnes pratiques pour renforcer la sécurité des données

Principe d’Elasticsearch

Elasicsearch est un outil de recherche, open source, très populaire. Son fonctionnement repose sur les index inversés, ou inverted indexes, qui recensent des caractéristiques associées à ces documents, comme par exemple des mots clés, mais il peut y avoir bien d’autres usages, comme le traitement d’un grand nombre de logs, sujet très pertinent en sécurité informatique.

Index inversé

Un index inversé est créé après examen de chacun des documents (« crawling »), et création des caractéristiques associées, que l’on définit selon ses besoins. A la suite de cela, on crée un index partant de ces caractéristiques et pointant vers les documents correspondant le mieux aux caractéristiques recherchées.

Dans des moteurs de recherche web (Yahoo, Google, Bing…) on tape une liste de mots clés, et l’index inversé nous renvoie les pages web les plus pertinentes qu’il a recensé auparavant.

Apache Lucene est un outil open source permettant l’indexation de documents, sur lequel est basé Elasticsearch, qui est une société commerciale mais qui propose des versions gratuites de son produit (qui reste open source).

Cluster

Conçu pour des requêtes complexes, et un nombre de documents très important, Elasticsearch se structure en clusters, dont chacun peut contenir de un à plusieurs milliers de nœuds, chaque nœud étant une machine de traitement.

Sharding

On comprend qu’une requête peut être complexe et avoir besoin de beaucoup de ressources, et donc utiliser plusieurs nœuds. De même, il peut arriver que l’indexation produise des tables si grandes qu’elles ne tiennent pas sur un seul nœud. Pour cela, on peut scinder un index sur plusieurs nœuds ; cela s’appelle le sharding.

Réplication

Comme toute bonne architecture distribuée digne de ce nom, toute donnée doit être dupliquée (ou répliquée) afin de pallier aux accidents mais aussi pour paralléliser les traitements, et Elasticsearch le permet.

Manipulons

ElasticSearch (que je vais abréger en ES) se manipule via des API Rest. Ce gros mot signifie qu’on appelle des requêtes HTTP avec une logique définie. Autant je trouve ça super pour développer une appli web, autant c’est pénible pour mes petits doigts quand il faut taper les commandes avec curl. Heureusement Kibana est une interface web qui permet de réaliser la plupart des opérations sur ES.

Opérations CRUD

Pour créer un index :

$ curl -XPUT 'localhost:9200/documents'

Pour ajouter un document (de format JSON) :

$ curl -XPUT 'localhost:9200/alerts/cloudtrail/1?pretty' -H 'Content-Type: application/json' -d fichier
$ curl -XPUT 'localhost:9200/alerts/cloudtrail?pretty' -H 'Content-Type: application/json' -d fichier

Les arguments sont le nom de l’index, le type du document, et son identifiant (facultatif). Pour un fichier JSON, depuis la version 6, il faut rajouter le type dans le header. Chouette.

Pour afficher les champs id et version du document #1.

$ curl -XGET 'localhost:9200/logs/cloudtrail/1?pretty&_source=id,version'

Pour savoir simplement si le document #1 existe :

$ curl -i -XHEAD 'localhost:9200/logs/cloudtrail/1?pretty'

Pour modifier un document :

$ curl -XPOST 'localhost:9200/alerts/cloudtrail/1?pretty' -H 'Content-Type: application/json' -d fichier

Il faut utiliser POST sur un document existant, et seuls les champs modifiés ont besoin d’être présents dans le fichier, lequel peut également « scripter » le résultat.

Sans surprise, pour supprimer un document, voici la commande :

$ curl -XDELETE 'localhost:9200/alerts/cloudtrail/1?pretty'

Pour avoir différentes informations sur le cluster, il faut jouer avec les commandes _cat.

$ curl -XGET 'localhost:9200/_cat/'
=^.^=
/_cat/allocation
/_cat/shards
/_cat/shards/{index}
/_cat/master
/_cat/nodes
/_cat/tasks
/_cat/indices
...

D’autres commandes utiles sont : _mget, _bulk.

Statut du machin

Différentes commandes permettent d’avoir des infos sur la santé d’ES. Exemples :

$ curl -XGET 'localhost:9200/_cat/health/?v&pretty'
epoch timestamp cluster status node.total node.data shards pri relo init unassign pending_tasks max_task_wait_time active_shards_percent
1535634422 15:07:02 elasticsearch yellow 1 1 6 6 0 0 5 0 - 54.5%

$ curl -XGET 'localhost:9200/_cluster/health/'
{"cluster_name":"elasticsearch","status":"yellow","timed_out":false,"number_of_nodes":1,"number_of_data_nodes":1,"active_primary_shards":6,"active_shards":6,"relocating_shards":0,"initializing_shards":0,"unassigned_shards":5,"delayed_unassigned_shards":0,"number_of_pending_tasks":0,"number_of_in_flight_fetch":0,"task_max_waiting_in_queue_millis":0,"active_shards_percent_as_number":54.54545454545454}

$curl -XGET 'localhost:9200/_cat/indices/?v&pretty'
health status index uuid pri rep docs.count docs.deleted store.size pri.store.size
green open .kibana ppRzSXt0Q8G8OXZg8o7_tQ 1 0 2 0 103.4kb 103.4kb
yellow open logs 8YYRLl5_SauA2sglf9YRfA 5 1 36886 0 32.2mb 32.2mb

Recherches et analyses

Les recherches sont similaires à ce qu’on imagine pour un moteur de recherche, tels que Google ou Yahoo. Un langage permet de créer la requête qui vous conviendra et qui vous rendra riche et célèbre, appelé DSL. Rien de mystérieux dans ce langage calqué sur du JSON, il est très souple et très puissant et permet de scripter des requêtes plus ou moins évoluées. Tout comme SQL, on arrivera facilement à faire des requêtes simples, alors que les requêtes complexes demanderont beaucoup de grattage de tête. Point important : les requêtes sont stateful, ce qui signifie qu’il n’y a pas de mécanisme genre curseur comme en SQL.

En gros, on peut demander quels sont les meilleurs documents selon nos critères, auquel cas un score est calculé (et peut être expliqué dans la réponse) et les meilleurs résultats sont affichés ; sinon on peut filtrer et demander si un enregistrement satisfait à nos critères ou pas (la réponse est alors binaire).

La puissance de l’algorithme

TF/IDF de son petit nom, l’algo qui sert de base pour le calcul du score des documents. Il doit être recalculé à chaque ajout de document, mais il ne dépend que de la base de documents indexés, et de rien d’autre. Il est au cœur du fonctionnement d’ES, mais je n’ai pas trouvé de présentation récente de son fonctionnement sur le site ES ; on peut trouver l’info ici (compose.com) ou ici (sur le site de Lucene, le moteur d’ES).

  • TF : Term frequency, calculé comme étant la racine carré du nombre d’occurrences d’un terme dans un document ; cela permet de savoir à quelle fréquence un terme apparaît dans un champ. Plus un terme apparaît dans un document, plus le document est pertinent ;
  • IDF : Inverse Document Frequency (à expliciter). Il permet de savoir à quelle fréquence un terme apparaît dans un index. Plus un terme est fréquent dans un index, moins il est différenciant.
  • La longueur d’un champ intervient aussi (plus la longueur du champ est court, plus l’apparition d’un terme à l’intérieur de celui-ci a de la pertinence). Ainsi, un terme trouvé dans le titre d’un livre induira un score plus élevé que s’il est trouvé dans le corps du texte du livre.

Quand une requête est lancée, les informations demandées dans la requêtes sont combinées avec les résultats de l’algo TF/IDF, et un score est associé à chaque document. Le tour est joué.

Analyse de données

ES permet aussi de réaliser des agrégations de données, ouvrant ainsi la possibilité à l’analyse de données (« analytics »). Il existe quatre types d’agrégation dans ES (je chercherai s’il existe une traduction) :

  • « Metric » qui permet de faire des calculs sur l’ensemble des données (ou sur un groupe logique, cf ci-dessous). Cela se rapproche des AVG(), SUM() du SQL ;
  • « Bucketing » réalise des groupes logiques de données à partir d’une requête de recherche, similaire au GROUP BY en SQL ;
  • « Matrix » est une fonction expérimentale portant sur plusieurs champs en même temps (à développer) ;
  • « Pipeline » permet d’enchaîner les agréations.
Champs textes

Les champs texte, de format assez libres, ne sont pas par défaut inclus dans les champs pouvant être requêtés (sic), car cela consomme beaucoup de ressources à indexer (et donc de mémoire). Si on souhaite pouvoir filter et requêter sur ces champs, il faut explicitement demander qu’ils soient intégrés dans le fielddata, qui est l’espace mémoire servant justement à ce type de requêtes.

Voir aussi