Déploiement d'une stack ELK en mode Swarm

[][1]

Bonjour à tous, dans cet article nous allons vous présenter comment déployer la solution open source ELK en mode Swarm.

Vous verrez les questions que nous nous sommes posées afin d'en déterminer l’infrastructure, le dimensionnement, mais aussi comment déployer la Stack et la rendre hautement disponible.

Qu'est-ce que ELK ?

Aujourd'hui appelé Elastic Stack, « ELK » est l'acronyme de trois projets open source : [Elasticsearch][2], [Logstash][3] et [Kibana][4].

Elasticsearch

Elasticsearch est un moteur de recherche et d'analyse [RESTful][5] distribué, conçu pour répondre à une multitude de cas d'utilisation.

Qu'il s'agisse de données structurées ou non structurées, de données géographiques ou d'indicateurs, avec Elasticsearch, il est possible de lancer différents types de recherches, ou encore les associer entre elles.

Logstash

Logstash est un pipeline open source côté serveur, destiné au traitement des données.

Sa mission ? Ingérer simultanément des données provenant d'une multitude de sources, puis les transformer et les envoyer vers un système de stockage.

Le pipeline de traitement des événements Logstash comprend trois étapes :

entrées -> filtres -> sorties

Les entrées génèrent des événements, les filtres les modifient et les sorties les expédient ailleurs. Les entrées et les sorties prennent en charge des codecs qui permettent de coder ou de décoder les données à l’entrée ou à la sortie du pipeline sans avoir à utiliser un filtre séparé.

Kibana

Kibana permet de visualiser les données Elasticsearch et de naviguer dans la Suite Elastic.

[][6]

Qu'est-ce que Swarm ?

Swarm est un groupe de machines qui exécutent Docker et qui font partie d’un cluster. Vous continuez à exécuter les commandes Docker auxquelles vous êtes habitué, mais elles sont maintenant exécutées depuis un nœud manager.

Les managers Swarm peuvent utiliser plusieurs stratégies pour exécuter les containers, telles que le « nœud le plus vide » - qui utilise les machines les moins utilisées, ou « global », qui garantit que chaque nœud obtient exactement une instance du container spécifié.

Vous demandez à l'orchestrateur Swarm d'utiliser ces stratégies dans le fichier compose, tout comme celui que vous avez déjà utilisé auparavant.

Cas d'entreprise

Voici un cas d'entreprise afin d'appuyer les propos qui vont suivre :

Vous êtes consultant en informatique et une entreprise A fait appel à vos compétences afin de remplacer le puits de logs existant.


L'entreprise A n'utilise qu'une machine afin de récolter le Syslog de son routeur.


Le tout est sauvegardé dans un fichier, avec une rotation par jour. La taille de chaque fichier est en moyenne de 3 Go.


L'objectif est de remplacer ce puits de logs en un SIEM

Volumétrie

Afin d'avoir davantage de marge de manœuvre, le volume journalier stocké sur le disque a été fixé à 5Go.

La rétention des données selon la [directive 2006/24/CE][7] exige la conservation des données pendant une période allant de six mois à deux ans, en particulier en vue de pouvoir :

La volumétrie annuelle est donc de : 5Go * 365 = 1 825Go de données.

Dimensionnement

Maintenant que la volumétrie est évaluée, il faut assurer une continuité de service. C'est la raison pour laquelle l’ensemble des services ainsi que le matériel seront redondés.

Dans un premier temps, il faut s’assurer de la pérennité des données. La réplication de ces dernières est nécessaire car étant sensibles, l'entreprise ne peut se permettre d’en perdre. C'est pourquoi elles seront dupliquées 2 fois. Le stockage doit être au minimum de : 3 * 1 825 = 5 475Go, soit 5.34To.

Indexes et shards

Par défaut, un index est composé de 5 shards primary et d'1 réplica. Il est courant de voir des shards de taille comprise entre 20Go et 40Go. En reprenant le calcul volumétrique précédent, l'index net-security-syslog-* fera 1.8To de données au bout d’un an.

Avec au maximum 40Go de données par shards, il faudra donc : 1 825Go / 40Go ~= 47 shards. Pour être un peu plus à l'aise, les indexes seront dimensionnés avec des shards de 35Go environ, soit 52 shards sur 1 an pour l’index net-security-syslog-*.

