Labo 1 : Les réseaux comme une fonction logicielle

Le but de ce laboratoire est de mettre en pratique des outils standards pour la configuration du réseau d’équipements réseaux purement logiciels, qui ont la particularité :

  • d’êtres instanciables à partir de matériel et logiciel complètement génériques, le plus souvent basés sur Linux.

  • d’êtres accessibles à travers une API.

  • d’avoir une interface de management connectée à Internet.

Pour ce travail pratique, nous nous baserons sur des images debian standard, disponibles dans GNS3, dont les symboles sont indiqués en Fig. 2.

Equipement réseaux virtuels Debian 11

Fig. 2 Equipement réseaux virtuels Debian 11

S1 est un switch 4 ports avec STP activé basé sur le bridge linux natif, R1 est un routeur 4 ports basé sur la pile TCP/IP Linux. H1 est un hôte avec une seul interface réseau. C1 est une image générique basée sur https://cloud.debian.org/images/cloud/, qui ne dispose d’aucun port réseau car elle reste à configurer selon nos besoins spécifiques.

Toutes ces images disposent d’un port de management, nommé mgmt0 sur S1, R1 et H1, mais dont le nom reste à fixer sur l’image générique. Ce port est connecté à Internet et permet d’accéder à la machine à distance via le VPN Tailscale installé sur votre PC et/ou d’installer des packages sur la machine avec les outils usuels de gestion de packages Debian (apt).

Le laboratoire est divisé en 3 parties :

  • Génération automatique du fichier de configuration du client SSH pour un accès distant aux équipements.

  • Construction d’une topologie switchées simple, adressage IPv4 d’hôte et re-configuration des domaines de broadcast avec iproute2 5

  • Provisioning automatique d’une machine générique pour la transformer en switch 4 ports.

1 - Génération automatique du fichier client SSH

A - Objectifs

Vos machines virtuelles sont accessibles par SSH à l’IP et au port+1 indiqué dans le Topology summary de GNS3. Cet accès est beaucoup plus commode que l’accès sur la console série mais nécessite de configurer le fichier du client SSH à chaque changement 6. Si les ports changent ou si le nombre de machines à accéder est grand, il devient fastidieux de reconfigurer le fichier ~/.ssh/config pour accéder à ces machines. Pour pallier à cela, vous écrirez un script python3, client de l’API REST/Json de gns3, basé sur requests 4, jinja2 3 et json 7 dont le début est le suivant

#!/usr/bin/env python3

import requests
import jinja2
import json
import sys

PROJECTS_URL='https://gns3.hepiapp.ch/v2/projects'
PROJECTS_NODES_URL=PROJECTS_URL+'/'+project_uuid+'/nodes'

def usage():
    print(f"{sys.argv[0]} PROJECT_NAME")

