lundi 2 juin 2014, 21:49:12 (UTC+0200)

Génération automatisée de clé pour SSH sur un commutateur Cisco

Pour qui à l'habitude de l'arborescence des systèmes Unix, la gestion du système de fichiers de l'IOS de Cisco est pour le moins «singulière». Ce billet illustre les mésaventures rencontrées dans la gestion des configuration des commutateurs 2960 et 3560.

Au départ, mon objectif est de rendre systématique l'utilisation de SSH pour l'accès à l'interface de configuration (CLI) des commutateurs des salles de travaux pratiques. Dans ce but, j'ai créé des patrons de fichiers de configuration dans lesquels figurait la commande de génération de clé. Une fois le commutateur relancé, la première tentative de connexion échoue. Mauvaise surprise !

Voyons si la génération de clés RSA peut être déclenchée automatiquement.

Tout d'abord, les choses qui fâchent

Comme annoncé, tout débute par une grosse déconvenue :

$ ssh admin@sw09-213.infra.stri
ssh: connect to host sw09-213.infra.stri port 22: Connection refused

En redémarrant le commutateur avec le cordon console connecté et l'outil minicom lancé, on relève le message suivant :

% Rsa keys can't be generated by the startup configuration

Après moultes recherches, notamment sur Cisco Technical Support Forum, l'argument qui explique ce comportement s'appuie sur le fait que la génération de clé est une opération unique effectuée lors du déploiement d'un équipement. Le premier message d'erreur ci-dessus est dû au fait que la clé n'a pas été générée et/ou sauvegardée. Or, dans un contexte de travaux pratiques, les configurations sont constamment effacées et réécrites. Nous sommes donc amenés à la question du lieu de stockage de clé.

Au niveau CCNA on apprend que, sur un commutateur, tout est stocké en mémoire flash. Nous devons donc observer le contenu de cette mémoire flash parallèlement aux opérations sur les clés.

sw09-213#sh flash: 

Directory of flash:/

    2  -rwx       10227  May 30 2014 11:26:18 +02:00  recovery-confg
    3  -rwx         556   Mar 1 1993 01:00:39 +01:00  vlan.dat
    4  -rwx    11792247  May 27 2014 22:34:31 +02:00  c2960-lanbasek9-mz.150-2.SE6.bin
    5  -rwx        3096  May 30 2014 11:46:43 +02:00  multiple-fs
    6  -rwx           5  May 30 2014 11:46:43 +02:00  private-config.text
    7  -rwx       16165  May 30 2014 11:46:43 +02:00  config.text

32514048 bytes total (20688896 bytes free)

Les deux fichiers de configuration sont marqués en couleur dans la copie d'écran ci-dessus.

  • Le fichier config.text contient la configuration du commutateur utilisée lors d'un redémarrage.
  • Le fichier private-config.text ne contient pas grand chose pour l'instant ; vu sa taille.

Allons-y pour la génération de clé. J'avais publié un billet «façon antisèche» sur cette question il y a quelques temps déjà : Compte utilisateur local & accès SSH sur un équipement Cisco. On reprend la démarche après avoir vérifié qu'aucune clé n'est déjà présente dans la configuration courante.

sw09-213#sh crypto key mypubkey all
sw09-213#
sw09-213#conf t
Enter configuration commands, one per line.  End with CNTL/Z.
sw09-213(config)#crypto key generate rsa label SSH-KEY modulus 4096
The name for the keys will be: SSH-KEY

% The key modulus size is 4096 bits
% Generating 4096 bit RSA keys, keys will be non-exportable...
[OK] (elapsed time was 504 seconds)

000023: May 30 14:54:30.551 MET: %SSH-5-ENABLED: SSH 2.0 has been enabled

On remarque que le service SSH s'est activé immédiatement après la création de clé. On peut aussi visualiser le résultat de l'opération en rappelant la commande sh crypto key mypubkey all.