Afin de ne pas avoir un seul index porteur de toutes les données, ce dernier sera divisé en plusieurs sous-indexes, datés par semaine, soit : net-security-syslog-%{+YYYY.ww}, eux-mêmes composés de 5 shards primaires et de 2 réplicas.

Pour terminer, l’infrastructure sera multipliée afin d’assurer une haute disponibilité, une répartition de la charge sur les différents nœuds, mais aussi une meilleure répartition des données afin d'avoir encore la totalité des données si jamais une ou plusieurs machines étaient défaillantes.

Prérequis

Pour ce cas d'entreprise, il faut :

Installer Docker 18.09.2

Pour commencer, effectuez l'installation de Docker en suivant les instructions sur le [site officiel][8] jusqu'à l'installation de [Docker CE][9],[Docker CLI][10] et [containerd][11].

1$ apt-get install docker-ce=5:18.09.2~3-0~ubuntu-bionic \
2                  docker-ce-cli=5:18.09.2~3-0~ubuntu-bionic \
3                  containerd.io
1$ systemctl enable docker
2$ service docker start
3$ usermod -aG docker user

Puis déconnectez / reconnectez-vous en tant que user.

Initialisation et configuration de votre cluster Swarm

Pour initialiser Swarm, effectuez les commandes suivantes :

1$ docker swarm init --advertise-addr 10.0.0.80
2Swarm initialized: current node (9cu80y8oolg4m9sn53kse8a1u) is now a manager.
3
4To add a worker to this swarm, run the following command:
5
6    docker swarm join --token SWMTKN-1-6b3o8lh8gfu8qsrxr85iwl7m7tvi82fqzhjr85n0ngmdikb5b0-881i2iesarv7foqyhkpegsevk 10.0.0.80:2377
7
8To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Sur chaque hôte du cluster, lancez la commande fournie précédemment par le résultat de l'initialisation du cluster :

1$ docker swarm join --token SWMTKN-1-6b3o8lh8gfu8qsrxr85iwl7m7tvi82fqzhjr85n0ngmdikb5b0-881i2iesarv7foqyhkpegsevk 10.0.0.80:2377
2This node joined a swarm as a worker.

Ces derniers seront ajoutés en tant que worker par défaut, à la différence de la machine qui initie la création du cluster qui est manager.

1$ docker node ls
2ID                            HOSTNAME            STATUS              AVAILABILITY        MANAGER STATUS      ENGINE VERSION
3visr29j2tb03vp6hxxmywa444 *   swarm1              Ready               Active              Leader              18.09.2
4cle7ugskcgre7jbsnn4dwp2my     swarm2              Ready               Active                                  18.09.2
5oe0coaikgm0h7eciv54daelzu     swarm3              Ready               Active                                  18.09.2
6uzbalyqmguhhaf7dh1yzkkyy2     swarm4              Ready               Active                                  18.09.2
79jhcdfyu4e99j0ddndmtmbou0     swarm5              Ready               Active                                  18.09.2

Ajouter des nœuds manager pour la tolérance aux pannes du cluster Swarm

Tout comme le cluster Elasticsearch, Swarm a besoin de plusieurs nœuds de type manager afin d’assurer : l'état du cluster, les services de planification, etc.

De plus, il est nécessaire d’avoir une tolérance aux pannes, comme le cluster Elasticsearch. Il est important de conserver un nombre impair de nœuds manager. Cela garantit que le quorum reste disponible pour traiter les demandes si le réseau est partitionné en deux ensembles.

https://docs.docker.com/engine/swarm/admin_guide/

Pour promouvoir des nœuds du cluster Swarm en manager, passez la commande suivante :

1

ocker node promote [node_id]

1
2
3Dans ce cas :
4
5

$ docker node promote cle7ugskcgre7jbsnn4dwp2my $ docker node promote oe0coaikgm0h7eciv54daelzu

1
2
3

$ docker node ls ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION visr29j2tb03vp6hxxmywa444 * swarm1 Ready Active Reachable 18.09.2 cle7ugskcgre7jbsnn4dwp2my swarm2 Ready Active Reachable 18.09.2 oe0coaikgm0h7eciv54daelzu swarm3 Ready Active Leader 18.09.2 uzbalyqmguhhaf7dh1yzkkyy2 swarm4 Ready Active 18.09.2 9jhcdfyu4e99j0ddndmtmbou0 swarm5 Ready Active 18.09.2

 1
 2
 3Maintenant que les nœuds sont déployés, il serait intéressant de pouvoir les identifier afin d'apposer des contraintes lors des déploiements.
 4
 5Par exemple, les containers ELK de type master pourraient être déployés sur des nœuds spécifiques, les containers de type data sur d'autres, etc.
 6
 7Dans ce cas, les contraintes de déploiements suivantes :
 8
 9  * Déployer les containers Elasticsearch de type master sur des nœuds spécifiques
