Qui utilise votre réseau ?

Gazette Linux n°141 — Août 2007

Deny

Adaptation française

Joëlle Cornavin

Relecture de la version française

Article paru dans le n°141 de la Gazette Linux d'août 2007.

Article publié sous Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.


Table des matières

1. La menace intérieure
2. Ce n'est pas un réseau téléphonique
3. Un shell sécurisé
4. OpenVPN
5. Le cachet de l'Autorité
6. Donnez-nous un signe
6.1. Organiser tout cela ensemble
6.2. Problèmes
7. Rappel
8. Conclusion et remerciements

1. La menace intérieure

Sécuriser un réseau local (LAN, Local Area Network) signifie généralement créer des règles de pare-feu, des règles pour accéder à un hôte et une configuration appropriée des serveurs de courrier, DNS (Domain Name System, système de noms de domaine) et web. Toutes ces méthodes sont principalement fondées sur l'hypothèse que la menace pesant sur votre réseau provient du grand méchant Internet. Dans cet article, je partirai d'un point de vue inverse — selon lequel ce sont les utilisateurs du réseau local qui sont (probablement) les assaillants.

Une telle hypothèse peut être justifiée dans les contextes suivants :

  • Il s'agit d'un grand réseau, comme un réseau à l'échelle d'un campus. L'administrateur du réseau n'a pas la connaissance ou le contrôle sur l'ensemble des différents ordinateurs reliés au réseau local.

  • Un réseau sans fil classique où chacun dans votre entourage peut utiliser votre connexion Internet

  • Vous êtes au siège d'une entreprise douteuse (peut-être ceci s'applique-t-il à certains départements universitaires également), où vous ne faites pas vraiment confiance à vos collègues — et tous portent des « chapeaux noirs » (black hat, expression désignant les pirates informatiques).

Bien que j'aie employé le mot « utilisateurs » ci-dessus, les véritables acteurs dans un réseau informatique sont les ordinateurs. En émettant l'hypothèse (souvent fausse !) que chaque ordinateur fait exactement ce que son utilisateur veut qu'il fasse, je limiterai la question à celle-ci :

Comment l'ordinateur Abdul, qui souhaite dialoguer avec l'ordinateur Chin, peut-il être raisonnablement sûr que l'ordinateur Betaal n'est pas à même d'intercepter la conversation et/ou de se faire passer pour Chin ?

2. Ce n'est pas un réseau téléphonique

Afin de comprendre pourquoi une solution quelque peu sophistiquée est requise, il faut réaliser qu'un réseau local n'est pas comme un réseau téléphonique et qu'une adresse IP n'est pas une marque d'identification au même titre que l'est un numéro de téléphone.