Si on réinitialise le commutateur maintenant, tout le travail de génération de clé sera perdu sachant qu'aucune sauvegarde n'a encore été effectuée. C'est là que la bizarrerie commence. La seule commande de sauvegarde dont nous disposons est la suivante :

sw09-213#copy run start
Building configuration...
[OK]
sw09-213#sh flash: | incl config
    7  -rwx        6820  May 30 2014 15:00:54 +02:00  private-config.text
    8  -rwx       16165  May 30 2014 15:00:54 +02:00  config.text

Alors que le fichier config.text n'a pas changé de taille, le fichier private-config.text est passé de 5 à 6820 octets. Notre clé est stockée dans ce dernier fichier. La commande copy running-config startup-config copie les clés dans la mémoire flash: en plus de la configuration courante du système.

L'effacement fonctionne comme la copie. La commande erase startup-config efface les deux fichiers private-config.text et config.text. Au redémarrage suivant, le commutateur a perdu sa configuration et son jeu de clés RSA. Malheureusement, il semble qu'il soit impossible de préserver une copie de sauvegarde du fichier private-config.text. Seul le fichier config.text peut être recopié en mémoire flash.

Une fois que les manipulations sont terminées, l'utilisation de la commande erase startup-config est recommandée dans tous les supports de travaux pratiques des curriculums Cisco. Il semble donc que nous soyons dans l'impasse.

Kron à la rescousse

Fort heureusement, nous pouvons contourner la difficulté grâce au service de planification des tâches baptisé kron. Bien entendu, ce service est loin d'offrir les possibilités d'un cron Unix. Sur les modèles de commutateurs 2960, il est seulement possible d'exécuter des commandes dites globales. Il n'est pas possible d'entrer directement dans le terminal de configuration.

Cependant, il est possible de charger un fichier contenant une suite de commandes de configuration via TFTP ou d'autres protocoles comme FTP ou HTTP. Les commandes contenues dans le fichier sont exécutées directement si la destination du transfert est le niveau d'exécution courant : system:/running-config.

Voici une copie de la partie intéressante du patron de configuration d'un commutateur.

!~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
!~~~~~~~~~      kron
!
file prompt quiet
!
kron occurrence crypto-key in 3 oneshot
 policy-list crypto-key
!
kron occurrence backup-startup in 30 oneshot
 policy-list backup-startup
!
kron policy-list crypto-key
 cli copy tftp://cooper/crypto-key-confg running-config
!
kron policy-list backup-startup
 cli delete /force flash:recovery-confg
 cli copy startup-config flash:recovery-confg
 cli copy running-config startup-config
!
end

On relève deux suites d'instructions.

  • La première phase baptisée crypto-key est exécutée un seule fois 3 minutes après l'initialisation du commutateur. C'est ce «script» qui sert à provoquer la génération de clé.

    $ cat /srv/tftp/crypto-key-confg 
    ! Génération de clés RSA pour SSH
    crypto key generate rsa label SSH-KEY modulus 4096
    !
    end
    
  • La seconde phase baptisée backup-startup est aussi exécutée une seule fois au bout de 30 minutes après l'initialisation. Son but est de sauvegarder le jeu de clés RSA.

Attention ! Le choix des temps avant exécution des commandes n'est pas anodin. Il faut être sûr que le lien montant est actif et que le serveur TFTP est joignable avant de lancer un téléchargement. On tient compte notamment, du temps de convergence du protocole Spanning Tree.

Au final, on obtient les informations suivantes dans les journaux système. Le jeu de clés a bien été généré et il est enfin possible d'accéder au commutateur via SSH.

000020: Jun  2 18:58:36.092 MET: %SSH-5-ENABLED: SSH 2.0 has been enabled
000021: Jun  2 18:58:43.004 MET: %SYS-5-CONFIG_I: Configured from tftp://cooper/crypto-key-confg by admin on console

Cette méthode fonctionne aussi sur les commutateurs Cisco de la gamme supérieure comme les 3560 ou 3750.