10
11Pour ce faire, il faut ajouter un **label** sur les nœuds Swarm concernés depuis un nœud **manager** de la façon suivante :
12
13

$ docker node update --label-add elk=master visr29j2tb03vp6hxxmywa444 $ docker node update --label-add elk=master cle7ugskcgre7jbsnn4dwp2my $ docker node update --label-add elk=master oe0coaikgm0h7eciv54daelzu

1
2
3Pour lister les nœuds avec les labels :
4
5

$ docker node ls -q | xargs docker node inspect
-f '{{ .ID }} [{{ .Description.Hostname }}]: {{ .Spec.Labels }}' visr29j2tb03vp6hxxmywa444 [swarm1]: map[elk:master] cle7ugskcgre7jbsnn4dwp2my [swarm2]: map[elk:master] oe0coaikgm0h7eciv54daelzu [swarm3]: map[elk:master] uzbalyqmguhhaf7dh1yzkkyy2 [swarm4]: map[] 9jhcdfyu4e99j0ddndmtmbou0 [swarm5]: map[]

1
2
3Afin d'avoir une vue du cluster Swarm, les containers qui y sont déployés, il est intéressant d'utiliser le service [Visualizer][12].
4
5Depuis un nœud manager :
6
7

docker run -it -d
-p 8080:8080
-v /var/run/docker.sock:/var/run/docker.sock
dockersamples/visualizer:stable

 1
 2
 3Une fois déployé, il est possible d'accéder à Visualizer depuis l'IP du nœud sur le port 8080.
 4
 5<p style="text-align:right" class="has-small-font-size">
 6  <a href="https://docs.docker.com/engine/swarm/ingress/">https://docs.docker.com/engine/swarm/ingress/</a>
 7</p><figure class="wp-block-image">
 8
 9[<img loading="lazy" width="1024" height="542" src="https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3-1024x542.png" alt="" class="wp-image-770" srcset="https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3-1024x542.png 1024w, https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3-300x159.png 300w, https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3-768x407.png 768w, https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3.png 1723w" sizes="(max-width: 1024px) 100vw, 1024px" />][13]<figcaption>Vue du cluster Swarm avec Visualizer</figcaption></figure> 
10
11## Déploiement de la Stack ELK
12
13### Prérequis système
14
15Maintenant que Swarm est prêt, il faut remplir certains prérequis système avant de pouvoir déployer la Stack ELK.
16
17En effet, il est nécessaire de désactiver la mémoire SWAP, augmenter le nombre maximal de descripteurs de fichiers ouverts, augmenter le nombre de [mmap][14] ou encore augmenter le nombre de connexions qu'Elasticsearch peut demander.
18
19Pour ce faire, éditez le fichier **/etc/sysctl.conf** et ajoutez les lignes suivantes :
20
21

$ echo /etc/sysctl.conf vm.swappiness=1 net.core.somaxconn=65535 vm.max_map_count=262144 fs.file-max=518144

1
2
3De plus, le démon Docker est souvent démarré avec une limite trop basse pour la mémoire verrouillable. Les containers héritent de cette limite, ce qui pose un problème pour Elasticsearch lorsqu'il tente de verrouiller plus de mémoire que celle autorisée. 
4
5Pour regarder les limites du démon Docker :
6
7

$ grep locked /proc/$(ps --no-headers -o pid -C dockerd | tr -d ' ')/limits Max locked memory 65536 65536 bytes

1
2
3Alors que dans ce cas il serait préférable de voir **unlimited**. Pour ce faire :
4
5

$ echo -e "[Service]\nLimitMEMLOCK=infinity" | SYSTEMD_EDITOR=tee systemctl edit docker.service systemctl daemon-reload systemctl restart docker

1
2
3Vérification :
4
5

$ grep locked /proc/$(ps --no-headers -o pid -C dockerd | tr -d ' ')/limits Max locked memory unlimited unlimited bytes

 1
 2
 3Vous trouverez toutes les informations nécessaires en suivant ce [lien][15] 
 4
 5### Explication
 6
 7La Stack est composée de plusieurs services, définis dans un fichier **docker-compose.yml**. Il est courant d'utiliser ce format de fichier dans le cadre d'un déploiement de containers, mais de nouvelles fonctionnalités sont ajoutées pour l'orchestrateur Swarm.
 8
 9Voici le docker-compose final du déploiement :
