vendredi 2 janvier 2015, 18:18:32 (UTC+0100)

Raspbian & IPv6

Voilà maintenant plus d'un an que j'utilise un système Raspberry Pi comme routeur IPv6 entre le réseau local domestique et l'Internet via un tunnel SixXS. Je suis vraiment satisfait de cette solution qui permet d'agréger les services d'une «box» opérateur à moindre coût en plus de la fonction de routage. De mon point de vue, l'utilisation du système d'exploitation Raspbian s'imposait naturellement.

En configurant une nouvelle carte Raspberry Pi B+, j'ai redécouvert le fait que le protocole IPv6 n'est pas activé par défaut sur le système. C'est vraiment dommage dans un contexte où l'objet «Raspberry Pi B+» doit être nécessairement raccordé à l'Internet. En effet, il est particulièrement intéressant de pouvoir accéder via SSH à la carte sans avoir enregistré quoi que ce soit dans les services DHCP et DNS. L'autoconfiguration IPv6 prend tout son sens dans ce contexte.

Étape 1 : activer IPv6

Sur un système Raspbian fraichement installé, le support du protocole IPv6 n'est pas activé. Il apparaît que le protocole a été compilé sous forme de module dans le noyau de la distribution. La première manipulation à faire consiste donc à activer le chargement du module.

Les options de chargement des modules sont contrôlées via les fichiers placés dans le répertoire /etc/modprobe.d. Dans ce répertoire, on trouve un fichier ipv6.conf dont le contenu est le suivant :

# Don't load ipv6 by default
alias net-pf-10 off
#alias ipv6 off

Il suffit de commenter la ligne en rouge qui désactive la famille de protocole numéro 10 dans le noyau Linux et de redémarrer le système pour bénéficier du support IPv6. Le contenu du fichier devient :

# Don't load ipv6 by default
#alias net-pf-10 off
#alias ipv6 off

Une fois le redémarrage achevé, le module ipv6 est automatiquement chargé en mémoire.

$ lsmod | egrep -e '(Module|ipv6)'
Module                  Size  Used by
ipv6                  316254  22

Là, il faut bien reconnaître que c'est le module ipv6 qui occupe le plus de mémoire dans la liste complète des modules chargés en mémoire.

Il est maintenant possible d'accéder à la carte via SSH en utilisant les adresses de type lien local.

pi@raspberrypi ~ $ ip addr ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether b8:27:eb:82:b2:64 brd ff:ff:ff:ff:ff:ff
    inet6 fe80::ba27:ebff:fe82:b264/64 scope link
       valid_lft forever preferred_lft forever

Une adresse de type lien local appartient au préfixe fe80::/10 et est composée automatiquement à partir de l'adresse MAC au format EUI-64. Dans l'exemple ci-dessus, on reconnaît l'insertion des deux octets ff:fe au milieu de l'adresse MAC d'origine qui apparaît sur la ligne au-dessus.

L'accès SSH à l'aide de l'adresse de type lien local se fait comme suit :

phil@myhostname:~$ ssh pi@fe80::ba27:ebff:fe82:b264%eth0
pi@fe80::ba27:ebff:fe82:b264%eth0's password: 
Linux raspberrypi 3.12.35+ #730 PREEMPT Fri Dec 19 18:31:24 GMT 2014 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan  3 15:49:24 2015 from fe80::226:18ff:fe27:7b9%eth0

La seule particularité de cet accès tient au fait qu'il est nécessaire de désigner l'interface du domaine de diffusion à utiliser. Ici, la notation %eth0 impose l'utilisation du réseau Ethernet sur lequel l'interface eth0 est raccordée.

Étape 2 : autoconfiguration IPv6

Si l'étape précédente ne nécessite aucun service d'infrastructure, l'affectation d'une adresse IPv6 visible sur l'Internet suppose qu'un routeur IPv6 déjà configuré se charge de l'attribution des paramètres de l'interface réseau. Sur le système Raspbian, il faut ajouter deux lignes au fichier /etc/network/interfaces.

auto lo

iface lo inet loopback
iface eth0 inet dhcp
iface eth0 inet6 auto

allow-hotplug wlan0
iface wlan0 inet manual
wpa-roam /etc/wpa_supplicant/wpa_supplicant.conf
iface default inet dhcp
iface default inet6 auto

Après réinitialisation de l'interface active à l'aide des commandes sudo ifdown eth0 et sudo ifup eth0, l'autoconfiguration IPv6 peut s'effectuer. On visualise ci-dessous les adresses ainsi que la table de routage.

$ ip -6 addr ls
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 
    inet6 ::1/128 scope host 
       valid_lft forever preferred_lft forever
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qlen 1000
    inet6 2001:db8:fe00:814f:ba27:ebff:fe82:b264/64 scope global dynamic
       valid_lft 86368sec preferred_lft 14368sec
    inet6 fe80::ba27:ebff:fe82:b264/64 scope link
       valid_lft forever preferred_lft forever
$ ip -6 ro ls
2001:db8:fe00:814f::/64 dev eth0  proto kernel  metric 256  expires 86251sec
fe80::/64 dev eth0  proto kernel  metric 256 
default via fe80::ba27:ebff:feea:2972 dev eth0  proto ra  metric 1024  expires 1651sec