Pour conclure, j'espère que ce billet pourra servir à quelques administrateurs d'équipements réseau et leur fera économiser un peu de temps pour faire des choses plus intéressantes. Avec ce genre de «Hack à 2€cts» nous sommes encore bien loin du Software Defined Network.

samedi 3 mai 2014, 17:25:15 (UTC+0200)

Autoconfiguration IPv6 stateless et multicast DNS

En voyant les difficultés rencontrées par les étudiants dans la mise en œuvre du protocole IPv6, je me suis décidé à rédiger un nouvel article sur l'autoconfiguration IPv6. L'objectif de ce document est de poser les bases de l'argumentation en faveur des communications sans suivi d'état (stateless) et de rassembler les éléments nécessaires à la mise en route d'une maquette de projet. Les communications IPv6 ne sont pas la finalité, elles constituent juste la première étape avant de passer aux services de la couche application. Il est terriblement frustrant de constater que cette première étape constitue trop souvent un mur infranchissable. Mon espoir est que le fait d'avoir compilé en un seul article des ressources disséminées sur le Net permettra d'arriver plus vite à un fonctionnement correct et fera avancer la compréhension de l'utilisation d'IPv6. Il est de coutume de dire que l'adoption du protocole IPv6 est freinée par le fait qu'elle nécessite la coopération de tous les acteurs ; des développeurs jusqu'aux opérateurs réseau. Le développement de l'Internet des objets pourrait bien être, enfin, le nouvel usage déterminant dans cette adoption.

L'interconnexion réseau type utilisée pour illustrer le propos rassemble les briques de base : un tunnel d'accès au réseau public, des routeurs et deux VLANs. Par commodité, j'ai utilisé des instances de machines virtuelles et Open vSwitch, mais ce n'est pas une obligation.

Maquette autoconfiguration IPv6

IPv6 n'est pas le seul écueil dans le déroulement des enseignements. Dire que le service DNS est une pièce critique et essentielle est un lieu commun. Mais, quand on arrive à conclure qu'une application ne marche pas et à rester bloqué devant la fenêtre vide de WireShark parce que le fichier /etc/resolv.conf est vide, on est «en droit de s'inquiéter». Que faire pour dépasser ce genre de blocage ?

Sachant que la mise en œuvre d'une infrastructure DNS au début de chaque séance de travaux pratiques est irréaliste, le service multicast DNS (mDNS), qui est sans infrastructure, est une solution très intéressante. Lorsque j'ai rédigé le document Initiation au développement C sur les sockets IPv4 & IPv6, j'ai inclus une infrastructure DNS complète. C'est certainement beaucoup trop lourd à utiliser en séance. La situation s'est reproduite dans le billet NIS, NFSv4, autofs5 & dual stack IPv4 + IPv6 ; même si dans ce dernier cas, le cocktail de tous les services à utiliser était long à installer en tout état de cause.

Dans la section Multicast DNS, j'essaie de montrer que même avec une résolution DNS classique «mal en point», il est toujours possible d'utiliser des noms d'hôtes et peut être d'éviter de conclure sur le mauvais fonctionnement d'une application qui n'a en réalité aucun problème ! Ceci dit, pour être tout à fait honnête, je n'ai fait que déplacer le problème du fichier /etc/resolv.conf au fichier /etc/nsswitch.conf ...

En bonus, il est possible de «propager» les enregistrements mDNS d'un domaine de diffusion à l'autre grâce à la fonction reflector du démon avahi.

Pour conclure ce billet, encore trop long, l'autoconfiguration IPv6 associée au service mDNS constitue une solution d'interconnexion réseau éphémère qui mérite que l'on s'y attarde. Son usage dépasse largement le cadre des enseignements.

samedi 15 février 2014, 09:22:44 (UTC+0100)

Dessine moi une interconnexion réseau

Le développement d'exercices sous forme de défi devient une condition importante pour attirer de nouveaux étudiants vers un domaine particulier. Les enseignements sur les systèmes et les réseaux n'échappent pas à cette condition. J'ai donc modifié la progression des travaux pratiques pour les étudiants de 2nde année d'IUT Génie Électrique, et l'introduction d'une séance Dessine moi une interconnexion réseau a été un succès relativement au vécu des années précédentes.