Le lecteur plus expérimenté connaîtra les adresses « physiques » — également appelées adresses Ethernet ou MAC (Medium Access Card, contrôle d'accès à la carte) qui sont intégrées au matériel, contrairement aux adresses IP. Cependant, la description du réseau évoquée dans le paragraphe ci-dessous est également appropriée si vous remplacez « adresse IP » par « adresse MAC ».

Un réseau local typique est un réseau à base de paquets. Chaque ordinateur est toujours « connecté » à tous les autres. Les conversations reposent sur des paquets qui sont envoyés « via le câble » et sont « entendus » par tous les ordinateurs présents sur le réseau. Sur chaque paquet est enregistrée l'adresse IP du destinataire, de sorte que la partie concernée peut « l'écouter » (en d'autres termes, le copier dans sa mémoire). Le paquet contient également l'adresse IP de l'expéditeur, de sorte que le destinataire sait où envoyer des réponses.

L'ordinateur Betaal (en tant qu'« esprit » dans la machine) peut rassembler des (copies des) paquets prévus pour une destination quelconque et peut également injecter des paquets avec n'importe quelle étiquette souhaitée.

Ainsi, Abdul doit signer (numériquement) chaque paquet envoyé et le chiffrer, pour que seul Chin puisse le lire. Si Abdul se contentait de signer les paquets, alors Betaal pourrait (encore) les réunir. Puisqu'il faut beaucoup de paquets pour constituer une conversation, Betaal pourrait réexpédier les paquets plus tard dans un ordre plus profitable — menaçant ainsi Chin. Si Abdul chiffrait seulement les paquets, alors Betaal pourrait injecter ses propres paquets chiffrés en jargon (données illisibles/indéchiffrables) et perturber la conversation entre Abdul et Chin.

Permettez-moi de reformuler ceci en vocabulaire technique. « Dans un réseau à base de paquets, secret et authenticité vont de pair. »

3. Un shell sécurisé

Quand Tatu Ylonen a écrit à l'origine ssh, ce dernier a été considéré comme un substitut de telnet et de rsh, qui sont des programmes/protocoles pour se connecter à distance (pour un accès distant à un shell). Cependant, comme ssh est un protocole réseau, il peut être utilisé pour créer des conversations sécurisées entre ordinateurs.

Chaque serveur ssh possède une clé privée — habituellement située dans /etc/ssh/ssh_host_rsa_key. Souvent, il y a une seconde clé privée dans /etc/ssh/ssh_host_dsa_key. Le travail de l'administrateur réseau est de rassembler les clés publiques associées à chacune de ces clés privées (au même endroit, avec une extension .pub) et de les distribuer à tous les ordinateurs du réseau.

La manière la plus simple de le faire est d'aller sur chaque ordinateur et de copier ces fichiers dans une clé USB (Universal Serial Bus, bus série universel) :


cp /etc/ssh/ssh_host_rsa_key.pub /media/usb/<adresse_ip>.rsa.pub
cp /etc/ssh/ssh_host_dsa_key.pub /media/usb/<adresse_ip>.dsa.pub

L'administrateur crée alors un fichier known_hosts :


for type in rsa dsa 
   do
       for i in /media/usb/*.$type.pub
       do
         addr=$(basename $i .$type.pub)
         (echo -n "$addr "; cut -f1-2 -d' '< $i)>> known_hosts
       done
   done

Ce fichier known_hosts est ensuite copié dans /etc/ssh/ssh_known_hosts sur chaque ordinateur. Pour conclure, on définit les paramètres de configuration :



echo "StrictHostKeyChecking yes" >> /etc/ssh/ssh_config


sur chaque ordinateur. (Les utilisateurs de chaque ordinateur peuvent également avoir à modifier le fichier de configuration $HOME/.ssh/config s'il existe.)

Après cette procédure (certes) interminable (mais non difficile), Abdul et Chin possèdent chacun les clés publiques de l'autre. Ainsi, Abdul peut chiffrer des paquets que seul Chin peut lire, et Chin peut vérifier les signatures générées par Abdul. (Le véritable protocole ssh est plus complexe et ne nous concerne pas ici.)

Ainsi, à présent, sur Abdul, on peut exécuter ssh Chin et être certain que c'est Chin qui répond. Chin demandera toujours le mot de passe à moins que tous les serveurs exécutent HostBasedAuthentication dans /etc/ssh/sshd_config. Cette procédure pourrait être risquée pour Chin, à moins que l'utilisateur root sur Abdul soit considéré comme équivalent à l'utilisateur root sur Chin.

Qu'en est-il des types d'échanges de données autres (que ssh) ? Heureusement, on a pensé à ce problème également. Si à présent Abdul veut ouvrir le port TCP (Transmission Control Protocol, protocole de contrôle de transmissions) (admettons) 80 sur Chin, alors Abdul exécute :


ssh -q -f -N -L 8080:localhost:80 Chin

Maintenant, ouvrir http://localhost:8080 depuis Abdul donne accès au serveur web de Chin.

Comment sécuriser tous les échanges de données ? Ce point a été pris en compte également. En fait, ssh fournit au moins deux méthodes :

  1. Les applications capables d'employer le protocole SOCKS (comme Mozilla et Thunderbird) peuvent utiliser un tunnel créé par cette commande :

    
    ssh -q -f -N -D 1080 Chin
    
    

    Il y a également des bibliothèques de wrappers comme tsocks qui peuvent « enseigner » à n'importe quelle application TCP comment utiliser SOCKS.

  2. On peut également créer un tunnel TCP entre les hôtes :

    
    ssh -q -f -N -w 0:any Chin
    
    

    Grâce à des réglages réseau supplémentaires à chaque extrémité, ce tunnel peut être employé pour toutes les applications TCP, mais non par les applications utilisant UDP au lieu de TCP pour leur transport.

En dépit de ces efforts, SSH n'est pas toujours adéquat pour le problème que nous nous proposons de résoudre, pour les raisons suivantes :

  1. Le mécanisme de distribution des clés est complexe.

  2. Ce n'est pas une bonne idée de percer un tunnel TCP over TCP comme décrit dans un article de Olaf Titz.

  3. Nous devons installer des tunnels entre chaque paire d'hôtes dans le réseau ; et ceci est fastidieux.

4. OpenVPN

On peut considérer qu'OpenVPN est semblable à SSH avec une solution pour les trois problèmes notés ci-dessus.

Une machine est configurée en tant que serveur openvpn et toutes les autres —en tant que clients. Le serveur attend passivement que le client prenne l'initiative d'une connexion. Dès lors que la connexion est établie, les rôles des deux ordinateurs dans la conversation sont complètement symétriques.

Le serveur (respectivement, le client) peut être configuré à l'aide du modèle de fichier server.conf (client.conf pour le client), qui fait partie du paquetage openvpn (les modèles de fichiers de configuration devraient se trouver dans /usr/share/doc/openvpn-<version>/sample-config-files, si vous employez une version auto-installable. Autrement, ils se trouvent dans le répertoire sample-config-files dans l'archive (tarball) du source. Dans le fichier de configuration du client, on ne doit modifier qu'une ligne commençant par remote et y insérer le serveur approprié pour se connecter. Dans le fichier de configuration du serveur, on peut modifier la ligne commençant par server pour y insérer un réseau aléatoire de la forme 10.a.b.0 (vous pourriez également utiliser 172.16-32.a.0 ou 192.168.a.0) au lieu du réseau par défaut. Comme nous voulons que les clients dialoguent entre eux, nous cocherons également l'option client-to-client dans le fichier de configuration du serveur. En outre, nous modifierons ces fichiers pour y insérer des noms appropriés, comme host.key et host.crt pour les fichiers certificat et de clé (voir ci-dessous).

Une fonctionnalité intéressante d'openvpn est qu'il peut utiliser des certificats. Cela simplifie considérablement la distribution des clés — il n'est plus nécessaire de distribuer la(clés) publique(s) d'un nouvel hôte à tous les autres hôtes. Cet avantage comporte l'« inconvénient » d'installer une Autorité de Certification.

5. Le cachet de l'Autorité

Tout d'abord, nous devons installer une Autorité de Certification (AC — en anglais, CA, Certificate Authority) sur chaque ordinateur (la machine personnelle de l'administrateur réseau, par exemple). Il y a plusieurs manières de procéder.

Une méthode simple pour installer une AC est fournie avec Openvpn. Commençons par copier le répertoire Easy RSA 2.0 dans un endroit approprié.


mkdir /root/openvpn_CA
cd /root/openvpn_CA
cp -a /usr/share/doc/openvpn/examples/easy-rsa/2.0 .

Ensuite, nous devons modifier les dernières lignes du fichier vars dans ce répertoire pour refléter notre organisation. Voici les lignes pertinentes :

export KEY_SIZE=2048
export KEY_COUNTRY=
export KEY_PROVINCE=
export KEY_CITY=
export KEY_ORG=
export KEY_OU=
export KEY_EMAIL=

Puis nous générons la clé de l'Autorité de Certification :


. ./vars
./clean-all
./pkitool --initca

Une fois que toutes les requêtes relatives à la dernière commande ont été correctement renseignées, on a un groupe de fichiers dans le sous-répertoire keys.

6. Donnez-nous un signe

Après avoir installé l'Autorité de Certification, il faut signer les clés de chaque hôte. D'abord, chaque hôte génère une demande de signature :


ln -s /etc/ssh/ssh_host_rsa_key.pub /etc/openvpn/host.key
cd /etc/openvpn
openssl req -new -extensions v3_req \
      -key host.key -out host.csr

Toutes les requêtes devront être renseignées avec soin. En particulier, il est judicieux d'employer le nom de domaine entièrement qualifié pour la ligne correspondant au nom commun (NC — en anglais, CN, Common Name). Ensuite, host.csr est copié dans le répertoire keys, où l'Autorité de Certification a été installée sous un nom comme <nom_hote>.csr. Puis l'AC vérifie et signe la clé avec les commandes suivantes :


. ./vars
./pkitool --interact --sign <nom_hote>

Ensuite, les fichiers ca.crt et <nom_hote>.crt appartenant au répertoire keys de l'AC sont copiés à nouveau dans le répertoire /etc/openvpn de l'hôte d'origine ; on renomme également (ou on crée un lien symbolique) <nom_hote>.crt en host.crt.

6.1. Organiser tout cela ensemble

À présent, pour démarrer le tunnel, on exécute :



/etc/init.d/openvpn start <config>


<config> est le serveur ou le client selon le cas. On peut démarrer plusieurs versions de client qui sont dirigées vers le même serveur. Puisqu'on veut que les clients dialoguent entre eux, on choisit l'option client-to-client dans la configuration du serveur.

Ainsi, supposons qu'Octavio est le serveur, et qu'Abdul et Chin sont deux clients. Quand Abdul et Chin dialoguent sur openvpn (ce dont s'assure Abdul en ouvrant une connexion à l'adresse 10.a.b.x affectée à Chin), ils peuvent être raisonnablement sûrs que nul — pas même Octavio — ne peut intercepter cette conversation. Puisque openvpn demande le certificat au début de la conversation, Abdul est également sûr que c'est bien Chin à l'autre extrémité de la communication. Au minimum, Abdul est certain que celui-ci a été certifié par l'Autorité de Certification.

6.2. Problèmes

Abdul et Chin ont-ils résolu leur problème ? Peuvent-ils communiquer sans se soucier de Betaal ?

Quelques problèmes demeurent :

  1. Toutes les machines dépendent d'Octavio, qui est au centre du réseau (virtuel). Ceci peut être approprié pour certaines situations, comme un réseau sans fil, où la forme naturelle (topologie) du réseau est en étoile, mais ne convient pas pour un réseau à l'échelle d'une université.

  2. Bien que le routage soit automatisé, il est encore complexe. Chaque paire de machines est connectée par le réseau local sous-jacent aussi bien que le réseau virtuel. Pour rendre les conversations sûres, veillez à ce que toutes les données soient échangées au travers du réseau virtuel.

7. Rappel

La solution à ces deux problèmes a été pour l'essentiel décrite par René Pfeiffer dans son premier article et son second article sur IPsec. Nous nous écarterons de ces prescriptions à deux égards :

  1. Employez le mode « transport » d'IPsec plutôt que le mode « tunnel ».

  2. Employez la politique « use » d'IPsec plutôt que la politique « require ».

La première garantit que le routage est « automatique ». La seconde nous permet de migrer vers un réseau IPsec sans interrompre les connexions existantes. Une fois que toutes les machines qui doivent dialoguer entre elles en sûreté sont configurées, on peut passer au mode « require » pour s'assurer que toutes les conversations sont chiffrées.

Une différence entre IPsec et openvpn est que, dans IPsec, un démon séparé gère l'échange et l'authentification des clés. Sous GNU/Linux, il s'agit de racoon. On configure le fichier /etc/racoon/racoon.conf comme suit. Tout d'abord, on insère le chemin vers les certificats. Celui-ci peut être le même que les certificats générés pour OpenVPN. Ensuite, on configure l'authentification :

        
remote anonymous {
   exchange_mode main;
   certificate_type x509 "$HOST_CERT" "$HOST_KEY";
   verify_cert on;
   my_identifier asn1dn;
   proposal {
         encryption_algorithm aes;
         hash_algorithm sha1;
         authentication_method rsasig;
         dh_group modp1024;
   }
}

Ici, il faut remplacer $HOST_CERT et $HOST_KEY par les emplacements du certificat et de la clé, respectivement. La section suivante du fichier de configuration décrit le chiffrement employé après une authentification réussie.

sainfo anonymous {
        pfs_group modp768;
        encryption_algorithm 3des;
        authentication_algorithm hmac_md5;
        compression_algorithm deflate;
}

On ordonne ensuite au noyau d'utiliser IPsec autant que possible. Pour ce faire, on veille à ce que les directives suivantes soient chargées par la commande setkey. Effacez les associations de sécurité et les politiques de sécurité.

       
flush;
spdflush;

La politique consiste à utiliser le protocole ESP (Encapsulating Security Payload, charge d'encapsulation de sécurité) et le protocole AH (Authentication Header, en-tête d'authentification) pour tous les paquets entre cet hôte et n'importe quel autre hôte du réseau, si possible. Dans les commandes ci-dessous, il faut insérer les valeurs $IP_ADDR et $NETMASK correctes :

spdadd $IP_ADDR $NETMASK any -P out ipsec
   esp/transport//use
   ah/transport//use;

spdadd $NETMASK $IP_ADDR any -P in ipsec
   esp/transport//use
   ah/transport//use;

Cela signifie que tous les hôtes utiliseront un trafic chiffré et authentifié pour chaque hôte du réseau local qui prend en charge le trafic chiffré. Ceci nous permet d'activer cette configuration sur tous les hôtes du réseau local, un hôte à la fois, sans perturber le réseau existant pendant le processus. Une fois que tous les hôtes sont configurés pour IPsec, on peut remplacer les commandes précédentes par :

spdadd $IP_ADDR $NETMASK any -P out ipsec
   esp/transport//require
   ah/transport//require;

spdadd $NETMASK $IP_ADDR any -P in ipsec
   esp/transport//require
   ah/transport//require;

8. Conclusion et remerciements

Maintenant, il est relativement facile de configurer des machines pour employer le chiffrement et l'authentification dans un réseau local. De nos jours, les ordinateurs et les réseaux étant assez rapides, les calculs et les paquets réseau supplémentaires qui sont exigés ne causent pas de retard notable. En outre, il est tout a fait simple de mettre en œuvre une telle solution sans arrêter l'ensemble du réseau jusqu'à ce que toutes les machines soient reconfigurées.

Il ne vous reste plus qu'à choisir une solution appropriée pour vos besoins et à la mettre en application !

Dans le réseau de l'IMSc (Institute of Mathematical Sciences), nous avons testé et mis en œuvre la solution openvpn. Un certain nombre de mes collègues m'y ont aidé à corriger divers aspects de cette application. Je les remercie tous pour leur aide. La documentation de ssh et d'openvpn est également de très bonne qualité. Il existe nombre de bons articles sur IPsec, dont ceux de la LG cités plus haut. Je remercie les auteurs de ces documents pour leur aide.

Kapil Hari Paranjape a l'âme d'un « hacker » depuis l'époque des cartes perforées. Plus précisément, cela veut dire qu'il n'a jamais écrit de « véritable » programme. Il s'est contenté d'expérimenter des programmes écrits par d'autres. Après avoir joué avec Minix en 1990-91, il a pensé écrire son premier logiciel — un « authentique » noyau *nix pour la classe d'ordinateurs x86. Heureusement pour lui, un certain Linus Torvalds l'a devancé — lui évitant ainsi la peine (une fois de plus) d'écrire effectivement du code. En signe de gratitude éternelle, il a passé beaucoup de temps à expérimenter et promouvoir le système Linux et le projet GNU depuis lors, au grand dam de la plupart de son entourage, qui pense qu'il devrait se concentrer sur la recherche en mathématiques — qui est son gagne-pain. L'interaction entre les programmes s'exécutant réellement, ce qui peut être calculé en théorie et ce dont on peut prouver l'existence, continuent de le fasciner.

Adaptation française de la Gazette Linux

L'adaptation française de ce document a été réalisée dans le cadre du Projet de traduction de la Gazette Linux.

Vous pourrez lire d'autres articles traduits et en apprendre plus sur ce projet en visitant notre site : http://wiki.traduc.org/Gazette_Linux.

Si vous souhaitez apporter votre contribution, n'hésitez pas à nous rejoindre, nous serons heureux de vous accueillir.