Pour compléter l'autoconfiguration, on ajoute le traitement des annonces RDNSS qui va servir à configurer le resolver DNS.

$ sudo aptitude install rdnssd
Les NOUVEAUX paquets suivants vont être installés : 
  rdnssd resolvconf{a}

On relève le résultat dans le fichier /etc/resolv.conf après réinitialisation de l'interface active.

# Dynamic resolv.conf(5) file for glibc resolver(3) generated by resolvconf(8)
#     DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN
nameserver 2001:db8:fe00:814f::1
search mydomain

Étape 3 : multicast DNS

Pour terminer, on ajoute le service multicast DNS au système. Manipuler des adresses IPv6 sous forme numérique peut s'avérer très fastidieux. Alors pourquoi ne pas bénéficier d'une résolution des noms d'hôtes sans passer par les enregistrements DNS «classiques» ?

On installe deux paquets supplémentaires ainsi que les dépendances associées.

$ sudo aptitude install avahi-daemon avahi-utils
Les NOUVEAUX paquets suivants vont être installés : 
  avahi-daemon avahi-utils bind9-host{a} libavahi-core7{a} libbind9-80{a} libdns88{a} libisc84{a} libisccc80{a} libisccfg82{a} liblwres80{a} libnss-mdns{a} 
0 paquets mis à jour, 11 nouvellement installés, 0 à enlever et 0 non mis à jour.
Il est nécessaire de télécharger 1 420 ko d'archives. Après dépaquetage, 3 360 ko seront utilisés.

Une fois les paquets installés, il reste une ultime édition de fichier. La recherche de noms mdns ne doit pas être restreinte au seul protocole IPv4. On modifie donc le fichier /etc/nsswicth.conf comme ci-dessous.

# /etc/nsswitch.conf
#
# Example configuration of GNU Name Service Switch functionality.
# If you have the `glibc-doc-reference' and `info' packages installed, try:
# `info libc "Name Service Switch"' for information about this file.

passwd:         compat
group:          compat
shadow:         compat

hosts:          files mdns_minimal [NOTFOUND=return] dns mdns
networks:       files

protocols:      db files
services:       db files
ethers:         db files
rpc:            db files

netgroup:       nis

Sur la ligne en vert ci-dessus, on a retiré les chiffres 4 pour les paramètres mdns.

Et voilà !

On accède maintenant à notre objet de l'Internet via son nom dans le Top Level Domain .local.

$ ssh pi@raspberrypi.local
The authenticity of host 'raspberrypi.local (2a01:240:fe00:814f:ba27:ebff:fe82:b264)' can't be established.
ECDSA key fingerprint is 4f:f9:17:ba:bf:57:16:a9:64:12:b7:e0:2b:51:7d:26.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'raspberrypi.local,2a01:240:fe00:814f:ba27:ebff:fe82:b264' (ECDSA) to the list of known hosts.
pi@raspberrypi.local's password: 
Linux raspberrypi 3.12.35+ #730 PREEMPT Fri Dec 19 18:31:24 GMT 2014 armv6l

The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the
individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent
permitted by applicable law.
Last login: Sat Jan  3 18:32:25 2015 from fe80::226:18ff:fe27:7b9%eth0

pour conclure, même si les configurations proposées dans ce billet ont une empreinte mémoire non nulle, je dirai qu'elles facilitent beaucoup l'utilisation de la connexion réseau sans qu'il soit nécessaire de déployer un jeu de services complet par ailleurs. Les «grands débutants» pourraient aborder plus facilement les outils disponibles sur ces nouveaux objets connectés à l'Internet.

samedi 29 novembre 2014, 16:41:43 (UTC+0100)

Comment effacer les fichiers de configuration inutiles ?

Sur les systèmes Debian GNU/Linux, les outils de gestion de paquets peuvent préserver les fichiers de configuration lors de la suppression d'un paquet. L'idée est que l'administrateur du système puisse retrouver une configuration personnalisée si le paquet supprimé était réinstallé par la suite.

Cependant, ces fichiers de configuration peuvent s'accumuler dans le temps et finir par générer des problèmes lors des migrations d'une version stable à l'autre. Ici, il faut insister sur le facteur temps. Retrouver des fichiers vieux de plus de dix ans n'est pas rare sur certains serveurs comme ceux utilisés pour l'hébergement des boîtes aux lettres de courrier électroniques. Les migrations matérielles d'une machine à l'autre se font depuis longtemps à l'aide de rsync et les systèmes de fichiers suivent. Il est donc utile de «faire le ménage» dans les fichiers de configuration de paquets trop anciens. Voici comment faire.

La version basée sur dpkg est connue de longue date :

# dpkg --purge $(dpkg -l | grep ^rc | cut -d ' ' -f 3 | tr '\n' ' ')

Il existe maintenant une version plus moderne basée sur aptitude :

# aptitude purge ~c

Contrairement à ce que j'avais indiqué dans une première version de ce billet, l'utilisation d'aptitude apporte une simplification considérable. Merci à JCD !.

Si vous avez une proposition de syntaxe encore plus optimisée pour le même traitement, je suis preneur !

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.