En premier lieu, j'ai révisé le support de travaux pratiques Configuration d'une interface réseau Ethernet en éliminant l'utilisation des outils net-tools au profit de la commande ip du paquet iproute2.

Avec l'utilisation conjointe des protocoles IPv4 & IPv6, une même interface peut avoir de nombreuses adresses. Le recours systématique à la commande ip s'impose donc. J'ai rencontré plusieurs cas où les étudiants ont ajouté manuellement une adresse IPv4 à une interface préalablement configurée via DHCP. Dans un tel cas de figure, la commande ifconfig ne fait apparaître qu'une seule adresse au lieu de deux et induit les étudiants en erreur.

Ce support est de «facture classique» et le jeu de questions proposé correspond à un scénario de lecture simple. Même si ces questions peuvent être traitées avec l'émulateur de terminal Android®, il n'y a pas d'enjeu particulier. Le support ne sert alors que de base documentaire sur les différentes options de la commande ip.

couche 3 de la modélisation réseau

En second lieu, j'ai créé le nouveau support Dessine moi une interconnexion réseau qui est bâti sur le «mode défi». Il s'agit de partir à la découverte d'une interconnexion de réseaux locaux inconnus. Les étudiants doivent identifier les réseaux communs entre les différents routeurs et aboutir à une représentation graphique des liens entre ces routeurs. Le point de départ du défi est une connexion SSH sur un routeur de cette interconnexion.

Pour faciliter le travail des étudiants, qui sont de véritables débutants, j'ai choisi d'utiliser des routes statiques de façon à ce qu'il soit possible de contacter n'importe quelle adresse d'interface depuis n'importe quel routeur. L'utilisation d'un préfixe agrégeant toutes les routes de l'interconnexion permet de diminuer le nombre des entrées dans la table de routage.

Cet exercice est une illustration de l'utilisation du guide Virtualisation système et enseignement : les routeurs sont des machines virtuelles Debian GNU/Linux et l'interconnexion est réalisée avec Open vSwitch. Le script de lancement de l'ensemble des instances est disponible sur GitHub. J'ai volontairement choisi de faire apparaître une interface distincte par lien réseau pour que l'identification des routes soit plus facile. Il aurait été plus simple du point de vue virtualisation de n'utiliser qu'une interface physique par routeur et autant de sous-interfaces que de VLAN utilisé.

Enfin, bien que le défi s'adresse avant tout à des débutants, il renferme quelques questions d'un niveau un tantinet plus élevé. Deux exemples :

  • D'après la table de routage ci-dessous, quelle est l'interface utilisée pour émettre un paquet à destination de l'adresse 172.19.129.21 ?

    Justifier le choix entre eth1 et eth3.

    $ ip route ls
    default via 192.0.2.1 dev eth0 
    172.19.128.0/22 via 172.19.131.169 dev eth3 
    172.19.129.0/26 dev eth1  proto kernel  scope link  src 172.19.129.12 
    172.19.131.0/25 dev eth2  proto kernel  scope link  src 172.19.131.13 
    172.19.131.128/25 dev eth3  proto kernel  scope link  src 172.19.131.142 
    192.0.2.0/26 dev eth0  proto kernel  scope link  src 192.0.2.11
    
  • Pourquoi est-il nécessaire d'appliquer la valeur 2 au paramètre de réglage de la fonction reverse path forwarding de certaines interfaces ?

    Extrait du fichier /etc/network/interfaces d'un routeur.

    auto eth2
    iface eth2 inet static
          address 172.19.131.13/25
          up echo 2 >/proc/sys/net/ipv4/conf/eth2/rp_filter
    

Alors !? Si vous êtes intéressé par ce défi, vous pouvez me contacter par courrier électronique à l'adresse donnée sur la page d'accueil du site inetdoc.