10
11

version: "3.7"

services: ################################################################################ ################################## CONFIGURATION ############################### ################################################################################ visualizer: image: dockersamples/visualizer:stable networks: - net volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: labels: - "traefik.port=8080" - "traefik.backend=visualizer" - "traefik.frontend.rule=Host:visualizer-elk.net-security.fr" - "traefik.frontend.auth.basic=admin:$$2y$$05$$vHovNtz4FPZx49eK0JeGoenXLA4D/5h0i5QoS50L90GN3OlfFkjW." mode: replicated replicas: 1 placement: constraints: - node.role == manager resources: limits: memory: 256M reservations: memory: 128M

traefik: image: registry.gitlab.com/net-security/elk/traefik:1.7 ports: - "80:80" - "443:443" networks: - net volumes: - /var/run/docker.sock:/var/run/docker.sock deploy: mode: 'global' placement: constraints: - node.role == manager resources: limits: memory: 256M reservations: memory: 128M ################################################################################ ################################### ELK STACK ################################## ################################################################################ elastic-master: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "true" node.data: "false" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net deploy: endpoint_mode: dnsrr mode: 'replicated' replicas: 3 update_config: parallelism: 1 delay: 10s placement: constraints: [node.labels.elk == master] resources: limits: memory: 4G reservations: memory: 2G

elastic-data-1: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "true" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net volumes: - esdata1:/usr/share/elasticsearch/data deploy: placement: constraints: [node.hostname == swarm1] mode: 'replicated' replicas: 1 resources: limits: memory: 4G reservations: memory: 2G

elastic-data-2: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "true" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net volumes: - esdata2:/usr/share/elasticsearch/data deploy: placement: constraints: [node.hostname ==swarm2] mode: 'replicated' replicas: 1 resources: limits: memory: 4G reservations: memory: 2G

elastic-data-3: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "true" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net volumes: - esdata3:/usr/share/elasticsearch/data deploy: placement: constraints: [node.hostname ==swarm3] mode: 'replicated' replicas: 1 resources: limits: memory: 4G reservations: memory: 2G

elastic-data-4: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "true" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net volumes: - esdata4:/usr/share/elasticsearch/data deploy: placement: constraints: [node.hostname ==swarm4] endpoint_mode: dnsrr mode: 'replicated' replicas: 1 resources: limits: memory: 4G reservations: memory: 2G

elastic-data-5: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "true" node.ingest: "false" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net volumes: - esdata5:/usr/share/elasticsearch/data deploy: placement: constraints: [node.hostname ==swarm5] endpoint_mode: dnsrr mode: 'replicated' replicas: 1 resources: limits: memory: 4G reservations: memory: 2G

elastic-coordination: image: docker.elastic.co/elasticsearch/elasticsearch:6.7.0 environment: discovery.zen.minimum_master_nodes: 2 discovery.zen.ping.unicast.hosts: elastic-master discovery.zen.ping_timeout: 5s discovery.zen.commit_timeout: 5s node.master: "false" node.data: "false" node.ingest: "true" cluster.remote.connect: "false" cluster.name: docker-swarm-cluster network.host: 0.0.0.0 ES_JAVA_OPTS: -Xms1g -Xmx1g networks: - net deploy: endpoint_mode: dnsrr mode: 'global' update_config: parallelism: 2 delay: 10s resources: limits: memory: 4G reservations: memory: 2G

kibana: image: docker.elastic.co/kibana/kibana:6.7.0 environment: ELASTICSEARCH_HOSTS: http://elastic-coordination:9200 networks: - net deploy: labels: - "traefik.enable=true" - "traefik.port=5601" - "traefik.backend=kibana" - "traefik.frontend.rule=Host:kibana-elk.net-security.fr" - "traefik.frontend.auth.basic=admin:$$2y$$05$$vHovNtz4FPZx49eK0JeGoenXLA4D/5h0i5QoS50L90GN3OlfFkjW." mode: replicated replicas: 2 update_config: parallelism: 1 delay: 10s resources: limits: memory: 512M reservations: memory: 256M