La sortie de l’API json peut-être explorée directement avec un navigateur mais nécessite que vous soyez connecté à Tailscale (Par ex, essayez https://gns3.hepiapp.ch/v2/projects). Ce script aura la responsabilité, pour un nom de projet donné en argument de :

  • Récupérer l’adresse IP et le numéro de port de la console de chaque noeud du projet avec requests.

  • Générer un fichier au format sshconfig avec une entrée Host pour chaque noeud de la topologie et les bonnes information d’utilisateur d’adresse et de port.

  • Gérer les erreurs eventuelles d’accès à l’API (par exemple un nom de projet non trouvé)

Afin d’être écrasé puis ré-initialisé avec de nouvelles valeurs facilement, ce fichier sera à inclure depuis le répertoire config.d de votre répertoire utilisateur. Pour cela rajouter à la main la ligne suivante au fichier .ssh/config de votre répertoire utilisateur

Include config.d/*

Si le fichier .ssh/config n’existe pas, il faudra le créer.

Pour rafraîchir vos connaissances en Python3, vous pouvez consultez l’excellente ressource en ligne https://perso.limsi.fr/pointal/python:memento

B - Exemple

Un exemple de sortie de votre script pourrait être

Host S1
    User root
    Hostname 100.64.0.2
    Port 2002
    StrictHostKeychecking no
    UserKnownHostsFile /dev/null
    IdentityFile ~/.ssh/gns3.rsa

Host S2
    User root
    Hostname 100.64.0.2
    Port 2006
    StrictHostKeychecking no
    UserKnownHostsFile /dev/null
    IdentityFile ~/.ssh/gns3.rsa

Host S3
    User root
    Hostname 100.64.0.2
    Port 2010
    StrictHostKeychecking no
    UserKnownHostsFile /dev/null
    IdentityFile ~/.ssh/gns3.rsa

C - Test

Téléchargez la clef gns3 et installez là sur votre machine, elle vous permettra d’accéder par ssh aux instances des templates GNS3 debian11-switch, debian11-router et debian11-host avec l’utilisateur root sans mot de passe.

Testez votre script python sur un projet avec quelques instances de ces templates et vérifiez que vous pouvez y accéder par SSH sans donner d’autre paramètre que le nom de l’instance indiquée dans GNS3.

2 - Re-configuration logicielle des domaines de broadcast

A - Setup initial

Télécharger le laboratoire switched_line et importez le dans GNS3. Vous devriez obtenir la topologie indiquée en figure Fig. 3.

Topologie switchée en ligne

Fig. 3 Topologie switchée en ligne

Tester sur cette topologie le script écrit dans la partie précédente. Après exécution du script, vous devriez pouvoir vous connecter sur chacun des noeuds par SSH depuis votre poste client et y exécuter des commandes très rapidement, comme par exemple

ssh S1 bridge link show

B - Nommages des hôtes

Ecrire un script bash qui modifie le nom d’hôte de toutes les machines par leur nom de machine indiqué dans votre configuration ~/.ssh/config en vous basant sur la commande hostname.

Il n’est pas nécessaire que le nom de la machine soit persistant après un redémarrage. Après exécution de votre script, vos machines devront avoir un prompt tel qu’indiqué dans l’exemple suivant pour S1

root@S1:~#

C - Configuration IPv4 des hôtes

Comme S1 et S2 sont dans le même domaine de broadcast, nous pouvons adresser les hôtes du réseau dans le même segment IP.

Ecrire un script bash, basé sur iproute2 9, qui configure l’interface connectée au switch de H1, H2, H3 et H4 avec chacun une IP unique dans le réseau 192.168.0.0/24 et change l’adresse MAC de l’interface eth0 de l’hôte par son index de nom d’hôte (00:00:00:00:00:01 pour H1, 00:00:00:00:00:2 pour H2, etc)

  • La configuration IP n’aura pas besoin d’être persistente après un redémarrage.

  • Votre script bash devra monter les interfaces.

  • Votre script bash devra vérifier que toutes les autres IP sont joignable depuis un hôte quelconque avec la commande ping.

L’une des meilleures référence d’utilisation de la commande ip, écrite par l’auteur de l’outil, est disponible dans ce document. Une autre excellente documentation en ligne sur iproute est disponible sur https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md

D - Fonctionnement du switch

Après avoir pingé un hôte depuis un autre hôte, afficher les entrées non permanentes de la table des switchs S1 et S2 avec la commande bridge 8

  1. Est-ce que les informations qui se trouvent dans ces tâbles correspondent à la théorie de fonctionnement d’un switch ? Expliquez avec un exemple et des captures d’écran. Vous pouvez vous aider de la commande bridge -s fdb show

  2. À quoi servent les valeurs de timer used et updated de chaque entrée dans la table du switch ?

  3. À quoi servent les entrées marquées comme permanentes dans la table du switch ?

  4. En supposant qu’une adresse MAC a émis une trame sur le réseau, puis qu’il n’y a plus de trafic venant de cette adresse MAC sur le réseau, combien de temps l’association adresse MAC <-> numéro de port reste-t-elle valide par défaut (Cette valeur est appelée Ageing Timer) ?

  5. Modifier valeur du Ageing Timer pour provoquer le flood du réseau pour un émetteur qui enverrait un paquet toutes les 10 secondes. Démontrer par une capture wireshark sur le bon lien GNS3 et en expliquant les opérations effectuées et que le flooding a bien lieu parce que Ageing Timer a expiré sur l’un des switches.

  6. Poser la valeur du Ageing Timer à zero et démontrer que vos switches fonctionnent comme un HUB à l’aide d’une capture de paquets et d’écran.

E - Subdivision du domaine de broadcast

Ecrire un script bash, basé sur iproute2, qui reconfigure S1 et S2 de la manière suivante, sans modifier la topologie GNS3 :

  • Plutôt que d’offrir la fonction d’un switch 4 port, S1 et S2 seront chacun transformés en 2 switches à 2 ports, c’est à dire 4 switches en tout. Ainsi, pour S1 qui dispose au départ d’un switch nommé br0 avec 4 interfaces, aura deux switches séparés br0 et br1 avec chacun deux interfaces. Rajouter l’interface manquante à la main dans GNS3 (Il y a une interface non utilisée sur S1 et sur S2)

  • Notre topologie contiendra 2 domaines de broadcast (H1,H2) et (H3,H4) comme indiqué sur la figure Fig. 4

Séparation des domaine de broadcast

Fig. 4 Séparation des domaine de broadcast

  • Vérifier que les domaines de broadcast ont bien été séparés en confirmant que H1 ne peut pas pinger H3 et le démontrer par une capture d’écran.

  • Nos deux domaines de broadcast offrent-ils la même fonctionnalité qu’un VLAN ? quelle est la différence de fonctionnement entre un switch virtuel et un VLAN ? Expliquez.

F - Routage IPv4

A partir de la topologie de la partie précédente, connecter les domaines de broadcast par un routeur virtuel, toujours sans modifier la topologie GNS3 et en se basant uniquement sur l’outil iproute2. Pour cela nous utiliserons la stratégie suivante :

  1. Ecrire la suite de commande dans un script bash.

  2. Assigner une IP aux switches br0 et br1 de S1 et S2 respectivement, est-il nécessaire de configurer des routes sur S1 et S2 ? Pourquoi ?

  3. Cette IP sera le next hop depuis H1,H2 pour rejoindre le domaine de broadcast H2,H3.

  4. Activer le routage IPv4 sur les switch en posant la valeur de /proc/sys/net/ipv4/ip_forward à 1.

  5. Installer la/les routes nécessaires dans H1/H2 pour rejoindre H3/H4.

3 - Provisioning de machine virtuelle

Le provisioning, c’est à dire la configuration initiale d’un équipement virtuel est souvent répétitive et manuelle : création de comptes utilisateurs, configuration du nom de la machine, installation de packages particuliers. Dans le contexte d’un data center, où on suppose qu’on a accès à Internet par défaut depuis l’interface de management d’un équipement, il devient possible d’effectuer ce provisionning de manière systèmatique au démarrage d’une machine virtuelle générique.

Nous utiliserons cloud-init 1 pour cet exercice de provisionning, associé à l’image debian11-cloud disponible dans les hôtes virtuelles de GNS3.

Les pré-requis de cloud-init sont les suivants :

  • La machine virtuelle tourne sous qemu avec possibilité de modification des options de démarrage de la machine.

  • La machine virtuelle dispose d’un accès Internet au démarrage.

  • le contenu des fichiers cloud-init doit pouvoir être accessible par une URL dont on contrôle le contenu.

Le contenu de cette URL, qui est en réalité un simple répertoire avec 3 fichiers (meta-data, user-data et vendor-data) sera accessible après génération du contenu sur une gitlab pages par l’intermédiaire de la CI de gitlab.

Pour le générer ce contenu, vous devez disposer d’un compte sur https://gitlab.com et créer un repository git dédié si ce n’est pas le cas, veuillez vous en créer un. A noter que vous ne pourrez pas utiliser gitedu pour cet exercice, qui ne dispose pas de la fonctionnalité gitlab pages.

A. Importation du laboratoire

Télécharger et importez le labo cloud-init-switches dans GNS3. Vous devriez obtenir la topologie indiquée en figure Topologie Initiale Cloud Init, qui ne contient pas encore de liens, car les équipements debian11-cloud sont complètement génériques et destinés à être provisionnés avant utilisation

Topologie initiale Cloud Init

Fig. 5 Topologie Initiale Cloud Init

B. Gitlab pages

Documentez-vous sur l’utilisation de gitlab pages (https://docs.gitlab.com/ee/user/project/pages/) et créez un projet gitlab qui généra une page quelconque après chaque commit sur votre repository.

C. Provisioning

  • Ecrire les fichiers user-data, meta-data et vendor-data qui après un premier redémarrage suite au provisioning de cloud-init configureront les machines C1 et C2 de la manière suivante :

    • Accessibilité par SSH publique/privée avec une clef et utilisateur par défaut qui est debian.

    • Offrir une session avec login automatique sur le terminal ttyS0 pour l’utilisateur root, vous pouvez vous aider du tutoriel suivant pour l’implémenter dans cloud-init : https://blog.oddbit.com/post/2020-02-24-a-passwordless-serial-console/

    • Avoir les noms de ports réseaux dénommés « eth0, eth1,… », pour cela il vous faudra modifier /etc/default/grub avec la ligne suivante

      GRUB_CMDLINE_LINUX="console=tty0 console=ttyS0,115200 earlyprintk=ttyS0,115200 consoleblank=0 net.ifnames=0"
      
    • Être configurée comme un switch 4 ports sur la base de ces noms de port réseaux à l’aide de l’extension ifup/down du package debian bridge-utils 2. Le switch devra avoir STP activé par défaut et être actif dès le démarrage. Vous pourrez vous aider de la configuration des noeuds de type debian11-switch pour réaliser cette config.

    • Les 4 ports de notre switch virtual seront ajoutés manuellemenent à la VM avec l’interface graphique de GNS3 après arrêt de celle-ci.

  • Vous partirez du template pour le fichier “user-data”, qui permet de désactiver cloud-init au redémarrage, prendre la main sur la configuration du réseau et nommer correctement l’interface de management de l’équipement en mgmt0

    #cloud-config
    apt:
        sources_list: |
            deb $MIRROR $RELEASE main
            deb-src $MIRROR $RELEASE main
            deb $SECURITY $RELEASE-security main
            deb-src $SECURITY $RELEASE-security main
            deb $MIRROR $RELEASE-updates main
            deb-src $MIRROR $RELEASE-updates main
            deb $MIRROR $RELEASE-backports main
            deb-src $MIRROR $RELEASE-backports main
        sources:
        nonfree.list:
            source: deb $MIRROR $RELEASE non-free
    
    runcmd:
    # remove cloud-init interface nameing
    - rm /etc/udev/rules.d/*
    - rm /etc/network/interfaces.d/*cloud*
    - touch /etc/cloud/cloud-init.disabled
    
    write_files:
    - content: |
        [Match]
        MACAddress=52:54:00:12:34:56
        [Link]
        Name=mgmt0
    path: /etc/systemd/network/10-persistent-net.link
    - content: |
        # Include files from /etc/network/interfaces.d:
        source /etc/network/interfaces.d/*
    path: /etc/network/interfaces
    - content: |
        auto mgmt0
        iface mgmt0 inet dhcp
    path: /etc/network/interfaces.d/mgmt0
    
  • l’URL des fichiers cloud-init que vous aurez général avec gitlab pages est à indiquer par GNS3 en cliquant sur l’équipement virtuel, Configure -> Advanced -> Additional settings

    -smbios type=1,serial=ds=nocloud-net;s=http://changeme/
    

D. Test

Vérifier que le provisionning est fonctionnel de la manière suivante :

  • C1 et C2 doivent se comporter comme un switch et implémenter un seul domaine de broadcast entre H1,H2, H3 et H4. Pour celà, vérifier que H1 arrive bien à pinger tout le monde après redémarrage de C1 et C2 et configuration des IPv4 de H1, H2, H3 et H4.

1

https://cloudinit.readthedocs.io/en/latest/

2

https://manpages.debian.org/testing/bridge-utils/bridge-utils-interfaces.5.en.html

3

https://jinja.palletsprojects.com/en/3.1.x/templates/#

4

https://requests.readthedocs.io/en/latest/

5

https://paulgorman.org/technical/linux-iproute2-cheatsheet.html

6

https://linuxhandbook.com/ssh-config-file/

7

https://docs.python.org/3/library/json.html

8

https://manpages.debian.org/unstable/iproute2/bridge.8.en.html

9

https://github.com/dmbaturin/iproute2-cheatsheet/blob/master/site/index.md