logstash-syslog: image: registry.gitlab.com/net-security/elk/logstash-syslog:latest ports: - "5000:5000/udp" networks: - net deploy: mode: global update_config: parallelism: 2 delay: 10s resources: limits: memory: 4G reservations: memory: 2G

################################################################################ ################################# CONFIGURATION ################################ ################################################################################ networks: net: driver: overlay

volumes: esdata1: esdata2: esdata3: esdata4: esdata5:

 1
 2
 3Afin d'assurer une haute disponibilité des services, il est judicieux de redonder l'ensemble des services.
 4
 5Des contraintes d&#8217;emplacement sont spécifiés pour certains services, ainsi que des modes de déploiement différents, comme le mode **global** ou le mode **replicated**.
 6
 7En mode global, Docker Swarm va s'assurer que chaque nœud du cluster possède une instance du service, alors qu'en mode replicated, Swarm déploiera autant d'instances de ce service que précisé.
 8
 9#### Traefik
10
11Traefik est un reverse proxy HTTP et un équilibreur de charge moderne qui facilite le déploiement de micro services. Il sera utilisé en tête des services afin qu'il redirige les requêtes HTTP des frontends vers les backends associés.
12
13Le mode de déploiement est en mode replicated, au nombre de 3.
14
15Ici l'image Docker provient d'un registry privé Gitlab car c'est une image personnalisée. Un certificat SSL ainsi que le fichier de configuration sont ajoutés à cette dernière, qui sera construite et déployée automatiquement grâce à Gitlab CI/CD.
16
17Le fichier **traefik.toml** est le suivant :
18
19

################################################################

Docker Provider

################################################################ defaultEntryPoints = ["http", "https"] insecureSkipVerify = true [entryPoints] [entryPoints.http] address = ":80" [entryPoints.http.redirect] entryPoint = "https" [entryPoints.https] address = ":443" [entryPoints.https.tls] [[entryPoints.https.tls.certificates]] CertFile = "/ssl/fullchain1.pem" KeyFile = "/ssl/privkey1.pem"

Enable Docker Provider.

[docker] endpoint = "unix:///var/run/docker.sock" domain = "net-security.fr" watch = true exposedByDefault = true usebindportip = true swarmMode = true network = "net"

[api] entryPoint = "traefik" dashboard = true debug = true

1
2
3Afin de limiter les accès à certains services tels que Visualizer ou Kibana, il faut dans un premier temps utiliser l'Authentification Basic que propose Traefik. Il suffit de générer un couple _user:password_ de la façon suivante :
4
5

$ echo $(htpasswd -nbB admin "admin") | sed -e s/\$/\$\$/g admin:$$2y$$05$$vHovNtz4FPZx49eK0JeGoenXLA4D/5h0i5QoS50L90GN3OlfFkjW.

 1
 2
 3Pour plus d'informations concernant les différentes possibilités qu'offre Traefik, rendez-vous [ici][16].
 4
 5#### Kibana
 6
 7Le déploiement du service Kibana est en mode replicated, avec un nombre d'instances égal à 2. Le nœud sur lequel sera déployé Kibana a peu d'importance, l'idée est simplement de s'assurer que ce service soit toujours disponible. 
 8
 9Afin d'avoir la main sur les ressources du cluster et du nœud, les ressources telles que la RAM sont limitées mais aussi réservées.
10
11Enfin, l'ajout de la variable d'environnement JAVA **ELASTICSEARCH_HOSTS: http://elastic-coordination:9200** permet aux requêtes envoyées à Kibana de passer par un type de nœud Elasticsearch spécifique, les nœuds de type coordinating qui seront présentées par la suite. 
12
13<blockquote class="wp-block-quote">
14  <p>
15    Attention, il faut que le nom DNS du nœud coordinating soit identique au nom du service qui se trouve dans le docker-compose.yml
16  </p>
17</blockquote>
18
19En utilisant le nom du service et non l'IP d'un nœud du cluster au sein de Swarm, la haute disponibilité du service de routing et de load balancer d'Elasticsearch est assurée, ce grâce au mode de [routing mesh][17] de Swarm.
20
21#### Logstash
22
23Logstash est le service déployé afin de traiter le flux Syslog du routeur de l'entreprise, en deux parties :
24
25  * la partie input, qui spécifie le port d'écoute, le type d'input, et le protocole, ici UDP
26  * la partie output, qui redirige le flux vers les services Elasticsearch de type coordinating ainsi que l'index associé. Là l'index est de type _année-numerodesemaine_, comme vu précédemment.
27
28

input { udp { port => 5000 type => syslog } }

output { elasticsearch { hosts => ["elastic-coordination:9200"] index => "net-security-syslog-%{+YYYY.ww}" } }

 1
 2
 3#### Elasticsearch
 4
 5Le cluster Elasticsearch doit avoir plusieurs nœuds maîtres afin d’éviter les problèmes de cerveau divisé, ou **split-brain**.
 6
 7Le problème de split-brain se produit lorsque deux parties du cluster ne peuvent pas communiquer et pensent que l'autre partie est hors-service. Ce problème risquerait de faire perdre des données parce que le maître du cluster décide quand de nouveaux indices peuvent être créés, comment les shards sont déplacés, etc.
 8
 9S’il y a 2 maîtres, l'intégrité des données devient périlleuse parce qu'il y aura 2 nœuds qui pensent être master du cluster, mais chacun de leur côté
10
11Pour éviter la situation du split-brain, il faut utiliser le paramètre suivant : 
12
13
1covery.zen.minimum_master_nodes: 2
2

Ce paramètre indique à Elasticsearch de ne pas élire un maître s'il n'y a pas assez de nœuds maîtres disponibles. Ce n'est qu'à ce moment-là qu'il y aura des élections

Le quorum est calculé de la façon suivante : (nombre de nœuds éligibles au master / 2) + 1.

Dans ce cas, le cluster est composé de 3 nœuds maîtres dédiés et 5 nœuds de données, le quorum est de 2, puisqu'il est nécessaire de seulement compter les nœuds qui sont maîtres éligibles.

https://docs.docker.com/engine/swarm/admin_guide/

Elasticsearch est configuré pour utiliser la découverte multicast prête à l’emploi. La multidiffusion fonctionne en envoyant des pings UDP sur votre réseau local pour découvrir les nœuds. Les autres nœuds Elasticsearch recevront ces pings et répondront. Un cluster est formé peu de temps après.

Le paramètre à appliquer est :

1

covery.zen.ping.unicast.hosts: elastic-master

1
2
3<p style="text-align:left">
4  Pour terminer, chaque container doit avoir sa propre fonction au sein du cluster ELK.
5</p>
6
7Il existe plusieurs type de nœud comme les nœuds master, data, coordinating ou encore ingest. Pour spécifier le type de nœud au container, il faut passer les variables suivantes, en ne mettant la valeur _true_ qu'à un paramètre sur les 3.
8
9

node.master: "true" node.data: "false" node.ingest: "false"

 1
 2
 3Un nœud de type coordinating n'est aucun des trois types précédents, il faut donc tout passer à _false_.
 4
 5Pour plus d'informations sur les différents types de nœuds, c'est par [là][18].
 6
 7### Déploiement {#mce_37}
 8
 9Maintenant que tous les containers sont paramétrés, il ne reste plus qu'à déployer la Stack à l'aide de la commande suivante :
10
11

$ docker login registry.gitlab.com -u user -p password $ docker stack deploy --compose-file docker-compose.yml
elk-net-security --with-registry-auth

1
2
3Comme dit précédemment, la création d'images est automatisée grâce à Gitlab CI/CD et leur stockage est effectué au sein d'un registry privé. C'est la raison pour laquelle il faut utiliser_docker login_ ainsi que le paramètre _-with-registry-auth_.
4
5Pour vérifier que la Stack existe :
6
7

$ docker stack ls NAME SERVICES ORCHESTRATOR elk-net-security 11 Swarm

1
2
3Afin de vérifier que les différents services s’exécutent et que le nombre de réplicas souhaité est respecté :
4
5

$ docker service ls ID NAME MODE REPLICAS IMAGE PORTS jl8igvhv3dw6 elk-net-security_elastic-coordination global 5/5 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 td8ywoyldvzk elk-net-security_elastic-data-1 replicated 1/1 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 ytaqblikt2yj elk-net-security_elastic-data-2 replicated 1/1 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 ung0ymqvp69j elk-net-security_elastic-data-3 replicated 1/1 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 piumng277siw elk-net-security_elastic-data-4 replicated 1/1 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 ixmyision5og elk-net-security_elastic-data-5 replicated 1/1 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 tldg967htz62 elk-net-security_elastic-master replicated 3/3 docker.elastic.co/elasticsearch/elasticsearch:6.7.0 k7mo9wvzmnka elk-net-security_kibana replicated 2/2 docker.elastic.co/kibana/kibana:6.7.0 afcshnqdcipb elk-net-security_logstash-syslog global 5/5 registry.gitlab.com/net-security/elk/logstash-syslog:latest *:5000->5000/udp oekhg4esqfkj elk-net-security_traefik global 3/3 registry.gitlab.com/net-security/elk/traefik:latest *:80->80/tcp, *:443->443/tcp ov0kcwiplm73 elk-net-security_visualizer replicated 1/1 dockersamples/visualizer:stable

 1
 2
 3Comme vu plus haut, il est possible de voir l'ensemble des containers déployés au sein du cluster. Rendez-vous sur [https://visualizer-elk.net-security.fr][19].
 4
 5Saisissez _admin_:_admin_ et vous voilà authentifié, avec l'accès à la vue de Visualizer.  
 6<figure class="wp-block-image">
 7
 8[<img loading="lazy" width="1024" height="773" src="https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer-1024x773.png" alt="" class="wp-image-835" srcset="https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer-1024x773.png 1024w, https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer-300x226.png 300w, https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer-768x580.png 768w, https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer.png 1903w" sizes="(max-width: 1024px) 100vw, 1024px" />][20]<figcaption> Vue du cluster Swarm avec Visualizer </figcaption></figure> 
 9
10Parfait ! Maintenant, rendez-vous sur  
11[https://kibana-elk.net-security.fr][19], saisissez _admin_:_admin_. Voici les vues que vous devriez avoir :<figure class="wp-block-image">
12
13[<img loading="lazy" width="1024" height="498" src="https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init-1024x498.png" alt="" class="wp-image-830" srcset="https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init-1024x498.png 1024w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init-300x146.png 300w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init-768x373.png 768w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" />][21]<figcaption>Page de lancement de Kibana</figcaption></figure> <figure class="wp-block-image">[<img loading="lazy" width="1024" height="505" src="https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1-1024x505.png" alt="" class="wp-image-832" srcset="https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1-1024x505.png 1024w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1-300x148.png 300w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1-768x379.png 768w, https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1.png 1900w" sizes="(max-width: 1024px) 100vw, 1024px" />][22]<figcaption>Page d'accueil de Kibana</figcaption></figure> 
14
15Suite au déploiement de la Stack, il est nécessaire de mettre en place le nombre de réplicas pour les indexes avant de rediriger le flux Syslog vers Logstash.
16
17La modification du nombre de réplicas d’un index ne peut se faire qu’avant la création de ce dernier.
18
19Pour ce faire, il faut créer un template et pousser le fichier de configuration suivant sur n’importe quel nœud du cluster Elasticsearch (au sein d'un container) :
20
21

{ "order": 0, "index_patterns": "net-security-syslog-*", "settings": { "index": { "refresh_interval": "5s", "number_of_shards": "5", "number_of_replicas": "2" } }, "mappings": { "doc": { "properties": { "@timestamp": { "type": "date" }, "@version": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "host": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "message": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } }, "type": { "type": "text", "fields": { "keyword": { "type": "keyword", "ignore_above": 256 } } } } } } }

1
2
3Afin de le déployer, voici la commande à lancer :
4
5

curl -XPUT 'http://localhost:9200/_template/net-security-syslog'
-H 'Content-Type: application/json'
-d @net-security-syslog.json

 1
 2
 3Pour terminer, il ne reste plus qu'à rediriger le flux de l'ancien puits de logs vers le SIEM ELK, sur n'importe quel nœud du cluster vers le port 5000.
 4
 5## Haute disponibilité avec keepalived
 6
 7Le cluster dispose de services hautement disponibles, repartis sur 5 nœuds. 
 8
 9Si deux nœuds de type data sont corrompus, l'intégrité reste assurée. Si deux nœuds de type master sont défaillants, l'ensemble du cluster est encore fonctionnel. Il en est de même avec Logstash et Kibana.
10
11Mais qu'arriverait-il si jamais le nœud qui reçoit la sortie Syslog du routeur de l'entreprise est défaillant ? Il y a ici un SPOF (Single Point Of Failure) qui met à plat la Stack hautement disponible. 
12
13Keepalived est une solution (libre et gratuite) « tout en un » de haute disponibilité, de virtualisation de services applicatifs et de répartition de charge. Elle s'appuie entièrement sur des fonctionnalités du noyau Linux et des protocoles standardisés tout en consolidant ces technologies dans une même solution. Keepalived est un outil extrêmement léger, très facile à appréhender, à configurer et à déployer.
14
15Pour continuer sur la lancée de dockerisation, Keepalived sera déployé dans un container, sur chaque hôte du cluster, mais pas au sein de la Stack d'ELK.
16
17Le container est à déployer de la façon suivante :
18
19

docker run -d --name keepalived --restart=always
--cap-add=NET_ADMIN --net=host
-e KEEPALIVED_UNICAST_PEERS="#PYTHON2BASH:['10.0.0.80', '10.0.0.81', '10.0.0.82', '10.0.0.83', '10.0.0.84']"
-e KEEPALIVED_VIRTUAL_IPS=10.0.0.89
-e KEEPALIVED_PRIORITY=12
-e KEEPALIVED_INTERFACE=enp3s0
osixia/keepalived:2.0.15

 1
 2
 3<blockquote class="wp-block-quote">
 4  <p>
 5    Attention, bien penser à positionner une priorité différente pour chaque nœud du cluster.
 6  </p>
 7</blockquote>
 8
 9Pour vérifier que l'adresse IP virtuelle VRRP fonctionne sur le bon hôte, voici la commande à lancer sur les hôtes du cluster :
10
11

$ ip addr show enp3s0 2: enp3s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 2c:56:dc:d4:8a:36 brd ff:ff:ff:ff:ff:ff inet 10.0.0.84/25 brd 10.13.9.127 scope global enp3s0 valid_lft forever preferred_lft forever inet 10.0.0.89/32 scope global enp3s0 valid_lft forever preferred_lft forever inet6 fe80::2e56:dcff:fed4:8a36/64 scope link valid_lft forever preferred_lft forever

 1
 2
 3Une fois la vérification faite, il faut modifier l'IP cible du flux Syslog de routeur pour maintenant la faire pointer sur la VIP.
 4
 5Le cluster est désormais hautement disponible 🙂
 6
 7## Les points à améliorer
 8
 9La Stack maintenant déployée, il reste certains points à améliorer et à mettre en place, comme : 
10
11  * Déployer une Stack de monitoring (Prometheus, Grafana etc.)
12  * Gérer la CPU des containers comme la RAM
13  * Mettre en place le stockage à chaud et à froid
14  * Gérer la rotation des logs (1 an)
15  * Configurer les _Persistent Queues_ de Logstash
16
17Je vous parlerai de ces points dans un prochain article. 
18
19D'ici là, j’espère que cet article vous aura plu, si vous avez des questions ou des remarques sur ce que j’ai pu écrire n’hésitez pas à réagir avec moi par mail ou en commentaire !
20
21Merci pour votre lecture et à bientôt !
22
23APavone
24
25 [1]: https://net-security.fr/wp-content/uploads/ELK-Swarm/swrm.png
26 [2]: https://www.elastic.co/products/elasticsearch
27 [3]: https://www.elastic.co/products/logstash
28 [4]: https://www.elastic.co/products/kibana
29 [5]: https://searchmicroservices.techtarget.com/definition/RESTful-API
30 [6]: https://net-security.fr/wp-content/uploads/ELK-Swarm/image-2.png
31 [7]: https://www.enisa.europa.eu/topics/threat-risk-management/risk-management/current-risk/laws-regulation/national-security/directive-2006-24-ec
32 [8]: https://docs.docker.com/install/linux/docker-ce/ubuntu/
33 [9]: https://docs.docker.com/install/
34 [10]: https://github.com/docker/cli
35 [11]: https://github.com/containerd/containerd
36 [12]: https://hub.docker.com/r/dockersamples/visualizer
37 [13]: https://net-security.fr/wp-content/uploads/ELK-Swarm/image-3.png
38 [14]: http://man7.org/linux/man-pages/man2/mmap.2.html
39 [15]: https://www.elastic.co/guide/en/elasticsearch/reference/current/system-config.html
40 [16]: https://docs.traefik.io/
41 [17]: https://docs.docker.com/engine/swarm/ingress/
42 [18]: https://www.elastic.co/guide/en/elasticsearch/reference/current/modules-node.html
43 [19]: https://visualizer-elk.net-security.com
44 [20]: https://net-security.fr/wp-content/uploads/ELK-Swarm/Screenshot_2019-05-02-Visualizer.png
45 [21]: https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-init.png
46 [22]: https://net-security.fr/wp-content/uploads/ELK-Swarm/kibana-welcome-1.png